Резервные копии баз данных
Как настроить дампы MySQL и PostgreSQL по расписанию, увезти их с машины и проверить, что копия действительно восстанавливается.
Обновлено 23 августа 2026 г.
Автоматических резервных копий машины и снимков состояния у VDS нет: всё, что вы не скопировали сами, существует в одном экземпляре. Дамп базы — первое, что стоит настроить, потому что данные восстановить неоткуда, а сайт можно развернуть заново.
Дамп вручную
PostgreSQL:
pg_dump -Fc -U shop -h 127.0.0.1 shop > /srv/backups/shop-$(date +%F).dump
pg_dumpall -U postgres --roles-only > /srv/backups/roles.sql
MySQL и MariaDB:
mysqldump --single-transaction --quick --routines --events \
-u root shop | gzip > /srv/backups/shop-$(date +%F).sql.gz
--single-transaction снимает согласованный дамп InnoDB без блокировки таблиц — без него сайт встанет на время выгрузки. Формат -Fc у PostgreSQL сжат и позволяет восстанавливать отдельные таблицы.
Пароли в командной строке не пишите: заведите ~/.pgpass или ~/.my.cnf с правами 600.
По расписанию
mkdir -p /srv/backups && chmod 700 /srv/backups
crontab -e
20 3 * * * /usr/local/bin/db-backup.sh >> /var/log/db-backup.log 2>&1
Скрипт /usr/local/bin/db-backup.sh:
#!/bin/bash
set -euo pipefail
DEST=/srv/backups
STAMP=$(date +%F-%H%M)
pg_dump -Fc -U shop -h 127.0.0.1 shop > "$DEST/shop-$STAMP.dump.tmp"
mv "$DEST/shop-$STAMP.dump.tmp" "$DEST/shop-$STAMP.dump"
find "$DEST" -name '*.dump' -mtime +14 -delete
Запись во временный файл с последующим переименованием важна: если дамп оборвётся, вы не примете обрубок за готовую копию. set -euo pipefail останавливает скрипт на первой ошибке вместо тихого продолжения.
Увезти с машины
Копия на том же диске не спасает от ошибки в миграции, шифровальщика и от переустановки системы на вкладке «Доступ». Отправляйте дампы наружу:
rsync -az --delete /srv/backups/ backup@другой-хост:/store/vds/
Или в любое S3-совместимое хранилище через rclone. Учитывайте полосу до 500 Мбит/с и лимит записи на диск по ступени: 60 МБ/с на ядро.
Проверка восстановления
Копия, которую ни разу не разворачивали, копией не является.
createdb -U postgres shop_check
pg_restore -U postgres -d shop_check /srv/backups/shop-2026-08-23.dump
psql -U postgres -d shop_check -c "SELECT count(*) FROM users;"
dropdb -U postgres shop_check
Для MySQL: gunzip -c дамп.sql.gz | mysql -u root shop_check.
Делайте это раз в месяц и записывайте дату проверки.
Частые ошибки
| Симптом | Причина |
|---|---|
| Дамп весит несколько килобайт | Скрипт упал на аутентификации, ошибка ушла в /dev/null |
| Кончилось место на диске | Нет удаления старых копий по mtime |
| Восстановление падает на правах | Роли не выгружены — нужен --roles-only |
| Cron молчит, копий нет | В cron нет вашего PATH — пишите абсолютные пути |
| Сайт тормозит ночью | Дамп конкурирует за диск — сдвиньте время, добавьте --quick |
Храните минимум две копии в разных местах и следите за размером дампа: резкое падение объёма — признак того, что выгрузилась не вся база.