Restic: настройка бэкапа в S3 за 15 минут
Москва, Щёлковское шоссе, д. 92, корп. 7 · Пн–Пт 9:00–19:00 · +7 903 729-62-41

Restic + S3: автоматический бэкап с дедупликацией

Restic + S3: автоматический бэкап с дедупликацией

Почему Restic для корпоративных бэкапов

Restic — инструмент резервного копирования на Go. Три вещи выделяют его среди конкурентов: дедупликация на уровне блоков (одинаковые данные физически хранятся один раз), шифрование по умолчанию — никаких отдельных плагинов, всё включено (AES-256-CTR + Poly1305-AES) — и поддержка множества бэкендов: локальные диски, S3, SFTP, Azure Blob, Google Cloud Storage. Поставил и работаешь.

Именно для ИТ-отделов небольших компаний это сочетание оказывается очень удачным. Инкрементальные бэкапы почти не занимают места — за счёт content-defined chunking (CDC) дублирующиеся блоки не пишутся повторно. При этом каждый снапшот — полноценная точка восстановления, не нужно прогонять всю цепочку инкрементов как в старых решениях. Ну и выбор по хранилищам широкий: поднять собственный MinIO или подключить Yandex Object Storage — дело получаса.

В этой статье разберём, как настроить автоматическое резервное копирование серверов в S3 — с ротацией снапшотов, мониторингом и оповещениями, когда что-то пошло не так.

Установка Restic и инициализация репозитория

Ставим Restic из официального репозитория:

# Ubuntu/Debian
sudo apt install -y restic

# Или скачиваем последнюю версию
wget https://github.com/restic/restic/releases/download/v0.16.4/restic_0.16.4_linux_amd64.bz2
bunzip2 restic_0.16.4_linux_amd64.bz2
sudo mv restic_0.16.4_linux_amd64 /usr/local/bin/restic
sudo chmod +x /usr/local/bin/restic

# Проверяем
restic version

Прописываем переменные окружения для доступа к S3:

# /etc/restic/env.sh
export RESTIC_REPOSITORY="s3:https://storage.yandexcloud.net/company-backups"
export RESTIC_PASSWORD="SuperSecretEncryptionKey2024"
export AWS_ACCESS_KEY_ID="YCAJExxxxxxxxxxxxxxxxx"
export AWS_SECRET_ACCESS_KEY="YCPxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Инициализируем репозиторий:

source /etc/restic/env.sh
restic init

Если используете MinIO — endpoint задаётся в формате s3:http://minio.company.ru:9000/backups.

Безопасное хранение credentials

Файл с переменными должен читать только root — никаких исключений:

sudo mkdir -p /etc/restic
sudo chmod 700 /etc/restic
sudo chmod 600 /etc/restic/env.sh

Пароль репозитория можно вынести в отдельный файл: RESTIC_PASSWORD_FILE=/etc/restic/password. Но вот что действительно важно помнить: сменить пароль шифрования без пересоздания репозитория невозможно. Мы сталкивались с ситуациями, когда люди хотели это сделать задним числом — не вышло. Выбирайте нормальный пароль сразу.

Создание бэкапов: файлы, базы данных, конфигурации

Базовая команда для запуска бэкапа:

# Бэкап директорий
restic backup /etc /home /var/www /opt/apps \
    --exclude="*.tmp" \
    --exclude="*.log" \
    --exclude=".cache" \
    --tag server=web-01 \
    --tag type=files

Для бэкапа баз данных сначала снимаем дамп, потом уже кладём его в restic:

# PostgreSQL
pg_dumpall -U postgres | restic backup --stdin --stdin-filename pg_dumpall.sql --tag type=database

# MySQL/MariaDB
mysqldump --all-databases --single-transaction | restic backup --stdin --stdin-filename mysql_all.sql --tag type=database

# Можно комбинировать в одном снапшоте
mkdir -p /tmp/db-dumps
pg_dumpall -U postgres > /tmp/db-dumps/postgres.sql
mongodump --out /tmp/db-dumps/mongo/
restic backup /tmp/db-dumps --tag type=database --tag server=db-01
rm -rf /tmp/db-dumps

Restic сам разбирается, что изменилось с прошлого раза. Первый бэкап — полный, всё копируется. Дальше — только дельта. При этом каждый снапшот остаётся самодостаточной точкой восстановления: не нужно ничего «склеивать».

Автоматизация через systemd-таймеры
systemd-сервис для бэкапов Restic

Автоматизация через systemd-таймеры

Создаём systemd-сервис /etc/systemd/system/restic-backup.service:

[Unit]
Description=Restic Backup
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
EnvironmentFile=/etc/restic/env.sh
ExecStartPre=/usr/local/bin/restic-pre-backup.sh
ExecStart=/usr/local/bin/restic backup /etc /home /var/www /opt --exclude-file=/etc/restic/excludes.txt --tag server=%H --tag type=files
ExecStartPost=/usr/local/bin/restic-post-backup.sh
Nice=19
IOSchedulingClass=idle

Таймер /etc/systemd/system/restic-backup.timer:

[Unit]
Description=Run Restic Backup daily

