- Опубликовано: 1 авг 2026
- 25
Бэкап есть — восстановить нельзя: проверяем резервные копии до аварии
Часть 12 из 14 · Серия «Хостинг без магии»
В панели хостинга каждый день появляется новая строка:
Резервная копия создана успешно
Владелец сайта спокоен.
Копии создаются автоматически. В списке доступны даты за последнюю неделю. Значит, при любой проблеме можно выбрать нужный день и вернуть сайт к работе.
Однажды интернет-магазин взламывают. Часть файлов зашифрована, база повреждена, а резервные копии внутри аккаунта удалены тем же вредоносным скриптом.
Поддержка находит копию двухдневной давности и запускает восстановление.
Файлы возвращаются. Главная страница открывается. Но войти в административную панель нельзя, а каталог пуст.
Выясняется, что в архив вошли только файлы. База данных копировалась отдельно и последние несколько недель завершалась ошибкой.
В другом проекте база есть, но её дамп равен нулю байт.
В третьем архив исправен, однако никто не знает пароль шифрования.
В четвёртом копия хранится на том же диске, который вышел из строя вместе с основным сайтом.
В пятом всё сохранено, но восстановление занимает двое суток, потому что инструкция существует только в голове у разработчика, который недоступен.
Во всех этих случаях резервная копия формально была.
Но готового способа вернуть сайт к работе не существовало.
Главный принцип резервного копирования:
Бэкап считается рабочим только после успешного проверочного восстановления.
Создание архива — это начало процесса. Результатом должна быть не коллекция файлов, а предсказуемая возможность восстановить конкретную версию сайта за приемлемое время.
Что такое резервная копия
Резервная копия — отдельная сохранённая версия данных, которую можно использовать после:
- случайного удаления;
- неудачного обновления;
- ошибки разработчика;
- повреждения базы;
- взлома;
- заражения;
- отказа диска;
- потери аккаунта;
- неправильной миграции;
- сбоя оборудования;
- удаления почты;
- компрометации доступа.
Ключевое слово — отдельная.
Каталог:
/home/user/site-backup/
рядом с рабочим сайтом удобен для быстрого отката, но не защищает от:
- поломки диска;
- удаления аккаунта;
- взлома пользователя;
- вредоносного шифрования;
- ошибки команды
rm -rf; - блокировки доступа к хостингу;
- аварии дата-центра.
Резервирование должно учитывать не только потерю одного файла, но и потерю всей среды.
Копия, синхронизация и высокая доступность — разные вещи
Эти понятия часто смешивают.
Синхронизация
Сервис автоматически повторяет изменения:
файл удалён на сервере
↓
файл удалён в синхронизированной папке
Синхронизация удобна для актуальной копии, но быстро переносит и ошибку.
Репликация
Данные копируются на другой сервер почти в реальном времени.
Если приложение записало повреждённые данные, они могут немедленно попасть и в реплику.
Реплика помогает при отказе основного узла, но не заменяет историю резервных копий.
Снимок
Snapshot фиксирует состояние диска или файловой системы в конкретный момент.
Он удобен для быстрого отката инфраструктуры, но может:
- находиться у того же провайдера;
- зависеть от того же аккаунта;
- не гарантировать логическую согласованность базы;
- удалиться вместе с сервером;
- не подходить для восстановления одного объекта.
Резервная копия
Сохраняет отдельную версию данных с историей и сроком хранения.
Высокая доступность
Позволяет продолжить работу при отказе части инфраструктуры.
Несколько серверов и реплика базы уменьшают простой, но не возвращают данные, удалённые неделю назад.
Надёжный проект может использовать все механизмы одновременно:
репликация
для быстрого переключения
снимки
для оперативного отката
резервные копии
для истории и аварийного восстановления
Один механизм не заменяет остальные.
Сначала определите, от каких аварий защищаетесь
Нельзя оценить бэкап без сценария.
Составьте список:
Случайно удалили один файл.
Неудачно обновили CMS.
Миграция испортила таблицу.
Сайт взломали три дня назад.
Потерян весь аккаунт хостинга.
Вышел из строя сервер.
Удалили почтовый ящик.
Провайдер заблокировал доступ.
Разработчик потерял .env.
Данные шифруются вредоносной программой.
Для каждого сценария ответьте:
- какая копия потребуется;
- где она хранится;
- кто имеет доступ;
- сколько данных будет потеряно;
- сколько займёт восстановление;
- как проверить результат.
Копия, которая спасает от случайного удаления файла, может не помочь при потере всего аккаунта.
RPO: сколько данных допустимо потерять
RPO — Recovery Point Objective.
Это допустимый промежуток между последней пригодной копией и моментом аварии.
Представим, магазин копирует базу раз в сутки в 03:00.
Авария произошла в 18:00.
При восстановлении версии на 03:00 будут потеряны:
15 часов заказов
изменений остатков
регистраций
оплат
обращений
Фактический RPO такой схемы может достигать суток.
Примеры RPO
| Проект | Возможный RPO |
|---|---|
| Сайт-визитка | 24 часа |
| Блог с редкими публикациями | 24 часа |
| Корпоративный сайт | 12–24 часа |
| Интернет-магазин | 15–60 минут |
| Активная CRM | несколько минут |
| Платёжная система | близкий к нулю |
Это не универсальные нормативы. Приемлемое значение определяет бизнес.
Если магазин получает один заказ в неделю, суточная копия может быть достаточной.
Если за час проходят сотни оплат, суточный бэкап неприемлем.
RTO: сколько сайт может восстанавливаться
RTO — Recovery Time Objective.
Это приемлемое время от аварии до восстановления работы.
Пример:
RTO = 4 часа
означает, что сайт должен быть возвращён к работе не позднее чем через четыре часа после начала восстановления.
На RTO влияют:
- объём данных;
- скорость копирования;
- доступность специалистов;
- наличие инструкции;
- готовность новой среды;
- размер базы;
- время импорта;
- DNS;
- SSL;
- проверка;
- необходимость синхронизировать новые данные;
- скорость поддержки.
Наличие копии на 500 ГБ мало помогает, если её скачивание и распаковка занимают два дня, а бизнес допускает простой только один час.
RPO и RTO решают разные задачи
RPO
Сколько данных потеряем?
RTO
Как долго не будет работать система?
Пример:
Копия каждые 15 минут
RPO: до 15 минут
Восстановление вручную за 12 часов
RTO: 12 часов
Данные защищены достаточно часто, но сервис долго возвращается к работе.
Обратная ситуация:
Снимок сервера восстанавливается за 10 минут
RTO: 10 минут
Снимок создаётся раз в сутки
RPO: до 24 часов
Сайт быстро запустится, но потеряет почти сутки изменений.
Хорошая стратегия учитывает оба показателя.
Что именно нужно резервировать
Современный сайт состоит не только из папки public_html.
Минимальный состав зависит от архитектуры.
Код приложения
Если код хранится в Git, его можно получить из репозитория.
Но Git не обязательно содержит:
- пользовательские файлы;
.env;- секреты;
- production-конфигурацию;
- сгенерированные документы;
- локальные плагины;
- изменения, внесённые вручную;
- файлы, исключённые через
.gitignore.
Репозиторий полезен, но не является полной резервной копией рабочего сайта.
База данных
В ней могут находиться:
- пользователи;
- заказы;
- товары;
- статьи;
- настройки;
- сессии;
- очереди;
- права;
- формы;
- логи действий;
- CMS-конфигурация.
Для многих динамических сайтов база важнее файлов кода.
Пользовательские загрузки
Например:
public/uploads
storage/app/public
wp-content/uploads
media
documents
avatars
Эти файлы часто не входят в Git и не могут быть восстановлены из исходного кода.
Конфигурация
Проверьте:
.env;- секреты;
- параметры подключения к базе;
- SMTP;
- API-ключи;
- cron;
- настройки доменов;
- Document Root;
- версии PHP;
- расширения;
- правила веб-сервера;
- переменные окружения;
- конфигурацию очереди.
Не храните секреты в открытом виде без защиты, но предусмотрите их восстановление.
Системные настройки
Для VPS:
- nginx или Apache;
- PHP-FPM;
- systemd;
- Supervisor;
- firewall;
- пользователи;
- SSH-ключи;
- cron;
- сертификаты;
- база данных;
- Docker Compose;
- reverse proxy;
- DNS;
- мониторинг.
Лучше хранить конфигурацию как код, но реальные production-параметры всё равно нужно учитывать.
Почта
Если почта находится на том же хостинге, выясните:
- копируются ли ящики;
- сохраняются ли папки;
- копируются ли фильтры;
- можно ли восстановить одно письмо;
- входит ли почта в общий архив;
- сколько хранится история.
DNS
DNS-зона обычно небольшая, но критичная.
Сохраните:
- A;
- AAAA;
- CNAME;
- MX;
- TXT;
- SPF;
- DKIM;
- DMARC;
- SRV;
- CAA;
- записи подтверждения сервисов.
Снимок экрана хуже текстового экспорта: его сложнее быстро применить и проверить.
Внешние сервисы
У сайта могут быть данные вне хостинга:
- объектное хранилище;
- CDN;
- CRM;
- поисковый индекс;
- Redis;
- отдельная база;
- сервис очередей;
- формы;
- почтовый SMTP;
- аналитика.
Уточните, какие данные считаются первичными и как они восстанавливаются.
Что обычно не нужно копировать полностью
Некоторые каталоги можно пересоздать:
vendor
node_modules
кэш
временные файлы
собранные логи
старые сессии
Но решение зависит от процесса восстановления.
vendor
Можно восстановить через:
composer install
если доступны:
composer.json;composer.lock;- нужная версия PHP;
- необходимые расширения;
- репозитории пакетов;
- приватные токены.
Если приватный пакет исчез или доступ потерян, готовый vendor может неожиданно оказаться полезным.
node_modules
Обычно пересоздаётся:
npm ci
Но production-сайту чаще нужны уже собранные файлы:
public/build
public/assets
dist
Если сборка выполнялась только на сервере, их нужно либо копировать, либо документировать воспроизводимую сборку.
Кэш
Обычно создаётся заново.
Но после восстановления холодный кэш может вызвать резкий рост нагрузки. Это нужно учитывать в RTO.
Логи
Для запуска сайта старые логи обычно не требуются.
Но они могут быть необходимы:
- для расследования взлома;
- аудита;
- юридических требований;
- анализа аварии.
Операционный бэкап и архив журналов — разные задачи.
Полная, инкрементальная и дифференциальная копия
Полная
Каждый раз сохраняются все выбранные данные.
Преимущества:
- простое восстановление;
- один понятный набор;
- меньше зависимостей между частями.
Недостатки:
- больше места;
- больше времени;
- выше нагрузка.
Инкрементальная
Сохраняются изменения после предыдущей копии любого типа.
Пример:
Воскресенье — полная
Понедельник — изменения после воскресенья
Вторник — изменения после понедельника
Среда — изменения после вторника
Для восстановления среды среды нужны:
полная копия воскресенья
понедельник
вторник
среда
Преимущество — экономия места и времени.
Недостаток — зависимость от всей цепочки.
Дифференциальная
Сохраняются изменения после последней полной копии.
Воскресенье — полная
Понедельник — изменения после воскресенья
Вторник — все изменения после воскресенья
Среда — все изменения после воскресенья
Для восстановления среды нужны:
полная копия воскресенья
дифференциальная среды
Дифференциальные копии растут к концу периода, но восстановление проще инкрементальной цепочки.
На виртуальном хостинге модель выбирает провайдер.
На VPS её нужно проектировать самостоятельно.
Правило 3-2-1
Практический ориентир:
3 копии данных
2 разных типа носителя или системы хранения
1 копия вне основной площадки
Например:
1. Рабочий сайт на хостинге
2. Автоматическая копия у хостера
3. Зашифрованная копия в независимом хранилище
Важно, чтобы внешняя копия не зависела от:
- того же аккаунта;
- тех же учётных данных;
- того же диска;
- той же панели;
- одного администратора;
- одной платёжной учётной записи.
Если злоумышленник получил root-доступ и может удалить все подключённые резервные хранилища, формальное количество копий не обеспечивает независимость.
Копия у хостера полезна, но не должна быть единственной
Хостинг-провайдер может делать резервные копии лучше большинства владельцев сайтов:
- автоматически;
- на отдельном оборудовании;
- с ротацией;
- с удобным восстановлением;
- без нагрузки на аккаунт;
- с резервированием инфраструктуры.
Но клиенту всё равно нужно знать:
- входит ли бэкап в услугу;
- гарантируется ли его создание;
- что копируется;
- сколько хранятся версии;
- где находятся данные;
- можно ли скачать архив;
- доступен ли бэкап после блокировки аккаунта;
- что происходит после окончания тарифа;
- кто отвечает за проверку восстановления.
Внешняя независимая копия защищает от сценария, в котором сам хостинг или доступ к нему недоступен.
Как это устроено на Siteko. Резервные копии аккаунтов создаются автоматически и хранятся не на самой ноде хостинга, а во внешнем объектном S3-хранилище — поэтому они переживают отказ диска или всего сервера с сайтами. В копию входят файлы сайтов, базы данных и почтовые ящики. Схема хранения двухуровневая: файлы и базы — полная копия раз в неделю плюс ежедневные догоняющие копии, то есть примерно неделя истории с посуточной детализацией; а базы данных дополнительно выгружаются раз в месяц и хранятся полгода — это защищает от медленно обнаруживаемых проблем (порча данных, заражение, ошибочная правка), когда недельной глубины файловых копий уже не хватает. Восстановление — через поддержку; свои копии аккаунта также видны в панели. Но даже при таком резервировании мы, как и сказано выше, советуем держать собственную независимую копию по правилу 3-2-1: копия у хостера удобна, но не должна быть единственной, особенно для интернет-магазина с ценными заказами.
Локальный бэкап внутри аккаунта
Команда:
tar -czf backup.tar.gz .
создаёт архив рядом с сайтом.
Преимущества:
- быстро;
- удобно перед обновлением;
- легко откатить один каталог.
Недостатки:
- занимает диск;
- расходует inode;
- может попасть в следующий бэкап и создать рекурсию;
- доступен вредоносному коду;
- исчезнет вместе с аккаунтом;
- создаёт нагрузку;
- может содержать секреты.
Локальная копия полезна как временная точка отката, но после создания её лучше:
- проверить;
- выгрузить;
- удалить или переместить в защищённое хранилище.
Бэкап базы нельзя заменять копированием её файлов
Для MySQL нельзя просто скопировать рабочий каталог базы обычным cp и считать результат согласованным.
Во время копирования база продолжает изменять:
- таблицы;
- индексы;
- журналы;
- служебные файлы.
Разные части могут попасть в архив в разные моменты.
Надёжные варианты:
- логический дамп;
- специализированное физическое резервирование;
- согласованный snapshot;
- реплика;
- инструменты СУБД.
На виртуальном хостинге обычно используется логический дамп.
MySQL: логический дамп
Пример:
mysqldump \
--single-transaction \
--routines \
--triggers \
--events \
--default-character-set=utf8mb4 \
--databases example_database \
> example_database.sql
Для больших InnoDB-баз --single-transaction позволяет получить согласованное представление без длительной блокировки таблиц, если во время дампа не выполняются несовместимые изменения структуры.
Но флаг не гарантирует идеальный результат для любых таблиц и любых операций.
Проверьте:
- используемый storage engine;
- размер;
- права пользователя;
- routines;
- triggers;
- events;
- views;
- кодировку;
- ошибки команды.
Не делайте вывод об успехе только по наличию файла.
Проверьте код завершения:
if mysqldump \
--single-transaction \
--routines \
--triggers \
--events \
example_database \
> example_database.sql
then
echo "Дамп создан"
else
echo "Ошибка дампа" >&2
exit 1
fi
Пароль базы не следует писать прямо в команде
Плохой вариант:
mysqldump -u user -pMySecretPassword database
Пароль может попасть:
- в историю shell;
- в список процессов;
- в журнал автоматизации;
- в письмо cron;
- в скриншот.
Используйте:
- защищённый конфигурационный файл клиента;
- переменные окружения с осторожностью;
- секреты CI;
- механизм хостинг-панели;
- запрос пароля при ручном запуске.
Пример защищённого файла:
[client]
user=backup_user
password=strong-password
host=localhost
Права:
chmod 600 ~/.my.cnf
После этого:
mysqldump \
--single-transaction \
example_database \
> example_database.sql
Отдельному backup-пользователю выдавайте только необходимые права.
Проверка дампа MySQL
Минимально:
test -s example_database.sql
Команда подтверждает, что файл не пустой, но не доказывает его пригодность.
Посмотрите начало:
head -n 30 example_database.sql
И окончание:
tail -n 30 example_database.sql
Проверьте, что команда завершилась успешно.
Настоящая проверка — импорт в отдельную базу:
mysql test_restore_database \
< example_database.sql
После импорта:
- проверить таблицы;
- сравнить ключевые количества;
- запустить приложение;
- выполнить smoke tests.
PostgreSQL: логический дамп
Формат custom удобен для pg_restore:
pg_dump \
--format=custom \
--file=example_database.dump \
example_database
Проверить содержимое:
pg_restore \
--list \
example_database.dump \
> example_database.contents.txt
Восстановление в тестовую базу:
createdb example_restore_test
pg_restore \
--dbname=example_restore_test \
--clean \
--if-exists \
example_database.dump
С осторожностью используйте --clean: он удаляет существующие объекты в целевой базе.
Никогда не проверяйте восстановление на production-базе.
Связь файлов и базы
Даже исправные отдельные копии файлов и базы могут не соответствовать друг другу.
Пример:
- В 03:00 началось архивирование файлов.
- В 03:10 пользователь загрузил изображение.
- В 03:11 запись об изображении попала в базу.
- В 03:20 начался дамп базы.
- Архив файлов уже сохранил состояние до загрузки.
После восстановления база содержит путь к изображению, которого нет в архиве.
Обратная ситуация:
- файл существует;
- запись о нём в базе ещё не попала в дамп.
Для обычного сайта такое расхождение может быть терпимым.
Для магазина, файлового сервиса или системы документов — критичным.
Как получить согласованную точку
Варианты:
Режим обслуживания
На короткое время запрещаются изменения:
сайт доступен только для чтения
или показывает maintenance page
Затем создаются дамп и архив.
Преимущество — простая согласованность.
Недостаток — простой.
Snapshot
Согласованный снимок файловой системы создаётся быстро, после чего данные копируются из него.
Для базы может потребоваться дополнительная координация.
Журнал изменений
После основной копии сохраняются изменения:
- binary logs;
- WAL;
- события;
- object versioning.
Это позволяет приблизиться к малому RPO.
Архитектурное разделение
Пользовательские файлы хранятся в версионируемом объектном хранилище, а база резервируется отдельно.
Главное — понимать допустимый уровень расхождения и проверять восстановление системы целиком.
Резервирование во время деплоя
Перед миграцией базы часто создают копию.
Это полезно, но нельзя полностью полагаться на автоматическую команду вида:
mysqldump database > backup.sql
php artisan migrate --force
Если mysqldump завершился ошибкой, а скрипт не проверил код возврата, миграции всё равно запустятся.
Безопаснее:
set -Eeuo pipefail
mysqldump \
--single-transaction \
example_database \
> backup-before-migrate.sql
test -s backup-before-migrate.sql
php artisan migrate --force
Но даже это не заменяет проверку дампа и внешнюю копию.
Преддеплойный бэкап — дополнительная точка отката, а не вся стратегия резервирования.
Пример скрипта резервного копирования
Упрощённый пример для PHP-проекта и MySQL:
#!/usr/bin/env bash
set -Eeuo pipefail
PROJECT_DIR="/home/user/www/example.com/project"
BACKUP_DIR="/home/user/backups/example.com"
DATABASE="example_database"
TIMESTAMP="$(date -u +'%Y-%m-%dT%H-%M-%SZ')"
WORK_DIR="$BACKUP_DIR/.tmp-$TIMESTAMP"
FINAL_DIR="$BACKUP_DIR/$TIMESTAMP"
cleanup() {
rm -rf "$WORK_DIR"
}
trap cleanup EXIT
umask 077
mkdir -p "$WORK_DIR"
mkdir -p "$BACKUP_DIR"
echo "Creating database dump..."
mysqldump \
--single-transaction \
--routines \
--triggers \
--events \
"$DATABASE" \
> "$WORK_DIR/database.sql"
test -s "$WORK_DIR/database.sql"
echo "Creating files archive..."
tar \
--create \
--gzip \
--file="$WORK_DIR/files.tar.gz" \
--directory="$PROJECT_DIR" \
--exclude="./storage/framework/cache/*" \
--exclude="./storage/logs/*" \
--exclude="./node_modules" \
.
test -s "$WORK_DIR/files.tar.gz"
echo "Creating checksums..."
(
cd "$WORK_DIR"
sha256sum \
database.sql \
files.tar.gz \
> SHA256SUMS
)
mv "$WORK_DIR" "$FINAL_DIR"
trap - EXIT
echo "Backup created: $FINAL_DIR"
Этот пример ещё не решает:
- внешнюю отправку;
- шифрование;
- ротацию;
- уведомления;
- проверочное восстановление;
- согласование файлов и базы;
- хранение секретов;
- блокировку повторного запуска.
Но он важным образом отличается от команды без контроля:
- останавливается при ошибке;
- проверяет непустые файлы;
- не публикует незавершённый каталог как готовый;
- создаёт контрольные суммы;
- ограничивает права новых файлов.
Не храните рабочую копию в каталоге сайта
Плохо:
public/backup.zip
public/database.sql
public/site-old.tar.gz
Такой файл может стать доступен по адресу:
https://example.com/database.sql
Последствия:
- утечка пользователей;
- пароли и хэши;
- настройки;
- персональные данные;
- API-ключи;
- исходный код;
- внутренняя структура.
Храните резервные копии вне Document Root:
/home/user/backups
или во внешнем хранилище.
После тестового создания проверьте, что архив не открывается через браузер.
Шифрование резервных копий
Бэкап может содержать больше чувствительных данных, чем сам публичный сайт:
- полную базу пользователей;
- историю заказов;
- адреса;
- токены;
- конфигурацию;
- почту;
- закрытые документы.
Если копия хранится у внешнего провайдера или передаётся по сети, рассмотрите шифрование.
Пример с age:
age \
--recipient age1examplepublickey... \
--output backup.tar.gz.age \
backup.tar.gz
Расшифрование:
age \
--decrypt \
--identity backup-key.txt \
--output backup.tar.gz \
backup.tar.gz.age
Закрытый ключ не должен находиться только:
- на резервируемом сервере;
- в том же аккаунте;
- внутри зашифрованного архива;
- у одного недоступного сотрудника.
Иначе в момент аварии данные будут сохранены, но недоступны.
Ключ шифрования тоже нужно резервировать
Для ключей нужен отдельный план:
- кто ими владеет;
- где они хранятся;
- есть ли защищённая копия;
- кто может использовать их при аварии;
- что происходит после увольнения сотрудника;
- как выполняется ротация;
- есть ли инструкция.
Пароль, записанный только в менеджере паролей человека, который покинул компанию, превращает исправный архив в бесполезный набор байтов.
Контрольные суммы
Контрольная сумма помогает обнаружить изменение файла после создания.
Пример:
sha256sum \
database.sql \
files.tar.gz \
> SHA256SUMS
Проверка:
sha256sum \
--check \
SHA256SUMS
Успешный результат:
database.sql: OK
files.tar.gz: OK
Контрольная сумма подтверждает, что файл не изменился относительно зафиксированного значения.
Она не доказывает, что:
- исходный дамп был логически корректен;
- в архив вошли все данные;
- база восстановится;
- приложение запустится;
- выбран правильный день.
Для этого нужен restore test.
Проверка архива без восстановления
Для gzip:
gzip \
--test \
files.tar.gz
Посмотреть список:
tar \
--list \
--file=files.tar.gz |
head
Проверить ZIP:
unzip \
-t \
backup.zip
Это обнаружит часть повреждений структуры архива, но не проверит работу сайта.
Мониторинг размера копии
Слишком маленький бэкап часто означает ошибку.
Обычный дамп базы:
2,4 ГБ
Сегодня:
12 КБ
Возможно:
- дамп содержит только заголовок;
- нет прав;
- выбрана пустая база;
- команда завершилась ошибкой;
- приложение подключено к другому серверу.
Слишком большой рост тоже подозрителен:
вчера: 4 ГБ
сегодня: 80 ГБ
Возможные причины:
- архив попал внутрь следующего архива;
- разрослись логи;
- созданы временные файлы;
- заражение;
- резервируются старые копии;
- неожиданно выросла почта.
Автоматизация должна проверять не только факт создания файла, но и разумность его размера.
Бэкап может рекурсивно копировать сам себя
Структура:
project/
├── public/
├── storage/
└── backups/
└── backup-1.tar.gz
Команда:
tar -czf backups/backup-2.tar.gz .
может включить backup-1.tar.gz в новый архив.
На следующий день новый архив включает уже две копии.
Размер растёт лавинообразно.
Каталог резервных копий должен находиться:
- вне резервируемого дерева;
- либо явно исключаться.
Ротация: сколько версий хранить
Одна последняя копия не защищает от ошибки, обнаруженной поздно.
Пример:
- Сайт взломали 20 дней назад.
- Вредоносный код не проявлялся.
- Ежедневная система хранит только 7 дней.
- Все доступные копии уже заражены.
Нужна история разных возрастов.
Возможная схема:
ежечасные — 24 часа
ежедневные — 14 дней
еженедельные — 8 недель
ежемесячные — 12 месяцев
Не копируйте эту схему бездумно. Сроки зависят от:
- RPO;
- скорости обнаружения ошибок;
- объёма;
- законодательства;
- стоимости хранения;
- характера данных.
Но хранение нескольких поколений защищает от медленно обнаруживаемых проблем.
Слишком долгая история тоже создаёт риски
Копии содержат персональные данные.
Бесконечное хранение может противоречить:
- внутренней политике;
- договору;
- требованиям удаления данных;
- законодательству;
- принципу минимизации.
Нужно определить:
- срок хранения;
- порядок удаления;
- доступ;
- шифрование;
- журнал восстановления;
- правила уничтожения носителей.
Резервная копия не должна становиться бесконтрольным архивом всех данных компании за десять лет.
Неизменяемые копии
Если вредоносный код может удалить или зашифровать бэкап, защита недостаточна.
Полезные механизмы:
- object lock;
- immutable storage;
- write-once retention;
- отдельные учётные данные;
- запрет удаления в течение срока;
- изолированная учётная запись;
- offline-копия.
Но неизменяемость нужно настраивать осторожно: ошибка политики может привести к невозможности удалить огромный объём ненужных данных до окончания retention.
Доступ к резервным копиям должен отличаться от доступа к сайту
Плохая схема:
один логин
один пароль
одна панель
сайт
база
резервное хранилище
Компрометация одной учётной записи открывает всё.
Лучше:
- отдельный аккаунт хранилища;
- отдельный ключ только на запись;
- MFA;
- ограниченные права;
- запрет удаления для backup-процесса;
- отдельный доступ для восстановления;
- аудит действий.
Серверу, который создаёт копии, не всегда нужно право удалять старые версии во внешнем хранилище.
Ротацию может выполнять отдельная защищённая система.
Уведомление об успехе недостаточно
Сообщение:
Backup job completed
может означать только, что скрипт дошёл до последней строки.
Нужно контролировать:
- код завершения;
- существование файлов;
- размер;
- контрольную сумму;
- возраст последней копии;
- отправку во внешнее хранилище;
- доступность хранилища;
- количество версий;
- результат проверочного восстановления.
Полезнее тревога:
Последняя успешно проверенная копия базы:
36 часов назад
Допустимый RPO:
1 час
чем зелёная отметка, основанная на запуске cron.
Проверочное восстановление
Это основная проверка стратегии.
Не нужно ждать аварии.
Создайте отдельную среду:
restore-test.example.net
или локальную/изолированную машину.
Порядок:
- Выбрать случайную копию.
- Проверить контрольные суммы.
- Расшифровать архив.
- Развернуть чистую среду.
- Восстановить файлы.
- Создать пустую базу.
- Импортировать дамп.
- Восстановить конфигурацию.
- Настроить домен или локальный hosts.
- Запустить приложение.
- Выполнить функциональные проверки.
- Измерить время.
- Зафиксировать ошибки.
- Обновить инструкцию.
Копия считается проверенной не после успешной распаковки, а после успешного запуска нужной функции сайта.
Что проверить после восстановления
Общая доступность
Главная страница открывается.
HTTPS работает.
Нет ошибки 500.
Авторизация
Администратор может войти.
Обычный пользователь может войти.
Восстановление пароля работает.
База
Есть таблицы.
Есть свежие записи.
Совпадают ключевые количества.
Миграции находятся в ожидаемом состоянии.
Файлы
Изображения открываются.
Пользовательские документы доступны.
Символические ссылки созданы.
Права runtime-каталогов правильные.
Критические функции
Для магазина:
каталог
корзина
тестовый заказ
почтовое уведомление
интеграции в безопасном режиме
Для CRM:
клиенты
задачи
поиск
история
права
Безопасность
В тестовой среде отключите:
- реальные платежи;
- production SMTP;
- webhooks;
- SMS;
- внешние изменения;
- фоновые задания, которые могут повлиять на клиентов.
Сверка ключевых данных
Необязательно вручную просматривать каждую запись.
Создайте набор контрольных показателей:
Количество пользователей:
128 420
Количество оплаченных заказов:
51 903
Дата последнего заказа:
2026-07-25 14:28
Количество товаров:
18 442
Количество пользовательских файлов:
96 217
После восстановления сравните их с ожидаемой точкой.
Можно автоматически сохранять метаданные рядом с копией:
{
"created_at": "2026-07-25T14:30:00Z",
"git_commit": "a1b2c3d",
"database": "example_database",
"users_count": 128420,
"orders_count": 51903,
"last_order_at": "2026-07-25T14:28:11Z",
"files_archive_sha256": "...",
"database_sha256": "..."
}
Не сохраняйте в метаданных секреты и персональные записи.
Проверяйте не только последнюю копию
Последняя копия может быть исправной, а старые — нет.
Периодически выбирайте:
- последнюю;
- случайную дневную;
- недельную;
- месячную.
Так проверяется вся цепочка хранения и ротации.
Для инкрементальных копий особенно важно тестировать восстановление из полной цепочки.
Измеряйте реальное время восстановления
Теоретическое:
Скачать архив — 15 минут.
Импортировать базу — 20 минут.
Итого — 35 минут.
Фактическое:
Получить доступы — 40 минут.
Найти ключ — 30 минут.
Скачать архив — 20 минут.
Исправить права — 45 минут.
Установить расширение — 30 минут.
Импортировать базу — 50 минут.
Найти неверный Document Root — 25 минут.
Проверить сайт — 40 минут.
Итого — почти пять часов.
RTO измеряется всей процедурой, а не скоростью распаковки.
Инструкция восстановления
Хорошая инструкция отвечает:
Где хранятся копии?
Как получить доступ?
Какой ключ нужен?
Как выбрать нужную дату?
Какие версии PHP и базы требуются?
Как создать базу?
Как импортировать дамп?
Какие каталоги должны быть writable?
Где взять .env?
Как настроить Document Root?
Какие cron-задачи нужны?
Какие процессы нужно запустить?
Как проверить результат?
Кто принимает решение о переключении?
Команды должны быть готовыми к применению с понятными переменными, а не состоять из фразы:
Развернуть сайт обычным способом.
Инструкция хранится отдельно от основного сервера.
Runbook должен учитывать отсутствие автора
Проверьте:
Сможет ли другой специалист восстановить сайт по этой инструкции, не звоня разработчику?
Если нет, инструкция неполна.
Полезно проводить учебное восстановление человеком, который не создавал бэкап.
Так обнаруживаются скрытые знания:
- нестандартный путь;
- забытый пароль;
- ручная правка;
- неизвестный плагин;
- внешняя зависимость;
- нужная версия PHP;
- отсутствующая лицензия.
Laravel: что резервировать
Минимально:
база данных
.env или защищённый эквивалент
storage/app
storage/app/public
пользовательские файлы
composer.json
composer.lock
код или Git-репозиторий
cron-конфигурация
очереди и внешние сервисы
Обычно можно пересоздать:
vendor
bootstrap/cache
storage/framework/cache
storage/framework/views
Но после восстановления понадобятся:
composer install \
--no-dev \
--prefer-dist \
--optimize-autoloader \
--no-interaction
php artisan optimize:clear
php artisan storage:link
php artisan optimize
Нужно также восстановить права на:
storage
bootstrap/cache
Если очередь содержит важные незавершённые задания, решите заранее:
- нужно ли их резервировать;
- можно ли безопасно повторить;
- не приведёт ли восстановление старой очереди к повторной оплате или отправке письма.
Symfony: что резервировать
Минимально:
база
.env.local или production secrets
пользовательские файлы
composer.lock
код
конфигурация cron и Messenger
внешние параметры
После восстановления:
composer install \
--no-dev \
--prefer-dist \
--optimize-autoloader \
--no-interaction
APP_ENV=prod APP_DEBUG=0 \
php bin/console cache:clear
Проверьте runtime-каталоги:
var/cache
var/log
И настройки Messenger, если используются очереди.
WordPress: что резервировать
Минимально:
база данных
wp-content/uploads
wp-content/plugins
wp-content/themes
wp-config.php
нестандартные файлы
правила веб-сервера
Ядро WordPress можно скачать заново, но в реальном проекте могли существовать:
- ручные изменения;
- старые версии;
- mu-plugins;
- премиальные плагины;
- приватные темы;
- лицензии;
- файлы вне стандартных каталогов.
Проверочное восстановление покажет, действительно ли достаточно базы и wp-content.
Почта и сайт могут восстанавливаться отдельно
Если почта обслуживается другим провайдером, авария сайта может её не затронуть.
Если всё находится в одном аккаунте, нужно определить:
- копируются ли ящики;
- как восстановить сообщения;
- сохраняются ли пароли;
- как избежать повторной доставки;
- что будет с письмами, пришедшими во время восстановления.
Для критичной корпоративной почты отдельная специализированная услуга часто упрощает независимость от сайта.
Бэкап VPS
На VPS нужно резервировать не только /var/www.
Проверьте:
/etc/nginx
/etc/apache2
/etc/php
/etc/systemd
/etc/supervisor
/etc/cron*
/etc/letsencrypt
/home
/var/lib
Docker volumes
базы данных
секреты
SSH-конфигурацию
firewall
Но полное копирование всей файловой системы не всегда является лучшим способом.
Современная стратегия часто сочетает:
- инфраструктуру как код;
- репозиторий;
- образы;
- дампы данных;
- резервирование volumes;
- снимки;
- документацию.
Цель — воспроизводимая среда, а не архив каждого временного файла Linux.
Снимок VPS перед обновлением
Snapshot удобен перед:
- обновлением ОС;
- изменением конфигурации;
- крупным деплоем;
- миграцией базы.
Но учтите:
- снимок может кратковременно приостановить операции;
- база может требовать согласования;
- snapshot находится у того же провайдера;
- хранение оплачивается;
- старые снимки нужно удалять;
- откат возвращает весь диск, включая изменения пользователей.
Не откатывайте магазин целиком к старому snapshot после нескольких часов новых заказов без плана сохранения свежих данных.
Точечное восстановление
Не каждая авария требует возврата всего сайта.
Пользователь мог удалить:
- одну статью;
- одну таблицу;
- один файл;
- один почтовый ящик;
- одну настройку.
Полезная система позволяет:
- скачать архив;
- восстановить отдельный файл;
- импортировать отдельную таблицу;
- поднять копию в тестовой среде;
- извлечь нужную запись;
- сравнить версии.
Полный откат сайта ради одной картинки может уничтожить новые заказы и изменения.
Point-in-time recovery
Для систем с малым RPO одного ежедневного дампа недостаточно.
База может сохранять журнал изменений:
- MySQL binary log;
- PostgreSQL WAL.
Схема:
полная копия в 03:00
+
журнал изменений
до 14:27
позволяет восстановить состояние ближе к конкретному моменту.
Это сложнее обычного дампа и требует:
- достаточного хранения журналов;
- непрерывного контроля;
- согласованной полной копии;
- документированной процедуры;
- регулярных тестов.
Point-in-time recovery особенно полезно, когда нужно вернуть базу к моменту до ошибочной команды:
DELETE FROM orders;
но не потерять все изменения с предыдущего дня.
Восстановление после взлома — не просто откат
Если сайт взломали, неизвестно, когда именно злоумышленник получил доступ.
Последняя копия тоже может содержать:
- web shell;
- изменённый плагин;
- нового администратора;
- вредоносный cron;
- утёкший ключ;
- изменённую конфигурацию.
Правильное восстановление включает:
- Определить вероятное время компрометации.
- Выбрать более раннюю чистую копию.
- Обновить уязвимое ПО.
- Сменить пароли и ключи.
- Проверить пользователей.
- Удалить вредоносные задания.
- Проверить логи.
- Восстановить данные, созданные после выбранной точки.
- Закрыть исходную уязвимость.
- Усилить мониторинг.
Просто вернуть вчерашний архив на тот же уязвимый сайт — значит позволить атаке повториться.
Восстановление после неудачной миграции
Сценарий:
код обновлён
миграция изменила базу
новый код не работает
Возврат старого Git-коммита может не помочь, потому что структура базы уже новая.
Нужны:
- совместимые миграции;
- резервная копия базы;
- стратегия отката;
- понимание потери новых данных;
- maintenance mode;
- тест на копии.
Перед destructive migration задайте вопрос:
Как будет возвращена предыдущая версия, если миграция завершится только наполовину?
Автоматический бэкап без журналов
Скрипт запускается cron:
0 3 * * * /home/user/bin/backup.sh
Но вывод отправляется в никуда:
0 3 * * * /home/user/bin/backup.sh >/dev/null 2>&1
Если команда начала падать месяц назад, никто этого не заметит.
Лучше:
- сохранять журнал;
- отправлять уведомление при ошибке;
- контролировать возраст последней копии;
- использовать внешний мониторинг cron;
- проверять код завершения.
Не отправляйте ежедневное сообщение «всё хорошо», которое через неделю перестанут читать.
Предпочтительнее молчать при нормальной работе и немедленно уведомлять об отклонении.
Минимальные автоматические проверки
После создания копии:
Команда завершилась с кодом 0?
Файлы существуют?
Они не пустые?
Размер находится в ожидаемом диапазоне?
Контрольная сумма создана?
Копия выгружена во внешнее хранилище?
Объект доступен для чтения?
Срок последней проверенной копии не превышен?
Периодически:
Архив распаковывается?
Дамп импортируется?
Приложение запускается?
Ключевые данные присутствуют?
RTO укладывается в план?
Вопросы хостинг-провайдеру
О составе
- Копируются ли файлы?
- Копируются ли базы?
- Копируется ли почта?
- Копируются ли DNS и настройки сайта?
- Входят ли пользовательские cron-задачи?
- Есть ли исключённые каталоги?
О частоте
- Как часто создаётся копия?
- В какое время?
- Каков максимальный RPO?
- Есть ли более частые копии базы?
О хранении
- Сколько версий доступно?
- Где они находятся?
- Используется ли отдельное оборудование?
- Есть ли копия вне основной площадки?
- Входят ли бэкапы в дисковую квоту?
О восстановлении
- Можно ли восстановить самостоятельно?
- Можно ли вернуть один файл?
- Можно ли восстановить только базу?
- Сколько занимает полный restore?
- Платное ли восстановление?
- Как подтверждается успешность?
О прекращении услуги
- Что происходит после неоплаты?
- Сколько хранятся данные?
- Можно ли скачать копию после блокировки?
- Как удалить все резервные версии?
О безопасности
- Шифруются ли данные?
- Кто имеет доступ?
- Есть ли журнал операций?
- Защищены ли копии от удаления злоумышленником?
Пошаговая проверка существующего бэкапа
Шаг 1. Найдите последнюю копию
Зафиксируйте:
дата
время
размер
состав
место хранения
Шаг 2. Убедитесь, что она независима
Спросите:
Переживёт ли копия удаление всего хостинг-аккаунта?
Шаг 3. Проверьте целостность
sha256sum --check SHA256SUMS
gzip --test files.tar.gz
tar --list --file=files.tar.gz >/dev/null
Шаг 4. Проверьте базу
Импортируйте дамп в отдельную тестовую базу.
Шаг 5. Проверьте секреты
Убедитесь, что доступен:
.env
ключ шифрования
пароли
токены
DNS
SMTP
Не раскрывайте их в тестовых журналах.
Шаг 6. Разверните сайт в изолированной среде
Не поверх production.
Шаг 7. Выполните smoke tests
Проверьте критичные функции.
Шаг 8. Измерьте RTO
Запишите фактическое время каждого этапа.
Шаг 9. Сравните с RPO
Определите дату последней записи в базе и пользовательского файла.
Шаг 10. Исправьте процесс
Обновите:
- расписание;
- состав;
- ротацию;
- инструкцию;
- мониторинг;
- права;
- шифрование.
Таблица: симптом, причина и действие
| Симптом | Вероятная причина | Следующее действие |
|---|---|---|
| Архив существует, база пустая | Дамп завершился ошибкой | Проверять код и размер |
| База есть, изображения отсутствуют | Не копировались uploads | Добавить пользовательские файлы |
| Архив не распаковывается | Повреждение или обрыв передачи | Контрольные суммы и повтор |
| Копия удалена вместе с сайтом | Хранилась в том же аккаунте | Внешнее независимое хранилище |
| Все копии заражены | Слишком короткая история | Увеличить retention |
| Восстановление требует неизвестный пароль | Нет управления ключами | Резервировать ключ отдельно |
| Git есть, данные потеряны | Репозиторий не содержит базу и uploads | Полный состав бэкапа |
| Snapshot откатил новые заказы | Восстановлен весь диск | Точечная стратегия |
| Бэкап создаётся, но никто не проверяет | Ошибочная автоматизация | Регулярный restore test |
| Размер архива резко вырос | В копию попали старые бэкапы | Исключить каталог |
| Размер дампа резко уменьшился | Выбрана пустая база или нет прав | Проверить конфигурацию |
| Восстановление длится сутки | RTO не учитывался | Автоматизация и готовая среда |
Код работает, .env потерян |
Секреты не резервировались | Защищённое хранилище конфигурации |
| База и файлы не совпадают | Копировались в разные моменты | Согласованная точка |
| Почта пропала после аварии | Ящики не входили в копию | Отдельная почтовая стратегия |
| Бэкап нельзя скачать после блокировки | Зависимость от одного аккаунта | Независимая копия |
| Последняя копия слишком старая | Не контролировался RPO | Мониторинг возраста |
| В тестовой копии ушли письма клиентам | Production SMTP не отключён | Безопасный restore environment |
Грабли резервного копирования
| Грабля | Результат | Как избежать |
|---|---|---|
| Считать наличие файла успехом | Архив оказывается непригодным | Проверочное восстановление |
| Хранить копию рядом с сайтом | Она теряется при той же аварии | Внешнее хранилище |
| Копировать только код | Теряются база и uploads | Инвентаризация данных |
| Считать Git бэкапом | Нет production-данных | Резервировать состояние |
| Не проверять код завершения | Пустой файл считается копией | set -e и проверки |
| Не следить за размером | Ошибка обнаруживается поздно | Контроль диапазонов |
| Хранить один последний бэкап | Поздно найденная ошибка уже в нём | Ротация поколений |
| Хранить всё навсегда | Растут расходы и риски данных | Политика retention |
| Не шифровать архивы | Утечка полной базы | Шифрование и контроль доступа |
| Хранить ключ только на сервере | После аварии архив не расшифровать | Независимая копия ключа |
| Включать бэкап в следующий бэкап | Размер растёт рекурсивно | Отдельный каталог |
Копировать файлы рабочей базы через cp |
Несогласованное состояние | Инструменты СУБД |
| Проверять restore на production | Риск уничтожить рабочие данные | Изолированная среда |
| Не измерять RTO | Восстановление слишком долгое | Учебные аварии |
| Не документировать процесс | Всё зависит от одного человека | Runbook |
| Не отключать внешние интеграции в тесте | Уходят реальные письма и платежи | Безопасный режим |
| Полагаться только на snapshot | Нет истории и независимости | Сочетать методы |
| Не менять доступ после взлома | Восстановленный сайт взламывают снова | Ротация секретов |
Что приложить к обращению в поддержку
Плохое сообщение:
Восстановите сайт как-нибудь.
Полезное:
Домен:
example.com
Нужная точка восстановления:
25 июля 2026, не позднее 13:00
Причина:
неудачная миграция базы в 13:17
Нужно восстановить:
только MySQL-базу example_database
Файлы сайта откатывать нельзя:
после 13:00 был загружен новый релиз,
который совместим со старой схемой.
Последний известный исправный заказ:
ID 51903
время 12:54
Новые заказы после 13:00:
сохранены отдельно и будут перенесены вручную.
Прошу уточнить:
какие точки восстановления базы доступны,
сколько займёт импорт,
будет ли сайт недоступен.
Для проверки бэкапа:
В панели отображается ежедневная копия.
Нужно уточнить:
— входят ли MySQL-базы;
— входит ли почта;
— где физически хранится копия;
— можно ли скачать её отдельно;
— сколько хранятся версии;
— можно ли выполнить тестовое восстановление
в отдельный каталог и отдельную базу.
Не просите выполнить полный откат, если достаточно одного файла или таблицы.
Минимальный чек-лист резервного копирования
Требования
Какой RPO?
Какой RTO?
Какие аварии рассматриваются?
Состав
Код?
База?
Uploads?
Конфигурация?
Секреты?
Почта?
DNS?
Cron?
Внешние сервисы?
Хранение
Сколько копий?
На скольких системах?
Есть ли внешняя площадка?
Можно ли удалить всё одним доступом?
Безопасность
Шифрование?
Где ключ?
MFA?
Раздельные права?
Неизменяемость?
Контроль
Проверяется код завершения?
Проверяется размер?
Есть контрольные суммы?
Есть уведомления об ошибке?
Контролируется возраст последней копии?
Восстановление
Есть инструкция?
Есть отдельная среда?
Когда проводился последний restore test?
Каков фактический RTO?
Проверены ли ключевые функции?
Ротация
Сколько дневных копий?
Сколько недельных?
Сколько месячных?
Когда они удаляются?
Что в итоге
Резервная копия — не архив и не зелёная отметка в панели.
Это работающий процесс:
определить RPO и RTO
↓
найти все важные данные
↓
создать согласованную копию
↓
сохранить её независимо
↓
защитить от удаления и утечки
↓
проверить целостность
↓
восстановить в тестовой среде
↓
проверить функции сайта
↓
измерить время
↓
повторять регулярно
Копируйте не только код, но и базу, пользовательские файлы, конфигурацию, секреты и связанные сервисы.
Не храните единственную копию внутри того же аккаунта.
Не считайте snapshot полноценной заменой истории.
Не доверяйте сообщению об успешном запуске задания без проверки результата.
И главное:
Бэкап, который никогда не восстанавливали, — это предположение, а не гарантия.
Следующая задача после создания надёжных копий — перенести сайт на другой хостинг так, чтобы не потерять данные.
Файлы можно скопировать заранее. Но база продолжает меняться, покупатели оформляют заказы, почта поступает на старый сервер, DNS-кэши обновляются не одновременно, а часть пользователей ещё некоторое время видит прежний IP.
В следующей части разберём переезд сайта без потери заказов, писем и пользовательских данных.
- 1 Как выбрать хостинг для сайта и не купить себе вторую работу
- 2 Виртуальный хостинг, VPS или облако: что действительно нужно вашему сайту
- 3 Гигабайты ничего не решают: как читать характеристики тарифа хостинга
- 4 «Безлимитный» хостинг: что заканчивается раньше дискового пространства
- 5 Домен подключён, а сайт не открывается: DNS без мистики
- 6 HTTPS включён, а браузер всё равно ругается: SSL без паники
- 7 Письма с сайта пропадают: SMTP, SPF, DKIM и DMARC на пальцах
- 8 Современный PHP-хостинг: зачем Laravel и Symfony нужны SSH, Composer, Node.js, cron и отдельная public-директория
- 9 Деплой без FTP на виртуальном хостинге: Git, Composer и безопасный откат
- 10 Ошибка 500 после загрузки сайта: где искать причину до обращения в поддержку
- 11 Сайт тормозит на хостинге: виноват тариф, код, база или внешний сервис
- 12 Бэкап есть — восстановить нельзя: проверяем резервные копии до аварии вы здесь
- 13 Переезд на другой хостинг без потери сайта, писем и заказов скоро
- 14 Когда виртуальный хостинг стал тесен: пора на VPS или ещё можно остаться скоро
Была статья полезной: