Зачем «просто бэкап» почти всегда не работает
В админке часто звучит: «у нас есть бэкапы». На практике это может означать что угодно — от копии файлов раз в месяц до набора архивов, которые никто никогда не пробовал восстановить.
Проблема в том, что резервное копирование — это не действие, а процесс: собрать данные, проверить их целостность, убедиться, что их реально можно восстановить, и управлять хранением (retention), чтобы бэкапы не съели диск и при этом закрывали ваши RPO/RTO.
Ниже соберём базовую, но «взрослую» схему для типичного сайта: файлы проекта плюс база данных. Опираться будем на привычные инструменты: mysqldump, pg_dump, tar, контрольные суммы (checksums), автоматизацию через cron, а также обязательные процедуры backup verification и restore test.
Базовая модель: что именно бэкапим (и что не надо)
Для большинства сайтов достаточно двух компонентов:
- Файлы сайта: код, статика, пользовательские загрузки (uploads), конфиги приложения (без секретов в открытом виде), иногда cron-скрипты и вспомогательные файлы.
- База данных: MySQL/MariaDB или PostgreSQL.
Частая ошибка — бэкапить «всё подряд» из домашнего каталога, включая кэши, временные файлы, сессии, node_modules/vendor, логи за годы и так далее. Это увеличивает размер, время архивации, нагрузку и усложняет восстановление. Лучше осознанно исключать то, что можно пересоздать.
Ориентир простой: в бэкап должны попадать только данные, которые либо уникальны, либо их пересоздание занимает неприемлемое время или деньги.
Минимально полезное правило: «файлы + дамп БД + проверка + тест восстановления». Дальше вы наращиваете зрелость процесса под свои требования.
Если сайт крутится на виртуальном хостинге, часто удобно держать бэкапы в отдельной директории пользователя (вне DocumentRoot) и периодически забирать их в другое место. На VDS обычно проще выстроить полный цикл: права, расписания, мониторинг места и тестовые восстановления.

Каталог для бэкапов и права
Начните с места хранения. Хороший старт — отдельная директория, недоступная из веба: например, /var/backups или каталог в домашней директории пользователя, но не внутри DocumentRoot.
Пример структуры:
/var/backups/site1/
daily/
weekly/
logs/
tmp/
Минимальные требования к безопасности и удобству:
- только владелец (root или отдельный backup-пользователь) имеет доступ на чтение/запись;
- веб-сервер не должен иметь прав на чтение бэкапов;
- в логах и скриптах не храните пароли в открытом виде.
Дамп MySQL/MariaDB через mysqldump (надёжный «по умолчанию»)
mysqldump остаётся универсальным способом получить логический бэкап. Он медленнее физических решений, но удобен переносимостью и простотой. Для живого сайта критично, чтобы дамп был консистентным.
Рекомендуемые флаги mysqldump
--single-transaction— консистентный снимок для InnoDB без блокировок на запись.--quick— стриминг строк, меньше потребление RAM.--routines,--triggers,--events— процедуры/триггеры/события (их часто забывают).--set-gtid-purged=OFF— помогает избежать сюрпризов при восстановлении в окружениях без GTID.
Пример команды (учётные данные лучше хранить в конфиге клиента, см. ниже):
mysqldump --single-transaction --quick --routines --triggers --events --set-gtid-purged=OFF --databases dbname > /var/backups/site1/tmp/dbname.sql
Если хотите сразу сжимать поток (экономия места и I/O):
mysqldump --single-transaction --quick --routines --triggers --events --set-gtid-purged=OFF --databases dbname | gzip -1 > /var/backups/site1/tmp/dbname.sql.gz
Как не светить пароль в командах
Не передавайте пароль в аргументах командной строки: его видно в ps, он может попасть в историю. Простой вариант — файл ~/.my.cnf с правами 600:
[client]
user=backupuser
password=strong_password
host=localhost
Тогда mysqldump можно вызывать без -u/-p (или только с -u при необходимости).
Если у вас репликация, GTID и вы хотите нарастить «взрослость» бэкапа до PITR, пригодится отдельная схема с binlog. См. материал: PITR для MySQL/MariaDB: binlog и восстановление.
Дамп PostgreSQL через pg_dump
Для PostgreSQL стандарт — pg_dump. Если база небольшая, можно делать plain SQL. Для более надёжной и быстрой загрузки часто выбирают «custom format» (под pg_restore).
Plain SQL
pg_dump -d dbname -f /var/backups/site1/tmp/dbname.sql
Со сжатием:
pg_dump -d dbname | gzip -1 > /var/backups/site1/tmp/dbname.sql.gz
Custom format (удобно для регулярных восстановлений)
pg_dump -d dbname -F c -f /var/backups/site1/tmp/dbname.dump
Если база использует расширения/роли и вы переносите окружение, дополнительно может понадобиться:
pg_dumpall --globals-only > /var/backups/site1/tmp/globals.sql
Доступ к БД задавайте через переменные окружения или ~/.pgpass (права 600), чтобы пароль не попадал в историю shell.
Для продвинутых сценариев (WAL-архивирование и PITR) уместен отдельный инструмент. По теме: PITR в PostgreSQL: WAL и восстановление.
Архивируем файлы сайта через tar (и исключаем мусор)
Файлы сайта удобнее паковать в tar: вы сохраните права, владельца и симлинки. Ключевой момент — корректные исключения: обычно это кэши, временные директории, исторические логи.
Пример (адаптируйте пути под себя):
tar -czf /var/backups/site1/tmp/site-files.tar.gz -C /var/www/site1 . --exclude=cache --exclude=tmp --exclude=logs --exclude=*.log
Если много мелких файлов, архивация может быть заметно тяжёлой по диску. Запускайте в окно минимальной нагрузки и следите за временем выполнения.
Собираем «один бэкап» как набор: БД + файлы + манифест
Удобная операционная модель: один запуск создаёт отдельный каталог-«снимок», внутри которого лежит всё необходимое для восстановления, плюс метаданные.
/var/backups/site1/daily/2026-01-18_03-10-00/
dbname.sql.gz
site-files.tar.gz
manifest.txt
sha256sums.txt
Так вы избегаете путаницы «какой дамп к какому архиву» и упрощаете retention: удаляете целиком каталог старого бэкапа.

Checksums: контрольные суммы как защита от «тихой порчи»
Контрольные суммы нужны, чтобы понять: файл не изменился и не повредился при записи, копировании или хранении. Это не замена шифрованию и не проверка «корректности SQL», но это хорошая базовая backup verification на уровне файлов.
Типовой подход — sha256sum по всем артефактам бэкапа:
cd /var/backups/site1/daily/2026-01-18_03-10-00
sha256sum dbname.sql.gz site-files.tar.gz > sha256sums.txt
Проверка:
cd /var/backups/site1/daily/2026-01-18_03-10-00
sha256sum -c sha256sums.txt
Если вы копируете бэкапы на другой сервер или в отдельное хранилище, проверку checksums полезно делать после передачи.
Backup verification: быстрая «техпроверка» без поднятия стенда
Контрольные суммы — это фундамент, но не всё. Минимально стоит убедиться, что:
- архив
tarчитается и содержит ожидаемые каталоги; - дамп БД не пустой и сжатие не повреждено;
- размер бэкапа «разумный» (резкие отклонения — повод разбираться).
Примеры быстрых проверок:
gzip -t /var/backups/site1/daily/2026-01-18_03-10-00/dbname.sql.gz
tar -tzf /var/backups/site1/daily/2026-01-18_03-10-00/site-files.tar.gz | head
ls -lh /var/backups/site1/daily/2026-01-18_03-10-00
Для SQL-дампов полезно хотя бы проверить, что файл не «обрублен» (например, внезапно очень маленький). Но единственная проверка, которой можно верить, — восстановление.
Restore test: единственная проверка, которой можно верить
Restore test — это регулярное тестовое восстановление. Без него «бэкап есть» остаётся предположением. Минимальный реалистичный сценарий:
- поднять временную директорию/контейнер/отдельную БД;
- распаковать архив файлов;
- восстановить дамп БД;
- проверить, что приложение стартует и отвечает хотя бы на главную страницу или healthcheck;
- удалить тестовое окружение.
Пример восстановления MySQL в тестовую базу (делайте это на тестовом сервере или в тестовой БД, не на проде):
gunzip -c /var/backups/site1/daily/2026-01-18_03-10-00/dbname.sql.gz | mysql
Для PostgreSQL custom format:
createdb restore_test_db
pg_restore -d restore_test_db /var/backups/site1/daily/2026-01-18_03-10-00/dbname.dump
Если вы не готовы поднимать стенд ежедневно, делайте restore test хотя бы раз в неделю или раз в месяц — и обязательно после крупных обновлений (смена версии БД, миграции схемы, обновление CMS).
Если у вас нет времени на restore test, значит у вас нет времени и на простой в аварии. Тест восстановления — это инвестиция в предсказуемость.
Автоматизация через cron: пример расписания
Ручные бэкапы заканчиваются в первый же аврал. Поэтому используем cron. Подход простой: один скрипт делает бэкап и пишет лог, а cron лишь запускает его.
Каркас скрипта backup
Упрощённый пример: создаёт каталог снимка, делает дамп, пакует файлы, считает checksums и выполняет базовую verification.
#!/bin/sh
set -eu
SITE_NAME=site1
SRC_DIR=/var/www/site1
BASE_DIR=/var/backups/site1
TS=$(date +%F_%H-%M-%S)
DEST_DIR=$BASE_DIR/daily/$TS
LOG_DIR=$BASE_DIR/logs
mkdir -p $DEST_DIR
mkdir -p $LOG_DIR
LOG_FILE=$LOG_DIR/backup-$TS.log
echo "[$(date)] start" >> $LOG_FILE
mysqldump --single-transaction --quick --routines --triggers --events --set-gtid-purged=OFF --databases dbname | gzip -1 > $DEST_DIR/dbname.sql.gz
tar -czf $DEST_DIR/site-files.tar.gz -C $SRC_DIR . --exclude=cache --exclude=tmp --exclude=logs --exclude=*.log
cd $DEST_DIR
sha256sum dbname.sql.gz site-files.tar.gz > sha256sums.txt
sha256sum -c sha256sums.txt >> $LOG_FILE
gzip -t $DEST_DIR/dbname.sql.gz
echo "[$(date)] done" >> $LOG_FILE
Скрипт лучше запускать от отдельного пользователя с минимальными правами: доступ на чтение к файлам сайта и доступ к БД только для дампа.
Запись в crontab
Ежедневно в 03:10:
10 3 * * * /usr/local/sbin/backup-site1.sh
В cron обычно урезанное окружение. Используйте абсолютные пути и проверяйте, что способ авторизации к БД (например, ~/.my.cnf или ~/.pgpass) работает именно под тем пользователем, от которого запускается задача.
Retention: сколько хранить и как не забить диск
Retention — это политика хранения бэкапов. Самый простой вариант:
- daily: хранить 7–14 дней;
- weekly: хранить 4–8 недель;
- monthly: хранить 6–12 месяцев (если требуется).
Реализация без сложных систем — удаление старых каталогов по возрасту. Например, хранить daily 14 дней:
find /var/backups/site1/daily -mindepth 1 -maxdepth 1 -type d -mtime +14 -print -exec rm -rf {} \;
Если вы вставляете команду в скрипт, сначала оставьте только -print, убедитесь, что список корректный, и лишь затем добавляйте удаление. Дополнительно заведите алерт на заполнение диска: бэкап-система, которая умирает молча, создаёт ложное чувство безопасности.
Типовые ошибки и как их поймать
1) «Дамп есть, но он пустой»
Причины: неверные права, подключение не к той БД, ошибка авторизации, дамп без таблиц из-за отсутствия прав. Лечится логированием, проверкой размера файла, а лучше — restore test.
2) «Архив есть, но в нём нет uploads»
Классика: неправильно указан путь -C или слишком агрессивные --exclude. Проверяйте список файлов хотя бы на уровне tar -tzf.
3) «Бэкап запускается, но иногда ломает производительность»
Архивация и дампы могут быть тяжёлыми по диску. Решения: ночное окно, аккуратное сжатие (например, gzip -1), разделение задач (БД отдельно от файлов), мониторинг времени выполнения и размера.
4) «Срок хранения есть на бумаге, по факту диск кончается»
Retention должен быть автоматизирован. И у вас должен быть контроль места. Иначе однажды вы обнаружите, что бэкап «вроде делается», но последние успешные копии — недели назад.
Мини-чеклист: зрелый бэкап сайта за 30 минут
- Определили, что бэкапим: файлы + БД.
- Делаем дамп через
mysqldumpилиpg_dump. - Пакуем файлы в
tarс понятными исключениями. - Считаем checksums и проверяем их (backup verification).
- Запускаем по
cron, пишем лог. - Настраиваем retention, чтобы бэкапы не съели место.
- Планируем регулярный restore test (хотя бы раз в месяц).
Если вы сделаете только это — вы уже будете выше среднего по рынку. Дальше можно наращивать уровень: разносить хранение на другой сервер, добавлять шифрование, уведомления, метрики, изоляцию прав и полноценные сценарии DR.