[Timer]
OnCalendar=*-*-* 02:00:00
RandomizedDelaySec=1800
Persistent=true

[Install]
WantedBy=timers.target

Активируем и запускаем:

sudo systemctl daemon-reload
sudo systemctl enable --now restic-backup.timer
sudo systemctl list-timers | grep restic

Скрипт pre/post-backup

Скрипт /usr/local/bin/restic-pre-backup.sh отрабатывает перед бэкапом — здесь удобно снимать дампы БД:

#!/bin/bash
set -euo pipefail
mkdir -p /var/backups/db
pg_dumpall -U postgres > /var/backups/db/postgres.sql 2>/var/log/restic-pre.log
echo "Pre-backup completed at $(date)" >> /var/log/restic-pre.log

Скрипт /usr/local/bin/restic-post-backup.sh запускается после — чистим временные файлы и отправляем уведомление:

#!/bin/bash
set -euo pipefail
source /etc/restic/env.sh

# Очистка дампов
rm -rf /var/backups/db

# Проверка целостности (раз в неделю)
if [ "$(date +%u)" -eq 7 ]; then
    restic check --read-data-subset=5% 2>&1 | logger -t restic-check
fi

# Уведомление об успехе
curl -s -X POST "https://api.telegram.org/bot${TG_TOKEN}/sendMessage" \
    -d chat_id="${TG_CHAT}" \
    -d text="Backup OK: $(hostname) at $(date '+%Y-%m-%d %H:%M')"

Политика ротации снапшотов

Ротация в Restic гибкая. Управляется через команду forget с набором флагов политики хранения:

# Оставляем: 7 ежедневных, 4 еженедельных, 12 ежемесячных, 2 годовых
restic forget \
    --keep-daily 7 \
    --keep-weekly 4 \
    --keep-monthly 12 \
    --keep-yearly 2 \
    --prune \
    --tag server=web-01

Флаг --prune удаляет данные сразу — те блоки, на которые больше не ссылается ни один снапшот. Без него forget только помечает снапшоты, но место на диске не освобождается. Путаница с этим моментом встречается часто — имейте в виду.

Для автоматической ротации добавьте в systemd-сервис:

ExecStartPost=/usr/local/bin/restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 12 --keep-yearly 2 --prune

Команда prune — не лёгкая операция. Она перепаковывает pack-файлы, и на больших репозиториях (от нескольких десятков ТБ) это серьёзная нагрузка на сеть и CPU. Спасает флаг --max-repack-size 5G: он ограничивает объём перепаковки за один запуск, и процесс не превращается в многочасовую пытку для инфраструктуры.

Восстановление данных из бэкапа

Смотрим список доступных снапшотов:

# Все снапшоты
restic snapshots

# Фильтр по тегу
restic snapshots --tag server=web-01

# Фильтр по дате
restic snapshots --tag type=files | head -20

Восстанавливаем данные:

# Полное восстановление в указанную директорию
restic restore latest --target /tmp/restore

# Восстановление конкретного снапшота
restic restore abc12345 --target /tmp/restore

# Восстановление отдельных файлов
restic restore latest --target /tmp/restore --include "/etc/nginx"

# Монтирование как FUSE-файловой системы
mkdir -p /mnt/restic
restic mount /mnt/restic &
# Снапшоты доступны как директории
ls /mnt/restic/snapshots/

FUSE-монтирование — штука реально удобная. Все снапшоты видны как обычные директории, нужный файл вытаскиваешь стандартным cp, не разворачивая весь бэкап. Сэкономили так не один час на точечном восстановлении у клиентов.

Мониторинг и проверка целостности
Проверка целостности бэкапов Restic

Мониторинг и проверка целостности

В Restic есть встроенная проверка целостности репозитория — пользуйтесь:

# Быстрая проверка метаданных
restic check

# Полная проверка с чтением данных
restic check --read-data

# Проверка части данных (для больших репозиториев)
restic check --read-data-subset=10%

Чтобы отслеживать размер репозитория и факт успешного прохождения бэкапов, напишем скрипт для Zabbix/Prometheus:

#!/bin/bash
# /usr/local/bin/restic-metrics.sh
source /etc/restic/env.sh

# Время последнего снапшота (Unix timestamp)
LAST_SNAP=$(restic snapshots --json --latest 1 | jq '.[0].time' -r)
LAST_TS=$(date -d "$LAST_SNAP" +%s)
NOW=$(date +%s)
AGE_HOURS=$(( (NOW - LAST_TS) / 3600 ))

# Статистика репозитория
STATS=$(restic stats --json)
TOTAL_SIZE=$(echo $STATS | jq '.total_size')
SNAP_COUNT=$(restic snapshots --json | jq 'length')

echo "restic_last_backup_age_hours $AGE_HOURS"
echo "restic_total_size_bytes $TOTAL_SIZE"
echo "restic_snapshot_count $SNAP_COUNT"

Настройте алерт по простому условию: если restic_last_backup_age_hours > 26 — ночной бэкап не прошёл. 26 часов с запасом перекрывают возможные задержки, но при этом не позволяют пропустить реальный сбой.

