Резервное копирование Linux VPS: файлы, базы данных, restic и автоматизация
Резервная копия должна пережить удаление VPS, ошибку администратора и компрометацию сервера. Копия на том же диске или снимок без проверки восстановления не решают эту задачу. Ниже — практическая схема для небольшого Linux VPS: согласованные дампы баз данных, копирование важных файлов в зашифрованный restic-репозиторий и автоматический запуск через systemd.
Сначала определите RPO и RTO
- RPO — сколько данных допустимо потерять. При ежедневном backup максимальная потеря может составить почти сутки.
- RTO — сколько времени допустимо восстанавливать сервис.
Эти цели определяют частоту, объём хранения и необходимость репликации. Для небольшого сайта часто достаточно ежедневного полного логического дампа базы и инкрементальной файловой копии. Для магазина или активно меняющейся базы может потребоваться более частая схема.
Правило 3-2-1
Практический минимум:
- Три экземпляра данных, включая рабочий.
- Два независимых типа или места хранения.
- Одна копия вне текущего 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 у того же провайдера.
- Файлы базы данных, скопированные во время работы без штатного инструмента.
- Архив без ключа шифрования и инструкции восстановления.
- Снимок, который ни разу не восстанавливали.
Итоговая схема
- Перед backup создаются согласованные дампы баз.
- Restic шифрует и отправляет конфигурацию, данные и дампы во внешнее хранилище.
- Systemd timer запускает процедуру по расписанию.
- Политика retention сохраняет ежедневные, недельные и месячные точки.
- Мониторинг обнаруживает сбой до аварии.
- Отдельная процедура регулярно проверяет реальное восстановление.