Резервное копирование VPS — та настройка, о которой вспоминают в худший момент: после rm -rf не в том каталоге, шифровальщика или умершей базы. Правило 3-2-1 формулируется в одну строку: три копии данных, на двух разных носителях, одна — вне основной площадки. В этой инструкции превратим правило в работающую систему: напишем скрипт бэкапа файлов и MySQL для Ubuntu 24.04 LTS, отправим копии на второй сервер по rsync и в S3-хранилище через restic, настроим ротацию и — самое важное — проверим восстановление. Всё на бесплатных инструментах, все команды рабочие.
Почему именно 3-2-1
Каждый элемент правила закрывает свой сценарий отказа:
- 3 копии (рабочие данные + два бэкапа) — потому что одиночный бэкап имеет свойство оказываться битым именно тогда, когда нужен.
- 2 разных носителя/системы — локальный архив на том же NVMe погибнет вместе с диском; вторая копия должна жить на другом железе.
- 1 копия вне площадки — защита от отказа дата-центра, блокировки аккаунта или человеческой ошибки, задевшей все серверы у одного провайдера.
Типичная ошибка новичка — считать бэкапом снапшоты хостера. Это полезный инструмент, но он хранится в той же инфраструктуре: сценарий «проблема на площадке» им не закрыт. Снапшот — дополнение к 3-2-1, а не замена.
Что копировать: карта данных сервера
Копировать образ всей системы обычно избыточно — ОС и пакеты переустанавливаются за 15 минут, а вот данные невосполнимы. Минимальный набор для типичного веб-сервера:
| Что | Где лежит | Как часто |
|---|---|---|
| Файлы сайтов и приложений | /var/www, /home/app | Ежедневно |
| Базы данных | Дамп mysqldump / pg_dump | Ежедневно, для магазинов — каждые 1–6 часов |
| Конфиги служб | /etc/nginx, /etc/ssh, /etc/letsencrypt, /etc/systemd/system | Ежедневно (места почти не занимают) |
| Задания cron | вывод crontab -l, /etc/cron.d | Ежедневно |
| Список пакетов | вывод dpkg --get-selections | Ежедневно |
Важно: базу данных нельзя бэкапить простым копированием файлов из /var/lib/mysql на работающем сервере — файлы меняются в процессе, копия выйдет неконсистентной. Только дамп. Если MySQL у вас ещё не настроен как следует, начните со статьи MySQL на VPS: установка и первичная настройка.
Копия №1: локальный скрипт с ротацией
Создаём каталог и скрипт:
sudo mkdir -p /backup
sudo nano /usr/local/bin/backup.sh
Содержимое скрипта (пути и имя базы поменяйте на свои):
#!/bin/bash
set -euo pipefail
DATE=$(date +%F)
DEST="/backup"
# 1. Дамп базы данных (доступ настроен в ~/.my.cnf)
mysqldump --single-transaction --routines --triggers \
--databases myapp | gzip > "$DEST/db-$DATE.sql.gz"
# 2. Файлы сайта и конфиги
tar -czf "$DEST/files-$DATE.tar.gz" \
/var/www \
/etc/nginx /etc/letsencrypt /etc/ssh /etc/systemd/system
# 3. Cron и список пакетов
crontab -l > "$DEST/crontab-$DATE.txt" 2>/dev/null || true
dpkg --get-selections > "$DEST/packages-$DATE.txt"
# 4. Ротация: удаляем локальные копии старше 7 дней
find "$DEST" -maxdepth 1 -type f -mtime +7 -delete
Пара пояснений. Ключ --single-transaction позволяет mysqldump снять целостный срез InnoDB-таблиц без блокировки базы. Пароль в скрипте не светим: создайте файл ~/.my.cnf с правами 600 и секцией [client], где указаны user и password. Строка set -euo pipefail останавливает скрипт при первой ошибке — молча «наполовину сделанный» бэкап хуже отсутствующего.
Делаем исполняемым, проверяем вручную и ставим в cron на 03:30:
sudo chmod +x /usr/local/bin/backup.sh
sudo /usr/local/bin/backup.sh
sudo crontab -e
# добавить строку:
30 3 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
Копия №2: второй сервер через rsync
Локальный архив защитил от rm -rf, но не от гибели самого VPS. Вторую копию отправляем на другой сервер — для этой роли не нужна мощная машина, хватит недорогого NAT VPS: у Cheap-Host тариф NAT Plus (4 vCPU, 8 ГБ RAM, 50 ГБ NVMe) стоит 349 ₽/мес, и его диска хватит на недельную историю бэкапов небольшого проекта. Бонус — сервер физически в Германии, то есть третий пункт правила 3-2-1 (копия вне площадки) закрывается автоматически.
На боевом сервере генерируем отдельный ключ для бэкапов и копируем его на резервный:
ssh-keygen -t ed25519 -f ~/.ssh/backup_key -N ""
ssh-copy-id -i ~/.ssh/backup_key.pub -p 22022 backup@IP_резервного
(Порт подставьте свой: на NAT VPS SSH живёт на выделенном порту из панели. Про настройку ключей подробнее — в статье SSH-ключи вместо пароля.)
Синхронизация каталога бэкапов:
rsync -a --delete -e "ssh -p 22022 -i ~/.ssh/backup_key" \
/backup/ backup@IP_резервного:/srv/backups/web01/
Ключ -a сохраняет права и время файлов, --delete убирает на приёмнике то, что удалено ротацией на источнике. Добавляем команду в тот же backup.sh последней строкой или отдельной cron-задачей на 04:00 — после завершения локального бэкапа.
Копия №3: S3-хранилище через restic
Третья копия — в независимое S3-совместимое хранилище (подойдёт любой провайдер объектного стораджа). Restic здесь удобнее самодельных скриптов: дедупликация экономит место (хранятся только изменённые блоки), шифрование включено по умолчанию, ротация встроена. Установка из репозитория Ubuntu 24.04:
sudo apt install restic
Инициализируем репозиторий и делаем первый бэкап:
export AWS_ACCESS_KEY_ID="ваш_ключ"
export AWS_SECRET_ACCESS_KEY="ваш_секрет"
export RESTIC_REPOSITORY="s3:https://s3.example.com/my-backups"
export RESTIC_PASSWORD="длинная_фраза_для_шифрования"
restic init
restic backup /backup /var/www /etc/nginx
restic snapshots
Ротация по классической схеме «7 дневных, 4 недельных, 6 месячных»:
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
Пароль репозитория сохраните в надёжном месте вне сервера: restic шифрует данные, и без пароля восстановить их не сможет никто, включая вас. Подробный разбор restic и rclone с примерами под разные хранилища — в отдельной статье бэкапы в S3-хранилище.
Проверка восстановления: без неё всё зря
Непроверенный бэкап — это лотерейный билет, а не страховка. Классика жанра: год исправно работавший скрипт копировал пустой каталог, потому что путь поменялся. Раз в месяц устраивайте учения:
- Разверните чистый сервер (на Cheap-Host он выдаётся за 45–60 секунд — удобно поднять машину на час и удалить).
- Распакуйте архив:
tar -xzf files-2026-07-17.tar.gz -C /илиrestic restore latest --target /restore. - Залейте дамп:
zcat db-2026-07-17.sql.gz | mysql. - Запустите nginx и приложение, откройте сайт, проверьте свежесть данных.
- Засеките время — это ваш реальный RTO (время восстановления).
Заодно проверяйте, что бэкапы вообще выполняются: тишина в логах неотличима от успеха. Простейший вариант — строка в конце backup.sh, отправляющая результат в Telegram; как настроить такие уведомления и мониторинг в целом, разобрано в статье мониторинг VPS своими руками. Кстати, отработанное восстановление из бэкапа — это одновременно и готовый план переезда: см. миграция на другой VPS.
Типичные ошибки резервного копирования
- Бэкап лежит только на том же сервере. Отказ диска уносит и данные, и «страховку».
- База копируется файлами, а не дампом. Восстановление из такой копии — рулетка.
- Нет ротации. Диск заполняется, скрипт падает, и это замечают через месяц.
- Хранится только вчерашняя копия. Взлом или порчу данных часто находят через недели — нужна глубина истории.
- Секреты в открытом виде. Дампы с данными пользователей уходят в чужое хранилище без шифрования.
- Восстановление никогда не проверялось. Самая дорогая ошибка из всех.
FAQ
Достаточно ли снапшотов хостера вместо своих бэкапов?
Нет: снапшоты хранятся в той же инфраструктуре, что и сервер, и не защищают от проблем на стороне площадки или закрытия аккаунта. По правилу 3-2-1 хотя бы одна копия должна жить вне хостинга — на другом сервере, в S3 или локально у вас.
Как часто делать бэкап сервера?
Отталкивайтесь от допустимой потери данных (RPO). Для блога достаточно ежесуточной копии, для интернет-магазина базу стоит выгружать каждые 1–6 часов, файлы — раз в сутки. Конфиги достаточно копировать при изменениях, но проще включить их в ежедневный архив.
Можно ли бэкапить MySQL простым копированием файлов?
Нельзя на работающей базе: файлы InnoDB в момент копирования меняются, и копия почти наверняка окажется неконсистентной. Используйте mysqldump --single-transaction — он делает целостный дамп без остановки базы.
Сколько хранить старые копии?
Разумный минимум — 7 ежедневных, 4 еженедельных и 3–6 ежемесячных. Длинный хвост нужен потому, что порчу данных или взлом иногда замечают через недели, и вчерашний бэкап к этому моменту уже содержит проблему.
Нужно ли шифровать бэкапы?
Копии, покидающие сервер, — обязательно: в дампах лежат данные пользователей, в конфигах — пароли и ключи. Restic шифрует всё по умолчанию, для tar-архивов подойдут age или gpg. Пароль шифрования храните отдельно от бэкапов — без него восстановление невозможно.
Вывод
Стратегия 3-2-1 на VPS реализуется за вечер: скрипт с mysqldump и tar плюс cron — первая копия, rsync на второй сервер — вторая, restic в S3 — третья, вне площадки. Останется ежемесячно проверять восстановление — и потеря сервера превратится из катастрофы в час рутинной работы. Если нужен сервер под основной проект — у Cheap-Host тариф Pro за 750 ₽/мес (12 vCPU, 16 ГБ RAM, 128 ГБ NVMe, безлимитный трафик), а под хранение бэкапов — NAT Plus за 349 ₽/мес с 50 ГБ NVMe в Германии; оба разворачиваются за минуту.