Все системы в норме · Средняя загрузка нод: 23% · Потери пакетов: 0,41 мс Статус сети →
Данные · 12 минут · обновлено 11.04.2026

Автобэкап на Storage VPS через restic

Снимок диска в панели — это удобно перед рискованным обновлением, но он лежит в том же дата-центре и на той же инфраструктуре. Настоящая резервная копия хранится в другой стране, шифруется вашим ключом и проверяется автоматически. Ниже — рабочая схема на restic.

Схема

Боевой сервер (например, NODE-4 в Дронтене) каждую ночь отправляет инкрементальную копию на Storage VPS (ARC-2 в Кишинёве). Данные шифруются до отправки, репозиторий на приёмнике бесполезен без пароля. Разные страны означают, что проблема на одной площадке не затрагивает копии.

1. Подготовка хранилища

На Storage VPS создаём отдельного пользователя без права входа в оболочку:

adduser --disabled-password --gecos "" backup
mkdir -p /home/backup/.ssh /srv/repo
chown -R backup:backup /home/backup /srv/repo

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

ssh-keygen -t ed25519 -N "" -f /root/.ssh/backup_key -C "backup@node-4"

Публичную часть кладём на хранилище с жёстким ограничением: ключ сможет запускать только приёмную часть restic и ничего больше.

command="restic --append-only serve --stdio --path /srv/repo",\
no-port-forwarding,no-agent-forwarding,no-pty ssh-ed25519 AAAA... backup@node-4

--append-only — ключевая деталь. Даже если боевой сервер будет скомпрометирован, злоумышленник не сможет удалить старые копии: режим разрешает только добавление.

2. Инициализация репозитория

apt install restic
export RESTIC_REPOSITORY="sftp:[email protected]:/srv/repo"
export RESTIC_PASSWORD_FILE=/root/.restic-pass

head -c 32 /dev/urandom | base64 > /root/.restic-pass
chmod 600 /root/.restic-pass

restic init

Содержимое /root/.restic-pass сохраните в менеджер паролей прямо сейчас. Без него репозиторий не открыть — ни вам, ни нам, ни кому-либо ещё.

3. Скрипт резервного копирования

Файл /usr/local/bin/backup.sh:

#!/bin/bash
set -euo pipefail

export RESTIC_REPOSITORY="sftp:[email protected]:/srv/repo"
export RESTIC_PASSWORD_FILE=/root/.restic-pass

# дамп базы перед копированием файлов
if systemctl is-active --quiet postgresql; then
  sudo -u postgres pg_dumpall | zstd -9 > /var/backups/pg.sql.zst
fi

restic backup \
  --verbose \
  --exclude-caches \
  --exclude '/var/cache' \
  --exclude '/var/lib/docker/overlay2' \
  --exclude '/proc' --exclude '/sys' --exclude '/dev' --exclude '/run' \
  /etc /home /srv /var/www /var/backups

# ротация: 7 дневных, 4 недельных, 6 месячных
restic forget --prune \
  --keep-daily 7 --keep-weekly 4 --keep-monthly 6

# проверка 5 % данных на каждом запуске
restic check --read-data-subset=5%
chmod 700 /usr/local/bin/backup.sh

Обратите внимание на дамп базы: копировать файлы работающей СУБД бессмысленно — вы получите несогласованное состояние, которое не восстановится.

4. Запуск по расписанию

Cron годится, но systemd-таймер даёт журнал, разброс времени запуска и корректный учёт пропущенных запусков.

/etc/systemd/system/backup.service:

[Unit]
Description=Nightly restic backup
After=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
Nice=10
IOSchedulingClass=idle

/etc/systemd/system/backup.timer:

[Unit]
Description=Run restic backup nightly

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

[Install]
WantedBy=timers.target
systemctl daemon-reload
systemctl enable --now backup.timer
systemctl list-timers backup.timer

RandomizedDelaySec разбрасывает старт в пределах получаса — если у вас десяток серверов, они не пойдут на хранилище одновременно.

5. Восстановление

Резервная копия, которую ни разу не восстанавливали, — это не резервная копия. Проверьте прямо после настройки:

restic snapshots                                  # список копий
restic restore latest --target /tmp/check --include /etc/nginx
restic restore 4a8f1c2e --target /                 # полное восстановление

Ещё удобнее смонтировать репозиторий и посмотреть содержимое как обычные файлы:

mkdir /mnt/backup
restic mount /mnt/backup

6. Контроль

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

# в конце backup.sh
if [ $? -ne 0 ]; then
  curl -s -X POST "https://api.telegram.org/bot<TOKEN>/sendMessage" \
    -d chat_id=<ID> -d text="Бэкап node-4 упал: $(date)"
fi

Раз в месяц смотрите журнал: journalctl -u backup.service --since "30 days ago".

Сколько это стоит

ARC-1 с терабайтом дискового пространства — 908 ₽ в месяц. Для сравнения: услуга автобэкапа в панели стоит 255 ₽ и хранит семь ежедневных копий вне ноды, но в том же дата-центре. Для критичных данных имеет смысл использовать обе схемы: локальные копии для быстрого отката, restic в другой стране — на случай серьёзных проблем.

Чек-лист

  • Отдельный ключ SSH только под бэкап, режим --append-only на приёмнике.
  • Пароль репозитория сохранён вне сервера.
  • Базы данных выгружаются дампом, а не копируются файлами.
  • Настроена ротация: 7 дневных, 4 недельных, 6 месячных.
  • Восстановление проверено вручную хотя бы один раз.
  • Настроено оповещение об ошибке.