Инкрементальные бэкапы с restic
restic — консольная программа для резервного копирования, которая шифрует данные ещё на стороне клиента, хранит их дедуплицированно и после первого полного снимка загружает только изменения. В этой статье вы установите restic на VPS ForestsNet Cloud, создадите репозиторий (на локальном диске, на другом сервере по SFTP или в S3), сделаете и восстановите бэкап, а также настроите политику хранения, чтобы старые снимки не копились бесконечно.
Что понадобится
- VPS ForestsNet Cloud на Ubuntu 22.04/24.04, Debian 11/12 или AlmaLinux/Rocky Linux 8/9.
- Доступ по SSH под
rootили пользователем сsudo. - Куда складывать бэкапы — один из вариантов шага 3: смонтированный отдельный диск на этом же сервере, второй сервер (например, ещё один VPS ForestsNet Cloud) с доступом по SSH, либо bucket в S3 или S3-совместимом хранилище с ключами доступа.
- Данные, которые нужно защитить, — в примерах ниже это
/etcи/var/www; замените на свои пути.
ℹ️ Совет: команды ниже даны от имени root — бэкап /etc в любом случае требует root (там есть файлы, недоступные на чтение обычным пользователям), а задание cron из последнего шага тоже будет выполняться от root. Если работаете под пользователем с sudo — проще один раз выполнить sudo -i и дальше идти по статье как есть: экспортированные переменные окружения (шаги 2–3) не передаются в команду через отдельный sudo без флага -E.
Как это устроено: шифрование, дедупликация, инкрементальность
- Шифрование. restic шифрует данные ещё на клиенте, до отправки в репозиторий, — AES-256 в режиме счётчика (CTR) плюс Poly1305-AES в качестве MAC для проверки целостности. Даже если репозиторий лежит на чужом сервере или в публичном облаке, без пароля прочитать его содержимое не получится.
- Дедупликация. Файлы режутся на фрагменты переменного размера (content-defined chunking, по отпечаткам Rabin) — обычно от 512 КиБ до 8 МиБ, в среднем около 1 МиБ; файлы меньше 512 КиБ не режутся вовсе. Каждый фрагмент адресуется по хешу SHA-256, и одинаковые фрагменты — даже из разных файлов и разных снимков — физически хранятся в репозитории только один раз.
- Инкрементальность. При каждом новом
restic backuprestic читает файлы заново, но благодаря дедупликации загружает в репозиторий только те фрагменты, которых там ещё нет, — фактически только изменения. При этом каждый снимок (snapshot) в списке выглядит как полноценный самостоятельный бэкап: чтобы восстановиться, не нужно искать «полный» бэкап и вручную накатывать на него цепочку инкрементов, как в классических схемах full+incremental, — берёте любой снимок и восстанавливаетесь прямо из него.
Шаг 1. Установите restic
Готового рецепта VMmanager 6 для restic нет (в отличие, например, от Zabbix или LEMP — полный список того, что ставится в один клик, в статье «Готовые рецепты VMmanager 6») — ставится restic одной командой из штатных репозиториев.
Ubuntu / Debian
apt update
apt install -y resticAlmaLinux / Rocky Linux
Пакет restic не входит в базовые репозитории — подключите EPEL:
dnf install -y epel-release
dnf install -y resticПроверьте версию:
restic versionℹ️ Совет: пакет из репозитория дистрибутива может отставать от самой свежей версии restic. Если нужна именно последняя версия — скачайте бинарник со страницы релизов github.com/restic/restic/releases, а дальше обновляйте его командой restic self-update (она сама проверяет GPG-подпись и подставляет свежий бинарник).
Шаг 2. Задайте пароль репозитория
Пароль репозитория — это то, из чего restic выводит ключ шифрования. Сам restic пароль нигде в открытом виде не хранит и восстановить его не может — только вы.
Сгенерируйте случайный пароль и сохраните его в файл, доступный на чтение только root:
mkdir -p /etc/restic
openssl rand -base64 48 > /etc/restic/password.txt
chmod 600 /etc/restic/password.txtПароль можно передавать restic тремя способами:
RESTIC_PASSWORD— сам пароль прямо в переменной окружения (виден в выводеpsи истории команд — для сервера не лучший вариант);RESTIC_PASSWORD_FILE(или флаг--password-file) — путь к файлу с паролем, как созданный выше;RESTIC_PASSWORD_COMMAND(или флаг--password-command) — команда, которая выводит пароль в stdout, например обращение к менеджеру паролей.
Экспортируйте переменную на файл — дальше по статье restic будет брать пароль из него и не станет спрашивать интерактивно:
export RESTIC_PASSWORD_FILE=/etc/restic/password.txt⚠️ Важно: потерянный пароль репозитория означает потерянные бэкапы — обхода или сброса пароля у restic не предусмотрено. Держите его копию отдельно от этого VPS (например, в менеджере паролей) — если сервер выйдет из строя, копия внутри него самого (/etc/restic/password.txt) пропадёт вместе с сервером.
Шаг 3. Создайте репозиторий (restic init)
Репозиторий — это то место, куда restic пишет зашифрованные и дедуплицированные данные. restic поддерживает и другие бэкенды (Backblaze B2, Azure Blob Storage, Google Cloud Storage, rclone, REST-сервер и другие) — здесь разберём три варианта, которые чаще всего нужны на VPS. Выберите один.
Локальный диск
Подходит для отдельного смонтированного диска на этом же сервере — например, для быстрого локального восстановления. Как единственная защита не годится: при потере или аварии самого сервера пропадёт и репозиторий вместе с ним — для надёжной защиты нужна ещё и копия за пределами этого сервера (SFTP или S3, см. варианты ниже).
mkdir -p /mnt/backup/restic-repo
export RESTIC_REPOSITORY=/mnt/backup/restic-repo
restic initПо SFTP на другой сервер
Понадобится второй сервер (например, ещё один VPS ForestsNet Cloud в другой локации) с SSH и беспарольным входом по ключу — без этого автоматический бэкап по расписанию будет останавливаться на запросе пароля. Пользователь resticbackup ниже — обычный пользователь на сервере-приёмнике (подойдёт и root, но отдельный пользователь безопаснее); создайте его заранее, если такого ещё нет.
Сгенерируйте отдельный ключ и скопируйте его на сервер-приёмник:
ssh-keygen -t ed25519 -f ~/.ssh/restic_backup -N ""
ssh-copy-id -i ~/.ssh/restic_backup.pub [email protected]Добавьте настройки для этого хоста в ~/.ssh/config — restic использует обычный SSH, поэтому подхватит их сам:
cat >> ~/.ssh/config <<'EOF'
Host backup.example.com
IdentityFile ~/.ssh/restic_backup
ServerAliveInterval 60
ServerAliveCountMax 240
EOFℹ️ Совет: ServerAliveInterval/ServerAliveCountMax не дают SSH разорвать соединение по тайм-ауту, пока restic долго обрабатывает большой объём данных, ничего не отправляя по сети.
Создайте репозиторий:
export RESTIC_REPOSITORY="sftp:[email protected]:/srv/restic-repo"
restic init⚠️ Важно: на сервере-приёмнике должен быть открыт порт SSH (обычно 22) в файрволе — иначе restic не подключится. Как открыть порт — в статье «Настройка файрвола UFW».
ℹ️ Совет: SFTP-серверы не разворачивают ~ как домашнюю директорию пользователя — если путь в RESTIC_REPOSITORY не начинается с /, restic будет считать его относительным к домашней папке пользователя resticbackup на сервере-приёмнике.
В S3 или S3-совместимом хранилище
Подойдёт Amazon S3 или любое S3-совместимое object storage — синтаксис отличается только URL.
Задайте ключи доступа:
export AWS_ACCESS_KEY_ID=<MY_ACCESS_KEY>
export AWS_SECRET_ACCESS_KEY=<MY_SECRET_ACCESS_KEY>Amazon S3:
export RESTIC_REPOSITORY="s3:s3.us-east-1.amazonaws.com/forestsnet-backups"
restic initДругое S3-совместимое хранилище — вместо адреса AWS укажите endpoint провайдера:
export RESTIC_REPOSITORY="s3:https://s3.example-provider.com/forestsnet-backups"
restic initℹ️ Совет: для Amazon S3 restic создаст указанный bucket сам, если его ещё нет. Не все S3-совместимые провайдеры это умеют (или требуют для этого отдельных прав) — надёжнее создать bucket заранее в панели провайдера. Если у провайдера свой регион по умолчанию — укажите его через AWS_DEFAULT_REGION или флагом -o s3.region="ваш-регион".
После того как репозиторий создан, сохраните обе переменные в файл — он понадобится в новых SSH-сессиях и в шаге 8 для cron:
cat > /etc/restic/env <<'EOF'
export RESTIC_REPOSITORY="sftp:[email protected]:/srv/restic-repo"
export RESTIC_PASSWORD_FILE=/etc/restic/password.txt
EOF
chmod 600 /etc/restic/envℹ️ Совет: подставьте в RESTIC_REPOSITORY тот адрес, который выбрали выше (локальный путь, sftp:... или s3:...). В новой SSH-сессии достаточно source /etc/restic/env — и команды restic ниже снова работают без флага -r и без запроса пароля.
✅ Готово: restic init без ошибок сообщает created restic repository ... at ... — репозиторий создан и готов принимать бэкапы.
Шаг 4. Сделайте первый бэкап (backup)
Список исключений — файлы и папки, которые бэкапить не нужно (логи, временные файлы и подобное). Создайте /etc/restic/excludes.txt:
cat > /etc/restic/excludes.txt <<'EOF'
*.log
*/node_modules
*/.git
EOFЗапустите первый бэкап — например, конфигурации сервера и файлов сайта:
restic backup --tag daily --exclude-file=/etc/restic/excludes.txt /etc /var/wwwrestic обойдёт указанные пути, зашифрует данные и загрузит их в репозиторий, а в конце покажет сводку: сколько файлов новых/изменённых/без изменений, сколько данных добавлено в репозиторий (Added to the repository: ...) и ID нового снимка.
ℹ️ Совет: отдельный путь или маску можно исключить прямо флагом, без файла, — --exclude="*.tmp" (флаг можно повторять). --tag тоже можно указывать несколько раз, если нужно больше одной метки.
Запустите ту же команду ещё раз, не меняя файлы:
restic backup --tag daily --exclude-file=/etc/restic/excludes.txt /etc /var/wwwВо второй раз restic всё равно читает все файлы заново — иначе не понять, что изменилось, — но благодаря дедупликации почти нечего загружать: в сводке будет Added to the repository: 0 B (0 B stored). Это и есть инкрементальность на практике.
✅ Готово: снимок создан. Дальше — как посмотреть список снимков и восстановиться из них.
Шаг 5. Посмотрите список снимков (snapshots)
restic snapshotsКоманда выведет таблицу по всем снимкам в репозитории: короткий ID снимка, дата и время создания, хост, теги (если задавали --tag) и список путей, которые вошли в снимок. ID снимка (первых нескольких символов достаточно, если они уникальны в репозитории) понадобится в следующем шаге для восстановления конкретной версии.
Шаг 6. Восстановите данные (restore)
Восстановить можно последний снимок:
restic restore latest --target /tmp/restoreИли конкретный — по ID из restic snapshots:
restic snapshots
restic restore 79766175 --target /tmp/restorerestic не перезаписывает файлы на месте — он воссоздаёт полный исходный путь внутри --target. Например, если бэкапили /etc, после восстановления с --target /tmp/restore конфиги окажутся в /tmp/restore/etc/.... Сравните восстановленные файлы с текущими и скопируйте нужное в боевое расположение вручную — так вы не затрёте случайно рабочую конфигурацию неудачным восстановлением.
Восстановить только часть снимка — например, один каталог — можно флагом --include:
restic restore latest --target /tmp/restore --include /etc/nginx✅ Готово: файлы появились в --target — восстановление отработало. Если восстанавливаете на другой сервер (например, при переезде), скопируйте их оттуда на постоянное место обычным cp/rsync.
Шаг 7. Ретеншн-политика: forget --prune
Без политики хранения каждый бэкап добавляет новый снимок, и список снимков растёт бесконечно. Команда forget убирает старые снимки по заданным правилам, но физически освобождает место, занятое больше не нужными данными, только prune — отдельной командой либо сразу, если добавить к forget флаг --prune.
Сначала проверьте, что политика удалит именно то, что вы ожидаете, — с --dry-run ничего не удаляется по-настоящему:
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --dry-runЕсли результат ожидаемый, выполните по-настоящему — сразу с --prune, чтобы освободить место, занятое удалёнными снимками:
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune--keep-daily 7— хранить по одному снимку за последние 7 дней, в которые был бэкап;--keep-weekly 4— плюс по одному снимку за 4 предыдущие недели;--keep-monthly 6— плюс по одному снимку за 6 предыдущих месяцев.
Снимок сохраняется, если подходит хотя бы под одно из условий (условия работают через «ИЛИ», а не все одновременно). Есть и более простой вариант — --keep-last N, оставить только N последних снимков независимо от календаря. По умолчанию restic группирует снимки по хосту и набору путей и применяет политику к каждой группе отдельно — это важно, если один и тот же репозиторий используют несколько серверов или в нём бэкапятся разные наборы путей.
⚠️ Важно: forget без --dry-run удаляет записи о снимках сразу и без отмены (кроме восстановления из отдельной копии репозитория). А сам prune может надолго занять диск, CPU и сеть — он перекладывает данные внутри репозитория, и это особенно заметно на SFTP/S3 с большим объёмом. Планируйте prune на спокойное для сервера время суток.
Шаг 8. Автоматизируйте через cron
Заверните бэкап и очистку старых снимков в один скрипт:
cat > /usr/local/bin/restic-backup.sh <<'EOF'
#!/bin/bash
set -euo pipefail
source /etc/restic/env
restic backup --tag daily --exclude-file=/etc/restic/excludes.txt /etc /var/www
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
EOF
chmod +x /usr/local/bin/restic-backup.shПроверьте его вручную перед тем, как доверить cron:
/usr/local/bin/restic-backup.shДобавьте задание в crontab — например, каждую ночь в 03:00:
crontab -e0 3 * * * /usr/local/bin/restic-backup.sh >> /var/log/restic-backup.log 2>&1ℹ️ Совет: разбор синтаксиса cron, ротации логов и уведомлений о сбое бэкапа — отдельная тема, подробно разобранная в статье «Бэкапы по расписанию: cron».
✅ Готово: бэкапы теперь снимаются и чистятся сами, без ручного запуска.
Что дальше
Полный разбор автоматизации через cron — в статье «Бэкапы по расписанию: cron». Если для ваших задач достаточно простого зеркалирования файлов на другой сервер без шифрования и дедупликации — см. «Бэкапы через rsync».