Коды возврата и типовые ошибки Restic

Скрипт бэкапа, который проверяет только «ноль или не ноль», пропускает важные случаи. С версии 0.17 restic возвращает разные коды выхода для разных сбоев, и я разбираю их явно:

  • 0 — команда выполнена успешно;
  • 1 — общая ошибка, подробности в выводе команды;
  • 3 — backup не смог прочитать часть исходных данных (снапшот создан, но неполный) или forget не удалил часть снапшотов;
  • 10 — репозиторий не существует (с 0.17.0);
  • 11 — не удалось заблокировать репозиторий (с 0.17.0);
  • 12 — неверный пароль (с 0.17.1);
  • 130 — команда прервана сигналом SIGINT или SIGTERM.

Код 3 особенно коварен: снапшот есть, в списке он выглядит нормально, но в нём не хватает файлов, которые были заняты или недоступны по правам. В скрипте я считаю его предупреждением и отправляю алерт с текстом ошибки, а не молча радуюсь созданному снапшоту. Документация отдельно оговаривает: новые коды будут добавляться, и любой неизвестный код нужно считать провалом.

restic backup /srv/data --tag daily
rc=$?
case $rc in
  0) echo "OK" ;;
  3) echo "WARN: часть файлов не прочитана" ;;
  11) echo "FAIL: репозиторий заблокирован" ;;
  *) echo "FAIL: код $rc" ;;
esac

Код 11 обычно означает «висящую» блокировку от прерванного процесса. Restic сам считает блокировку устаревшей, если её отметке времени больше 30 минут или если процесс, создавший её на этой же машине, уже завершён. Такие блокировки снимает restic unlock. Ключ --remove-all удаляет вообще все блокировки, включая действующие, — его я применяю, только убедившись, что с репозиторием сейчас никто не работает.

Ещё один параметр, влияющий на счёт за S3, — --max-unused у prune. По умолчанию restic допускает до 5% неиспользуемых данных в репозитории, чтобы не перепаковывать частично занятые файлы. Значение 0 минимизирует объём, но увеличивает трафик и время prune; unlimited экономит трафик ценой места. Для S3 с платой за исходящий трафик я оставляю значение по умолчанию.

Часто задаваемые вопросы

Да, безопасно. Restic шифрует и данные, и метаданные ещё до отправки в хранилище (AES-256). Провайдер на своей стороне видит только зашифрованные blob-файлы — без пароля репозитория это просто набор байт. Дополнительно стоит закрыть бакет политикой IAM, чтобы ограничить доступ на уровне облака.

Несколько параметров, которые реально помогают. Параметр --read-concurrency включает параллельное чтение, -o s3.connections=20 поднимает число одновременных соединений с S3. Отдельно — кеш: --cache-dir /var/cache/restic хранит метаданные локально и заметно ускоряет повторные бэкапы. На крупных репозиториях разница ощутимая.

Да, нативная сборка под Windows есть. Поддерживается VSS (Volume Shadow Copy) — это значит, можно бэкапить открытые файлы без остановки приложений. Запускать удобно через Task Scheduler или завернуть логику в PowerShell-скрипт.

Restic атомарен. Если бэкап прервался посередине — незавершённый снапшот просто не появится в списке. При следующем запуске процесс стартует заново, но уже загруженные блоки повторно не передаются — дедупликация делает своё дело.

#restic backup#резервное копирование s3#restic настройка#дедупликация бэкапов#автоматический бэкап linux#restic minio#бэкап сервера#restic ротация

Источники

Столкнулись с похожей задачей? Обращайтесь — решим

Если у вас происходит что-то из описанного в этой статье — или любая другая проблема с ИТ-инфраструктурой, — обращайтесь в любое время. Мои специалисты и я лично разберём ситуацию, найдём настоящую причину и доведём до решения.

Возьмёмся и за разовую задачу, и за постоянное обслуживание. Первичная консультация — бесплатно и без обязательств.

📞 +7 903 729-62-41 ✈ Telegram @ITfresh_Boss

С уважением, Семёнов Евгений Сергеевич, директор «АйТи Фреш» — IT-аутсорсинг для компаний до 50 рабочих мест, 15+ лет практики

Комментарии 0

Оставить комментарий

загрузка...

Подпишитесь на рассылку ITfresh

Каждую неделю мы выпускаем практические гайды для руководителей IT и системных администраторов. Это не просто теория! Здесь вы найдёте всё: безопасность, 1С, миграции, резервные копии и проверенные лайфхаки из наших реальных проектов.

Письмо придёт в течение минутыНе нашли его во «Входящих» — загляните в папку «Спам» или «Промоакции» и нажмите «Не спам». Так все следующие выпуски будут приходить прямо в основную почту.
Реквизиты оператора персональных данных

ООО «АЙТИ-ФРЕШ», ИНН 7719418495, КПП 771901001. Юридический адрес: 105523, г. Москва, Щёлковское шоссе, д. 92, корп. 7. Контакт: info@itfresh.ru, +7 903 729-62-41. Оператор обрабатывает e-mail подписчика в целях рассылки информационных и рекламных материалов до момента отзыва согласия.