Это случилось три года назад. Я переносил базу данных с одного сервера на другой, что-то пошло не так с командой, я подтвердил удаление старой базы — и через секунду понял что удалил новую. Ту которая уже работала. С реальными пользователями.

Бэкап был. Трёхнедельной давности.

Три недели данных — это не конец света для того конкретного проекта. Но это был хороший урок. После него я начал относиться к бэкапам как к части архитектуры, а не как к галочке.

Что значит «нормальный бэкап»

Нормальный бэкап — это не просто файл где-то на сервере. Это:

  1. Регулярность. Не «когда вспомню» а по расписанию. Для большинства проектов достаточно ежедневного бэкапа. Для критичных данных — чаще.

  2. Хранение в другом месте. Бэкап на том же сервере что и данные — это не бэкап. Если сервер горит — горит всё вместе. Минимум: другой сервер или облачное хранилище.

  3. Проверка восстановления. Бэкап который никто не проверял — это потенциально сломаный бэкап. Я потратил два часа однажды на «восстановление» из бэкапа который оказался пустым файлом. Всё это время думал что всё под контролем.

  4. Ротация. Хранить бесконечно всё не нужно и дорого. Обычная схема: 7 дней ежедневных, 4 недельных, 12 месячных.

Как я делаю бэкапы сейчас

Для PostgreSQL у меня крон-задача которая запускается каждую ночь:

#!/bin/bash
set -e

DB_NAME="myapp"
BACKUP_DIR="/backups/postgres"
DATE=$(date +%Y-%m-%d)
FILENAME="$BACKUP_DIR/$DB_NAME-$DATE.sql.gz"

mkdir -p $BACKUP_DIR

pg_dump $DB_NAME | gzip > $FILENAME

# Загружаем в S3-совместимое хранилище
s3cmd put $FILENAME s3://my-backups/postgres/

# Удаляем локальные бэкапы старше 7 дней
find $BACKUP_DIR -name "*.sql.gz" -mtime +7 -delete

echo "Backup completed: $FILENAME"

Для S3 использую Backblaze B2 — дешевле AWS S3 в несколько раз, S3-совместимый API, надёжный.

Файлы — rsync на отдельный сервер плюс копия в облако. Для загруженных пользователями файлов использую restic — он делает дедуплицированные, инкрементальные бэкапы и умеет шифровать.

# Первый раз: инициализация
restic -r s3:s3.us-west-002.backblazeb2.com/my-backups init

# Бэкап
restic -r s3:s3.us-west-002.backblazeb2.com/my-backups backup /var/www/uploads

# Посмотреть снапшоты
restic -r ... snapshots

# Восстановить
restic -r ... restore latest --target /tmp/restore

Мониторинг бэкапов

Бэкап который молча падает — хуже чем отсутствие бэкапа, потому что даёт ложную уверенность.

Я использую healthchecks.io (есть бесплатный план) — сервис который ждёт пинг от вашего скрипта. Если пинг не пришёл в ожидаемое время — шлёт алерт. Добавить в скрипт одну строку:

curl -fsS https://hc-ping.com/your-uuid > /dev/null

Если бэкап упал до этой строки — алерт придёт утром. Просто и надёжно.

Тест восстановления

Раз в квартал я беру бэкап и восстанавливаю его в тестовое окружение. Проверяю что данные читаются, приложение запускается, ничего не сломано.

Это занимает час. Зато я знаю что бэкапы рабочие.

Что в итоге

Бэкапы это скучно. Настраиваешь один раз, они работают тихо в фоне, месяцами ничего не происходит. Именно поэтому их откладывают.

Но когда что-то случается — а рано или поздно случается у всех — разница между «есть бэкап вчерашнего дня» и «бэкап трёхнедельной давности» может быть очень большой.

Я больше не откладываю это на потом.