Бэкапы сайтов и проектов: как делать правильно и нужен ли отдельный S3
В этой статье разберём, как правильно делать резервные копии сайтов и проектов. Что именно копировать, сколько копий нужно и где их хранить, почему бэкапов хостинга недостаточно и зачем нужно отдельное S3-хранилище у другого провайдера. Покажем, как защитить копии от взлома и случайного удаления и как всё это автоматизировать. В конце — готовый скрипт, пример для Laravel и чек-лист. Примеры рассчитаны на сайты на VPS или хостинге с SSH, например на Рег.ру или Timeweb Cloud, но подход одинаковый для любого провайдера.
От чего защищает бэкап
Резервная копия нужна не «на случай поломки диска» — это как раз самый редкий сценарий. Чаще данные теряют так:
- Ошибка человека.
DROP TABLEне на той базе, неудачная миграция, удалённая папка с загрузками. - Ошибка в коде. Скрипт, который неделю тихо портил данные, пока никто не заметил.
- Взлом. Злоумышленник шифрует или удаляет данные — и заодно бэкапы, если до них можно дотянуться с того же сервера.
- Проблемы у провайдера. Сбой в дата-центре, блокировка аккаунта, неоплаченный счёт, ошибка поддержки. Известный пример — пожар в дата-центре OVH в Страсбурге в марте 2021 года: часть клиентов потеряла и серверы, и копии, которые хранились там же.
Из этого списка следуют почти все правила ниже: копий должно быть несколько, хотя бы одна — в другом месте и под другим доступом, и нужны старые версии, а не только вчерашняя.
Что копировать, а что нет
| Что | Копировать | Почему |
|---|---|---|
| База данных (MySQL, PostgreSQL) | Да, обязательно | Самое ценное и то, что нельзя восстановить из других источников |
Загруженные файлы (uploads, storage/app) |
Да | Картинки и документы пользователей есть только на сервере |
Конфигурация (.env, конфиги Nginx, cron) |
Да, но отдельно и зашифровано | Без неё восстановление растянется на часы; внутри пароли и ключи |
| Код | Он уже в Git | Но Git-репозиторий тоже нужно где-то копировать, если он у одного провайдера |
vendor/, node_modules/, кэш, логи |
Нет | Пересобираются командами composer install, npm ci; только раздувают копию |
Отдельно — секреты: пароли от S3, ключ шифрования бэкапов, доступы к хостингу. Их храните в менеджере паролей, а не только на сервере. Если сервер пропал вместе с ключом шифрования, зашифрованный бэкап бесполезен.
Правило 3-2-1
Классическое правило резервного копирования:
- 3 копии данных: рабочая и две резервные;
- 2 разных типа хранения или площадки: например, диск сервера и объектное хранилище;
- 1 копия — вне основной площадки: у другого провайдера, в другом аккаунте.
Сейчас его часто дополняют до 3-2-1-1-0:
- ещё 1 копия — неизменяемая (immutable) или отключённая от сети: её нельзя удалить даже с полным доступом к серверу;
- 0 ошибок при проверке восстановления: бэкап считается рабочим, только когда из него реально восстановились.
Для небольшого проекта это выглядит так: бэкапы хостинга (копия 1) плюс собственные ежедневные дампы в S3 у другого провайдера с версионированием (копия 2, вне площадки и защищённая от удаления).
Почему бэкапов хостинга недостаточно
Рег.ру, Timeweb Cloud и другие провайдеры делают резервные копии VPS и хостинга — платно или в составе тарифа. Это хороший первый уровень: быстро откатить сервер целиком после неудачного обновления. Но полагаться только на них нельзя:
- копии лежат у того же провайдера и в том же аккаунте. Заблокировали аккаунт, взломали личный кабинет, случилась авария в дата-центре — пропадает всё сразу;
- обычно хранится несколько последних копий. Если порчу данных заметили через месяц, нужной версии уже нет;
- снимок диска с работающей базой не всегда консистентен. Дамп базы надёжнее;
- вы не контролируете расписание, срок хранения и не проверяете восстановление.
Нужен ли независимый S3
Да, и лучше у другого провайдера, чем хостинг. Объектное хранилище S3 — самый удобный способ хранить копии вне площадки:
- платите только за объём, а бэкапы небольших сайтов занимают единицы гигабайт;
- данные хранятся с репликацией внутри провайдера, вам не нужно следить за дисками;
- S3 API понимают все инструменты бэкапа: restic, rclone, Kopia,
spatie/laravel-backup, плагины WordPress; - есть версионирование и блокировка объектов (Object Lock) — защита от удаления.
S3-совместимые хранилища есть у многих российских провайдеров: у Timeweb Cloud, Рег.ру (Рег.облако), Selectel, Yandex Cloud (Object Storage) и других. Логика выбора простая — разнесите сайт и бэкапы по разным компаниям:
- сайты на Рег.ру → бэкапы в S3 Timeweb Cloud или Selectel;
- сайты в Timeweb Cloud → бэкапы в S3 Рег.ру, Selectel или Yandex Cloud.
Тогда проблема с одним провайдером не затронет второй. Если в базе есть персональные данные россиян, выбирайте хранилище с дата-центром в России — этого требует закон 152-ФЗ.
Как настроить S3 под бэкапы
- Создайте отдельный приватный бакет только для бэкапов, без публичного доступа.
- Включите версионирование. Если файл перезапишут или удалят, предыдущая версия останется.
- Если провайдер поддерживает Object Lock (например, в Timeweb Cloud он есть), включите его со сроком хранения 14–30 дней. Заблокированную версию нельзя удалить до конца срока даже с ключом администратора — это и есть неизменяемая копия.
- Создайте для сервера отдельный ключ доступа с правами только на этот бакет. Ключ от основного аккаунта на сервер класть нельзя.
- Настройте правила жизненного цикла (lifecycle), чтобы старые версии удалялись автоматически и хранилище не росло бесконечно.
Названия пунктов в панели и доступные режимы у провайдеров отличаются — сверяйтесь с документацией своего хранилища.
Куда отправлять копии: push или pull
- Push — сервер сам отправляет бэкап в хранилище. Просто, но на сервере лежит ключ от хранилища. Взломщик может им воспользоваться — поэтому нужны версионирование, Object Lock и ключ с минимальными правами.
- Pull — отдельный сервер забирает бэкапы с рабочих серверов по SSH. Рабочий сервер ничего не знает о хранилище, и взлом сайта не даёт доступа к копиям. Надёжнее, но нужен ещё один сервер.
Для нескольких небольших сайтов обычно достаточно push в S3 с версионированием. Pull стоит рассмотреть, когда проектов много или данные критичные.
Как делать дамп базы правильно
Не копируйте файлы базы (/var/lib/mysql) с работающего сервера — получите неконсистентную копию. Делайте логический дамп.
MySQL / MariaDB:
mysqldump --single-transaction --quick --routines --triggers --no-tablespaces \
my_database | gzip > /var/backups/db/my_database-$(date +%F).sql.gz
--single-transaction— консистентный снимок таблиц InnoDB без блокировки сайта;--quick— построчная выгрузка, не загружает всю таблицу в память;--routines --triggers— вместе с данными сохранит процедуры и триггеры;--no-tablespaces— нужен в MySQL 8, если у пользователя нет привилегииPROCESS(типично для хостинга); иначе дамп падает с ошибкой.
Пароль не передавайте в командной строке — его видно в списке процессов. Положите его в ~/.my.cnf с правами 600:
[mysqldump]
user=backup_user
password=секретный_пароль
PostgreSQL:
pg_dump --format=custom my_database > /var/backups/db/my_database-$(date +%F).dump
Формат custom уже сжат и позволяет восстанавливать отдельные таблицы через pg_restore.
Для бэкапов заведите отдельного пользователя БД только с правами на чтение (SELECT, SHOW VIEW, TRIGGER, LOCK TABLES, EVENT), а не используйте пользователя приложения или root.
Шифрование
Бэкап содержит всю базу: пользователей, заказы, хэши паролей. Если он попадёт в чужие руки, это та же утечка. Поэтому копии в стороннем хранилище шифруются на сервере до отправки, а ключ шифрования хранится отдельно, например в менеджере паролей.
Проще всего взять инструмент, который шифрует сам. restic шифрует всё по умолчанию, умеет дедупликацию (повторяющиеся данные хранятся один раз), ротацию копий и работает с любым S3-совместимым хранилищем. Альтернативы — Kopia и Borg (Borg работает по SSH, а не с S3 напрямую); для простых случаев — gpg или age поверх rclone.
Ротация: сколько хранить
Хранить все копии вечно дорого, а только последнюю — опасно. Обычно используют схему «дед-отец-сын» (GFS):
- 7 ежедневных копий;
- 4 еженедельных;
- 12 ежемесячных.
Так можно откатиться и на вчера, и на состояние трёхмесячной давности, если порчу заметили поздно. А места это занимает немного — особенно с дедупликацией.
Как часто делать копии, зависит от того, сколько данных не жалко потерять. Это называют RPO. Блог с одной статьёй в неделю — раз в сутки достаточно. Интернет-магазин с заказами каждый час — дампы каждый час или репликация базы. Второй параметр — RTO: за сколько нужно поднять сайт. От него зависит, хватит ли дампа или нужен готовый резервный сервер.
Пример: скрипт бэкапа на restic
Скрипт для VPS: делает дамп базы, отправляет его вместе с загрузками в S3, удаляет старые копии и сообщает об успехе в сервис мониторинга.
Сначала установите restic (sudo apt install restic в Ubuntu/Debian) и создайте файл с настройками /root/.backup-env с правами 600:
export AWS_ACCESS_KEY_ID='ключ_доступа_к_бакету'
export AWS_SECRET_ACCESS_KEY='секретный_ключ'
export RESTIC_REPOSITORY='s3:https://<endpoint-провайдера>/<имя-бакета>/my-site'
export RESTIC_PASSWORD_FILE='/root/.restic-password'
Адрес endpoint возьмите из панели S3 своего провайдера. В /root/.restic-password положите длинный случайный пароль (например, из openssl rand -base64 32) и сохраните его копию в менеджере паролей — без него восстановить данные невозможно. Затем один раз инициализируйте репозиторий:
source /root/.backup-env && restic init
Сам скрипт /usr/local/bin/backup-site.sh:
#!/usr/bin/env bash
set -euo pipefail
source /root/.backup-env
DUMP_DIR=/var/backups/db
mkdir -p "$DUMP_DIR"
# 1. Дамп базы (пароль — в /root/.my.cnf)
mysqldump --single-transaction --quick --routines --triggers --no-tablespaces \
my_database | gzip > "$DUMP_DIR/my_database.sql.gz"
# 2. Отправка дампа, загрузок и конфигов в S3 (шифрует restic)
restic backup "$DUMP_DIR" /var/www/my-site/storage/app /var/www/my-site/.env \
--tag my-site
# 3. Ротация: 7 дневных, 4 недельных, 12 месячных
restic forget --tag my-site --keep-daily 7 --keep-weekly 4 --keep-monthly 12 --prune
# 4. Сообщить мониторингу, что бэкап прошёл
curl -fsS --retry 3 https://hc-ping.com/<ваш-uuid> > /dev/null
Файл дампа каждый день перезаписывается под одним именем — это нормально: историю версий хранит restic. Из-за set -euo pipefail скрипт остановится на первой ошибке и не отправит сигнал об успехе.
Запуск каждую ночь в 03:30 — через sudo crontab -e:
30 3 * * * /usr/local/bin/backup-site.sh >> /var/log/backup-site.log 2>&1
Учтите: forget --prune удаляет старые данные из хранилища, поэтому ключу на сервере нужны права на удаление. Это ещё одна причина включить версионирование и Object Lock: даже если взломщик воспользуется ключом, заблокированные версии останутся. Для большей защиты ротацию можно запускать с отдельной машины другим ключом, а серверу дать ключ только на запись.
Если сайт на Laravel или WordPress
- Laravel. Пакет spatie/laravel-backup делает дамп базы и архив файлов, отправляет их на любой диск Laravel (в том числе S3), чистит старые копии и присылает уведомления о проблемах. Запуск — через планировщик Laravel (
backup:run,backup:clean,backup:monitor). Учтите: шифрование архива нужно включить отдельно, паролем в настройках пакета. - WordPress. Плагины вроде UpdraftPlus умеют отправлять копии в S3 по расписанию (произвольное S3-совместимое хранилище — в платной версии). На хостинге без SSH это самый простой вариант. Но плагин работает внутри взламываемого сайта — поэтому оставьте и копии хостинга, и версионирование в бакете.
Мониторинг: бэкап, который молча сломался
Самая частая история — бэкапы «настроены», но уже три месяца падают из-за смены пароля или переполненного диска. Чтобы этого не случилось:
- используйте «сигнал жизни» (dead man's switch): скрипт после успеха отправляет запрос в сервис вроде Healthchecks.io или Uptime Kuma, а тот пишет вам в Telegram или на почту, если сигнала нет в ожидаемое время. Сообщения об ошибках не спасают, когда cron вообще не запустился;
- раз в неделю запускайте
restic check— он проверяет целостность репозитория; - следите за размером копий: резкое уменьшение — признак того, что что-то перестало попадать в бэкап.
Проверка восстановления
Бэкап, из которого ни разу не восстанавливались, — это надежда, а не бэкап. Раз в месяц или раз в квартал:
- Достаньте последнюю копию:
source /root/.backup-env restic restore latest --tag my-site --target /tmp/restore-test - Разверните дамп в отдельную тестовую базу, не в рабочую:
mysql -e 'CREATE DATABASE restore_test' gunzip < /tmp/restore-test/var/backups/db/my_database.sql.gz | mysql restore_test - Проверьте, что данные свежие: последние записи, количество строк в главных таблицах, открываются ли загруженные файлы.
- Запишите, сколько времени заняло восстановление, и коротко опишите шаги в документации проекта. В момент аварии эта инструкция сэкономит часы.
Типичные ошибки
- Бэкапы лежат на том же сервере или у того же провайдера, что и сайт.
- На сервере ключ от основного аккаунта хранилища, а версионирование выключено — взломщик удалит и сайт, и все копии.
- Нет проверки восстановления: бэкап оказывается пустым или битым в самый нужный момент.
- Хранится только последняя копия, и порча данных, замеченная через неделю, уже в ней.
- Ключ шифрования есть только на сервере, который пропал.
- В бэкап попадают
vendor/и кэш, а загрузки пользователей — нет. - Пароль базы передаётся в командной строке, а архив с
.envлежит в публичной папке сайта.
Чек-лист
- Определите, что копировать: база, загрузки, конфиги; код — в Git.
- Оставьте бэкапы хостинга как первый уровень.
- Заведите S3 у другого провайдера: отдельный приватный бакет, версионирование, Object Lock, ключ с доступом только к этому бакету.
- Делайте дамп базы (
mysqldump --single-transactionилиpg_dump) отдельным пользователем с правами на чтение. - Шифруйте копии до отправки (restic) и храните пароль шифрования в менеджере паролей.
- Автоматизируйте через cron и ротацию 7 / 4 / 12.
- Подключите мониторинг «сигнала жизни» и
restic check. - Регулярно проверяйте восстановление на тестовой базе и записывайте шаги.