Системный журнал — практичная база знаний по VPS и Linux
Системный журнал Системный журнал
Backup • Linux • VPS • restic • Резервные копии

Резервное копирование Linux VPS: файлы, базы данных, restic и автоматизация

7 мин чтения Урок 4 из 6

Резервная копия должна пережить удаление VPS, ошибку администратора и компрометацию сервера. Копия на том же диске или снимок без проверки восстановления не решают эту задачу. Ниже — практическая схема для небольшого Linux VPS: согласованные дампы баз данных, копирование важных файлов в зашифрованный restic-репозиторий и автоматический запуск через systemd.

Сначала определите RPO и RTO

  • RPO — сколько данных допустимо потерять. При ежедневном backup максимальная потеря может составить почти сутки.
  • RTO — сколько времени допустимо восстанавливать сервис.

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

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

Практический минимум:

  1. Три экземпляра данных, включая рабочий.
  2. Два независимых типа или места хранения.
  3. Одна копия вне текущего VPS и желательно вне провайдера.

Не подключайте удалённое хранилище к серверу с правом безусловного удаления всех старых копий, если сервис поддерживает append-only или object lock. При компрометации злоумышленник получает права процесса backup.

Что сохранять

Составьте явный список:

  • /etc — конфигурация ОС и служб;
  • /var/www, /srv, /opt — приложения и пользовательские данные;
  • compose-файлы, env-файлы и volumes контейнеров;
  • дампы MariaDB/PostgreSQL;
  • список пакетов, systemd units, cron и timers;
  • сертификаты и ключи, если они нужны для восстановления;
  • документация с DNS, внешними сервисами и последовательностью запуска.

Не копируйте как обычные файлы живой каталог базы данных, если СУБД работает. Такая копия может быть внутренне несогласованной. Используйте логический дамп или штатный физический backup.

Создайте каталог подготовки

sudo install -d -m 700 /var/backups/vps
sudo install -d -m 700 /var/backups/vps/databases
sudo install -d -m 700 /var/backups/vps/inventory

Сохраните инвентаризацию

dpkg-query -W -f='${binary:Package}\t${Version}\n' \
  | sudo tee /var/backups/vps/inventory/packages.tsv >/dev/null

systemctl list-unit-files --state=enabled \
  | sudo tee /var/backups/vps/inventory/enabled-units.txt >/dev/null

sudo ss -lntup \
  > /var/backups/vps/inventory/listening-ports.txt

sudo crontab -l \
  > /var/backups/vps/inventory/root-crontab.txt 2>/dev/null || true

systemctl list-timers --all \
  > /var/backups/vps/inventory/timers.txt

Эти файлы не заменяют данные, но существенно ускоряют восстановление.

Согласованный дамп MariaDB

sudo mariadb-dump \
  --all-databases \
  --single-transaction \
  --quick \
  --routines \
  --events \
  --triggers \
  | gzip -1 \
  > /var/backups/vps/databases/mariadb-all.sql.gz

--single-transaction создаёт согласованный снимок транзакционных таблиц InnoDB без долгой глобальной блокировки. Таблицы нетранзакционных движков требуют отдельного анализа.

Проверка:

gzip -t /var/backups/vps/databases/mariadb-all.sql.gz
zgrep -m1 -E 'MariaDB dump|CREATE DATABASE' \
  /var/backups/vps/databases/mariadb-all.sql.gz

Согласованный дамп PostgreSQL

Для каждой важной базы создайте custom dump, а глобальные роли сохраните отдельно:

sudo -u postgres pg_dump -Fc appdb \
  > /var/backups/vps/databases/postgresql-appdb.dump

sudo -u postgres pg_dumpall --globals-only \
  | gzip -1 \
  > /var/backups/vps/databases/postgresql-globals.sql.gz

Проверка:

pg_restore --list \
  /var/backups/vps/databases/postgresql-appdb.dump | head

gzip -t \
  /var/backups/vps/databases/postgresql-globals.sql.gz

Установите restic

sudo apt update
sudo apt install restic
restic version

Restic шифрует содержимое и имена файлов на стороне клиента, выполняет дедупликацию и поддерживает локальные и удалённые backends. Репозиторий может находиться на отдельном диске, SFTP, S3-совместимом object storage или другом поддерживаемом хранилище.

Храните параметры отдельно

sudo install -d -m 700 /etc/restic
sudoedit /etc/restic/vps.env

Пример для SFTP:

RESTIC_REPOSITORY=sftp:backup@example.net:/srv/restic/vps-web01
RESTIC_PASSWORD_FILE=/etc/restic/password

Пароль:

sudo sh -c 'umask 077; openssl rand -base64 48 > /etc/restic/password'

Сохраните пароль отдельно от VPS. Потеря пароля означает потерю доступа ко всем снимкам. Копия файла на том же сервере нужна для автоматизации, но не является резервным хранением секрета.

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

sudo sh -c '. /etc/restic/vps.env; restic init'

Инициализацию выполняют один раз. Если репозиторий уже существует, команда сообщит об этом; не создавайте второй в том же пути.

Создайте список исключений

sudoedit /etc/restic/excludes.txt
/var/cache
/var/tmp
/tmp
/proc
/sys
/dev
/run
/mnt
/media
/swapfile
/var/lib/docker/overlay2
/var/lib/docker/containers/*/*-json.log

Volumes Docker исключать нельзя, если в них находятся единственные пользовательские данные. Лучше перечислить нужные volumes явно или создать штатные дампы приложений.

Первый backup

sudo sh -c '. /etc/restic/vps.env; exec restic backup \
  /etc \
  /var/www \
  /srv \
  /opt \
  /root \
  /var/backups/vps \
  --exclude-file=/etc/restic/excludes.txt \
  --one-file-system \
  --tag=vps'

--one-file-system не позволяет незаметно захватить смонтированное удалённое или временное хранилище. Если нужные данные находятся на отдельном разделе, добавьте его отдельным путём.

Проверьте снимок

sudo sh -c '. /etc/restic/vps.env; restic snapshots'
sudo sh -c '. /etc/restic/vps.env; restic stats latest'
sudo sh -c '. /etc/restic/vps.env; restic check'

restic check проверяет структуру репозитория. Периодически выполняйте более глубокую проверку данных согласно возможностям вашей версии и объёму хранилища.

Скрипт подготовки дампов

sudoedit /usr/local/sbin/vps-backup-prepare
#!/bin/sh
set -eu
umask 077

OUT=/var/backups/vps/databases
install -d -m 700 "$OUT"

if systemctl is-active --quiet mariadb; then
  mariadb-dump --all-databases \
    --single-transaction --quick \
    --routines --events --triggers \
    | gzip -1 > "$OUT/mariadb-all.sql.gz.tmp"
  gzip -t "$OUT/mariadb-all.sql.gz.tmp"
  mv "$OUT/mariadb-all.sql.gz.tmp" "$OUT/mariadb-all.sql.gz"
fi

if systemctl is-active --quiet postgresql; then
  runuser -u postgres -- pg_dumpall \
    | gzip -1 > "$OUT/postgresql-all.sql.gz.tmp"
  gzip -t "$OUT/postgresql-all.sql.gz.tmp"
  mv "$OUT/postgresql-all.sql.gz.tmp" "$OUT/postgresql-all.sql.gz"
fi
sudo chmod 700 /usr/local/sbin/vps-backup-prepare

Автоматизируйте через systemd service

sudoedit /etc/systemd/system/vps-backup.service
[Unit]
Description=Backup VPS with restic
Wants=network-online.target
After=network-online.target
ConditionPathExists=/etc/restic/vps.env

[Service]
Type=oneshot
EnvironmentFile=/etc/restic/vps.env
ExecStartPre=/usr/local/sbin/vps-backup-prepare
ExecStart=/usr/bin/restic backup /etc /var/www /srv /opt /root /var/backups/vps --exclude-file=/etc/restic/excludes.txt --one-file-system --tag=vps
ExecStartPost=/usr/bin/restic forget --keep-daily 7 --keep-weekly 5 --keep-monthly 12 --prune
Nice=10
IOSchedulingClass=best-effort
IOSchedulingPriority=7
PrivateTmp=true

Пути нужно адаптировать к вашему серверу. Сначала проверьте service вручную и только потом включайте таймер.

Создайте timer

sudoedit /etc/systemd/system/vps-backup.timer
[Unit]
Description=Daily VPS backup

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

[Install]
WantedBy=timers.target

Активируйте и протестируйте:

sudo systemctl daemon-reload
sudo systemctl start vps-backup.service
sudo systemctl status vps-backup.service --no-pager
sudo systemctl enable --now vps-backup.timer
systemctl list-timers vps-backup.timer --all

Мониторинг backup

Минимум контролируйте:

  • код завершения systemd service;
  • время последнего успешного снимка;
  • размер и рост репозитория;
  • свободное место локально и удалённо;
  • результат restic check;
  • успешное тестовое восстановление.
journalctl -u vps-backup.service --since '-7 days' --no-pager
systemctl show vps-backup.service \
  -p Result -p ExecMainStatus -p ActiveEnterTimestamp

Что нельзя считать backup

  • Копию в другом каталоге того же диска.
  • RAID: он защищает доступность, но повторяет удаление и повреждение.
  • Единственный snapshot у того же провайдера.
  • Файлы базы данных, скопированные во время работы без штатного инструмента.
  • Архив без ключа шифрования и инструкции восстановления.
  • Снимок, который ни разу не восстанавливали.

Итоговая схема

  1. Перед backup создаются согласованные дампы баз.
  2. Restic шифрует и отправляет конфигурацию, данные и дампы во внешнее хранилище.
  3. Systemd timer запускает процедуру по расписанию.
  4. Политика retention сохраняет ежедневные, недельные и месячные точки.
  5. Мониторинг обнаруживает сбой до аварии.
  6. Отдельная процедура регулярно проверяет реальное восстановление.