Бэкапы без самообмана: создаём и восстанавливаем
Архив на том же диске исчезнет вместе с VPS. Поэтому сделаем локальную ежедневную копию для скорости, отправим её во внешнее хранилище и обязательно проверим восстановление.
Что считать хорошим бэкапом
Правило 3‑2‑1: три экземпляра данных, два разных типа хранения, одна копия вне основного сервера. Копируем только то, что нельзя получить заново: базу, загрузки пользователей, конфигурацию и секреты в защищённом виде. Код уже есть в Git, образ можно пересобрать.
1. Создаём закрытую папку
sudo chown deploy:deploy /var/backups/ratehost
chmod 700 /var/backups/ratehost
Права 700 дают доступ только владельцу.
2. Архивируем файлы
/home/deploy/app/uploads \
/home/deploy/app/compose.yaml \
/etc/nginx/sites-available/app
tar собирает файлы, z сжимает gzip, $(date ...) добавляет дату к имени. Предупреждение про удаление начального слеша нормально.
3. Сохраняем PostgreSQL
Копировать живые файлы базы обычным архивом нельзя: можно получить несогласованное состояние. Используем pg_dump через контейнер:
docker compose exec -T db pg_dump -U app app | gzip \
> /var/backups/ratehost/db-$(date +%F-%H%M).sql.gz
Первое app после -U — имя пользователя БД, второе — имя базы. Замените их значениями вашего Compose.
4. Собираем сценарий
set -euo pipefail
DEST=/var/backups/ratehost
STAMP=$(date +%F-%H%M)
mkdir -p "$DEST"
tar -czf "$DEST/files-$STAMP.tar.gz" /home/deploy/app/uploads
cd /home/deploy/app
docker compose exec -T db pg_dump -U app app | gzip > "$DEST/db-$STAMP.sql.gz"
find "$DEST" -type f -mtime +7 -delete
echo "Backup completed: $STAMP"
sudo /usr/local/sbin/backup-ratehost
ls -lh /var/backups/ratehost
set -euo pipefail останавливает сценарий при ошибке вместо создания ложного «успешного» бэкапа.
5. Запускаем по расписанию
Добавьте ежедневный запуск в 03:30:
Cron использует время сервера. На следующий день проверяйте не только наличие файла, но и журнал.
6. Уносим копию с VPS
Подключите S3‑совместимое хранилище через rclone и добавьте после создания файлов команду копирования. Ключу выдайте доступ только к отдельному bucket бэкапов. Включите версионирование или защиту от удаления, если хранилище это поддерживает.
7. Репетируем восстановление
tar -tzf /var/backups/ratehost/files-ФАЙЛ.tar.gz | head
Это проверяет целостность, но не содержание. Настоящий тест базы:
gunzip -c db-ФАЙЛ.sql.gz | psql -d app_restore
В Docker восстановите дамп в отдельную тестовую базу, не поверх рабочей. Откройте несколько ключевых записей и только затем удаляйте тест.
Что обычно забывают
- бэкап создаётся, но никогда не покидает VPS;
- скрипт падает, а никто не читает журнал;
- копируется база «как папка» во время записи;
- есть архив, но нет инструкции восстановления;
- ключ от хранилища лежит в публичном репозитории.
Что дальше
Осталось вовремя узнавать о сбоях: настроим мониторинг и алерты →