Файлы работающей базы нельзя просто скопировать: в момент копирования они меняются, и копия может оказаться повреждённой. Правильный способ — дамп, согласованный снимок данных, который база делает сама без остановки.
$ mkdir -p /var/backups/db$ chmod 700 /var/backups/dbPostgreSQL
$ sudo -u postgres pg_dump -Fc app > /var/backups/db/app-$(date +%F).dump$ sudo -u postgres pg_dumpall --globals-only > /var/backups/db/globals-$(date +%F).sql-Fc — сжатый формат, из которого можно восстановить всю базу или отдельные таблицы. Второй файл содержит роли и их права: pg_dump их не сохраняет.
MySQL и MariaDB
$ mysqldump --single-transaction --routines --triggers --events --databases app | gzip > /var/backups/db/app-$(date +%F).sql.gz--single-transaction делает согласованный дамп таблиц InnoDB без блокировки. На Ubuntu и Debian root подключается к MySQL через сокет без пароля, поэтому команда работает от root как есть.
База в Docker
$ cd /opt/myapp$ docker compose exec -T db pg_dump -U app -Fc app > /var/backups/db/app-$(date +%F).dumpФлаг -T отключает псевдотерминал — без него бинарный дамп будет испорчен.
Скрипт с ротацией
$ #!/bin/sh$ set -e$ DIR=/var/backups/db$ STAMP=$(date +%F-%H%M)$ $ sudo -u postgres pg_dump -Fc app > "$DIR/app-$STAMP.dump"$ # mysqldump --single-transaction --routines --triggers --databases app | gzip > "$DIR/app-$STAMP.sql.gz"$ $ # Храним 14 дней$ find "$DIR" -type f -mtime +14 -delete$ echo "$(date -Is) ok"$ chmod 700 /usr/local/bin/backup-db.sh$ /usr/local/bin/backup-db.sh && ls -lh /var/backups/db0 * * * * root flock -n /run/backup-db.lock /usr/local/bin/backup-db.sh >> /var/log/backup-db.log 2>&1Дамп раз в час. Дальше отправляйте каталог /var/backups/db за пределы сервера — через restic или rsync.
Проверьте восстановление
Восстанавливайте в отдельную базу, чтобы не задеть рабочую:
$ sudo -u postgres createdb app_restore$ sudo -u postgres pg_restore -d app_restore --no-owner /var/backups/db/app-2026-09-25-0300.dump$ sudo -u postgres psql -d app_restore -c "\dt"$ mysql -e "CREATE DATABASE app_restore"$ gunzip -c /var/backups/db/app-2026-09-25-0300.sql.gz | sed "s/\`app\`/\`app_restore\`/g" | mysql$ mysql -e "SHOW TABLES FROM app_restore"Дамп с --databases содержит команды CREATE DATABASE и USE с именем исходной базы — sed подменяет его, чтобы данные ушли в app_restore. Проверив таблицы и свежие записи, удалите тестовую базу.
Частые ошибки
- Дампы лежат только на том же сервере — при переустановке или взломе пропадут вместе с базой.
- Файл дампа нулевого размера — скрипт упал, а cron об этом молчит. Проверяйте лог и размер последнего файла.
- Дамп MySQL без --single-transaction блокирует таблицы на время выгрузки, и сайт «подвисает».