restic на практике: репозиторий, снимки, восстановление
Файловый бэкап с дедупликацией и шифрованием: init, backup, snapshots, restore, forget с prune и check. Все выводы сняты с живого прогона.
Почему restic
Файлы сервера (загрузки пользователей, конфиги, дампы базы) нужно куда-то
класть, и голый rsync тут проигрывает: он не хранит историю версий, не
дедуплицирует и ничего не шифрует.
restic делает три вещи из коробки: режет данные на блоки и хранит каждый уникальный один раз, шифрует всё на стороне клиента, умеет писать в локальную папку, по SFTP, в S3 и совместимые хранилища. Альтернатива с тем же набором свойств — borg; выбор между ними дело вкуса.
Все выводы ниже сняты с настоящего прогона, ничего не придумано.
Репозиторий
Репозиторий это папка (или бакет), где лежат зашифрованные блоки и метаданные. Создаётся один раз:
export RESTIC_PASSWORD='длинный-пароль'
restic -r /backup/repo init
created restic repository 1b8914b832 at /backup/repo
Please note that knowledge of your password is required to access
the repository. Losing your password means that your data is
irrecoverably lost.
Предупреждение буквальное. Пароль это ключ шифрования, восстановления
через поддержку не существует. Пароль хранят в менеджере секретов, а в
скриптах передают через RESTIC_PASSWORD_FILE, чтобы он не светился в
списке процессов.
Первый бэкап
restic -r /backup/repo backup /var/lib/app
no parent snapshot found, will read all files
Files: 3 new, 0 changed, 0 unmodified
Added to the repository: 197.454 KiB (196.935 KiB stored)
processed 3 files, 195.390 KiB in 0:00
snapshot 6558ab20 saved
Прочитано 195 KiB, столько же и записано: репозиторий пустой, экономить не на чем.
Второй бэкап: видно дедупликацию
Дописываем одну строку в один файл и повторяем команду:
Files: 3 new, 0 changed, 0 unmodified
Added to the repository: 1.760 KiB (1.122 KiB stored)
processed 3 files, 195.402 KiB in 0:00
snapshot 66c25f06 saved
Обработано снова 195 KiB, а добавлено в репозиторий 1.76 KiB. Одинаковые блоки уже лежат на месте, второй раз их никто не пишет. Именно поэтому тридцать ежедневных снимков занимают немногим больше одного.
При этом снимок остаётся самодостаточным: восстановить можно любой, цепочку собирать не нужно.
Грабля с parent snapshot
Обратите внимание на две строчки выше: no parent snapshot found и
3 new вместо 1 changed. Файлы не изменились, а restic перечитал их
целиком.
Причина в том, что restic ищет предыдущий снимок по хосту и путям, а прогон шёл в контейнере, где имя хоста каждый раз новое:
ID Time Host Paths
6558ab20 2026-08-23 10:55:17 76190abc0d5c /w/data
66c25f06 2026-08-23 10:55:18 ededf2d22b3c /w/data
Лечится флагом --host с постоянным именем:
restic -r /backup/repo backup --host web-01 /var/lib/app
Files: 0 new, 1 changed, 2 unmodified
Added to the repository: 1.772 KiB (1.127 KiB stored)
snapshot 1d62a0f3 saved
Теперь видно нормальную картину: один файл изменился, два не тронуты. Дедупликация работала и без этого, но лишнее чтение диска на больших объёмах обходится дорого.
Список снимков и восстановление
restic -r /backup/repo snapshots
restic -r /backup/repo restore 801e51dc --target /restore
restoring snapshot 801e51dc of [/w/data] at 2026-08-23 10:55:31 by root@web-01 to /restore
Summary: Restored 6 files/dirs (195.402 KiB) in 0:00
Вместо идентификатора можно писать latest. Восстановление кладёт данные
в указанный --target, поверх оригинала ничего не пишется, и это правильно:
разбираться удобнее на копии.
Достать один файл, не разворачивая всё:
restic -r /backup/repo restore latest --target /restore --include /var/lib/app/app.conf
Summary: Restored 3 / 1 files/dirs (40 B / 40 B) in 0:00
Такой выборочный restore закрывает самый частый запрос в жизни: «верни один конфиг, который я вчера испортил».
Ретенция: forget и prune
forget удаляет записи о снимках по правилам, prune вычищает блоки,
на которые больше никто не ссылается. Обычно их запускают вместе:
restic -r /backup/repo forget --keep-daily 7 --keep-weekly 4 --keep-monthly 12 --prune
Вот тут ждёт неочевидное поведение. Простая команда
restic -r /backup/repo forget --keep-last 2 --prune
на репозитории из четырёх снимков оставила четыре, а не два. Потому что
restic группирует снимки по хосту и путям (--group-by host,paths по
умолчанию) и применяет правило внутри каждой группы. Снимки с двух разных
хостов это две группы, в каждой сохранилось по своему набору.
На практике это как раз удобно: политика «7 дней» действует отдельно для
каждого сервера. Но если вы ждали ровно два снимка на весь репозиторий,
результат удивит. Сменить поведение можно флагом --group-by ''.
Перед первым запуском в бою полезен --dry-run: покажет, что будет
удалено, ничего не трогая.
Проверка
Копия считается копией после проверки, и у restic для этого есть команда:
restic -r /backup/repo check --read-data
check all packs
check snapshots, trees and blobs
[0:00] 100.00% 4 / 4 snapshots
read all data
[0:00] 100.00% 6 / 6 packs
no errors were found
Без --read-data проверяются только структура и контрольные суммы
метаданных, это быстро. С флагом читаются и сверяются все блоки: на
терабайтах это долго и дорого по трафику, поэтому полную проверку обычно
гоняют по расписанию раз в месяц, а частичную (--read-data-subset=1/10)
чаще.
И помните, что check проверяет целостность репозитория, а не пригодность
данных. Настоящая проверка это восстановление и запуск того, что
восстановили.
Как это выглядит в бою
#!/bin/sh
set -e
export RESTIC_REPOSITORY=s3:s3.example.com/backups
export RESTIC_PASSWORD_FILE=/etc/restic/pass
pg_dump -Fc mydb > /var/backups/mydb.dump
restic backup --host web-01 /var/backups /var/lib/app
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
restic check
Скрипт в cron, вывод в лог, лог в мониторинг. Отдельно стоит следить за тем, что бэкап вообще был: тишина в логах обычно означает не «всё хорошо», а «скрипт не запускался».
Что важно запомнить
Пароль репозитория это ключ шифрования: потеряли — данные потеряны насовсем.
Дедупликация видна прямо в выводе: обработано 195 KiB, добавлено 1.76 KiB.
--host с постоянным именем нужен, чтобы restic находил предыдущий снимок
и не перечитывал всё заново.
restore --include достаёт отдельный файл без разворачивания всего снимка.
forget применяет правила внутри группы «хост плюс пути», поэтому снимков
остаётся больше, чем кажется по числу в --keep-last.
check --read-data проверяет целостность репозитория, но не заменяет
тестовое восстановление.
Прошли материал до конца? Отметьте урок пройденным.
Прогресс сохранён в этом браузере
Почистишь историю или откроешь с телефона, и отметки пропадут. Оставь почту, они переедут в аккаунт. Пароль придумывать не нужно.
Готово. теперь в аккаунте: прогресс виден с любого устройства. Мой прогресс