Бэкапы по правилу 3-2-1 на restic

Обещал в прошлый раз — рассказываю, как я бэкаплю домашний сервер. Тема нудная ровно до того момента, как у тебя умирает диск с фотками за десять лет. После этого она становится самой интересной темой в твоей жизни, но уже поздно. Так что давайте до.

Правило 3-2-1

Если коротко, это здравый смысл, оформленный в цифры:

У меня это раскладывается так. Оригинал живёт на сервере (раз). Бэкап едет на внешний HDD, который воткнут в сервер по USB (два, другой носитель). И копия этого репозитория уезжает offsite — на удалённое хранилище через тот же restic (три, вне дома). Если дома случится потоп, пожар или просто кто-то унесёт коробку — данные переживут.

Почему restic

Перепробовал я разное, остановился на restic. Один бинарь, дедупликация (одинаковые куски хранятся один раз — экономит прилично), всё шифруется на клиенте перед записью. Последнее особенно важно для offsite-копии: на удалённом хранилище лежит зашифрованный мусор, и мне всё равно, кто его теоретически увидит.

Инициализируем репозиторий на внешнем диске один раз:

export RESTIC_REPOSITORY=/mnt/backup-hdd/restic
export RESTIC_PASSWORD_FILE=/root/.restic-pass
restic init

Пароль я держу в файле и отдельно записал его в надёжное место. Потеряешь пароль — потеряешь весь репозиторий, restic в этом смысле безжалостен.

Сам бэкап

Бэкаплю каталог /app целиком — там и compose-рецепты, и данные сервисов, и тот самый дамп БД Nextcloud, который я делаю перед этим.

restic backup /app \
  --exclude-caches \
  --tag daily

Чтобы репозиторий не пух до бесконечности, навожу порядок политикой хранения — оставляю разумную глубину истории и удаляю старьё:

restic forget \
  --keep-daily 7 \
  --keep-weekly 4 \
  --keep-monthly 6 \
  --prune

То есть последние 7 дней, 4 недели и 6 месяцев. Этого с головой, а --prune физически освобождает место от выкинутых снапшотов.

По расписанию

Руками такое делать нельзя — забудешь на второй неделе. У меня это systemd timer (cron тоже годится, дело вкуса), который раз в сутки ночью дёргает скрипт: сначала дамп БД, потом restic backup, потом forget --prune, а в конце пушит копию в offsite-репозиторий командой restic copy.

Грубый набросок строки в cron, если без systemd:

30 3 * * *  /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1

Лог обязательно, потому что молчаливый бэкап — это бэкап, про который ты не знаешь, что он сломался месяц назад.

Самое главное: тест восстановления

А вот теперь то, ради чего весь пост. Бэкап, который ты ни разу не восстанавливал, — это не бэкап, а гипотеза. Я регулярно (раз в пару месяцев) проверяю, что из репозитория реально достаётся файл.

Смотрим, какие снапшоты есть:

restic snapshots

И разворачиваем последний во временную папку:

restic restore latest --target /tmp/restore-test

Дальше глазами проверяю, что внутри лежит то, что должно, и файлы не битые. Один раз так выяснил, что забыл в бэкап положить .env-файлы (исключил лишним паттерном) — и спокойно поправил это в мирное время, а не в три часа ночи под крик «всё пропало».

Вот, собственно, и всё. Скучно, надёжно, проверяемо. Спите спокойно.