Удалили сервер вместе с бэкапами: как мы восстановили данные и перестроили систему резервного копирования

Что произошло

Бухгалтерская компания «БухСервис» из 40 сотрудников использовала VPS у небольшого хостера для своей CRM, файлового хранилища и 1С-базы. Ежемесячная оплата — 4 800 рублей, бэкапы — через панель хостера за дополнительные 800 рублей.

В феврале 2026 бухгалтер, оплачивающий хостинг, ушёл в отпуск. Автоплатёж не прошёл — карта была перевыпущена. Через 7 дней хостер удалил сервер. Вместе с ним были удалены все бэкапы — они хранились на том же аккаунте и были привязаны к жизненному циклу сервера.

Потери:

  • База 1С за 3 года — 12 ГБ (первичные документы, проводки, отчётность)
  • CRM с историей 8 000 клиентов
  • Файловое хранилище — 180 ГБ сканов документов
  • Конфигурация сервера и все скрипты автоматизации

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

Анализ: что пошло не так

При расследовании мы выявили пять критических ошибок:

1. Single Point of Failure в оплате. Один человек, одна карта, без автоматического уведомления коллег. Когда этот человек стал недоступен — цепочка оплаты прервалась.

2. Бэкапы привязаны к серверу. Хостер хранил бэкапы в том же аккаунте. При удалении аккаунта удалялось всё. Клиент платил за «услугу бэкапов», но фактически это была копия на соседнем диске того же датацентра.

3. Отсутствие offsite-копии. Ни одной копии данных вне хостера. Ни облако, ни локальный NAS, ни внешний диск.

4. Бэкапы никогда не тестировались. За 3 года ни разу не проверяли, можно ли восстановить данные из бэкапа. Даже формат бэкапа не был известен.

5. Отсутствие документации. Пароли от хостинга знал только один администратор. Восстановление доступа заняло 2 дня переписки с хостером.

Экстренное восстановление данных

Мы были вызваны на третий день после инцидента. Полное восстановление невозможно, но частичное — реально. Вот что мы сделали:

Этап 1: Сбор осколков.

# Поиск локальных копий на рабочих станциях
# Многие сотрудники синхронизировали файлы через WebDAV
find /home/ -type f -name '*.1cd' -o -name '*.dt' -o -name '*.cf' 2>/dev/null
find /home/ -type f \( -name '*.pdf' -o -name '*.xlsx' \) -newer /tmp/cutoff_date

# Проверка кэша Яндекса и Google для публичных страниц CRM
curl -s "https://yandex.ru/search/?text=site:crm.buhservice.ru" | \
    grep -oP 'href="[^"]*cache[^"]*"'

Этап 2: Восстановление базы 1С. На ноутбуке главного бухгалтера обнаружилась копия базы 6-недельной давности — он выгружал её для работы дома. Пришлось восстановить 6 недель проводок вручную из первичных документов.

Этап 3: CRM из email. Большинство контактов клиентов удалось восстановить из почтовых архивов и выгрузки контактов телефонов сотрудников.

Итог: восстановлено около 70% данных. Потеряно 30% сканов документов и 6 недель бухгалтерских проводок. Ручное восстановление заняло 3 недели и обошлось компании в 480 000 рублей (работа бухгалтеров + наши услуги).

Правило 3-2-1-1-0

Классическое правило 3-2-1 давно известно, но мы используем расширенную версию 3-2-1-1-0:

  • 3 копии данных — оригинал + 2 бэкапа
  • 2 типа носителей — например, SSD сервера + объектное хранилище
  • 1 копия offsite — географически удалённая, другой провайдер
  • 1 копия immutable — неизменяемая, защищённая от шифровальщиков и ошибок
  • 0 ошибок при восстановлении — регулярное тестирование

Для «БухСервис» мы спроектировали три уровня бэкапов:

# Уровень 1: Локальный бэкап на сервере (быстрое восстановление)
# /etc/cron.d/backup-local
0 */4 * * * root /opt/backup/local-backup.sh

# Уровень 2: Offsite в S3-совместимое хранилище (Selectel)
# Каждые 6 часов
0 1,7,13,19 * * * root /opt/backup/s3-backup.sh

# Уровень 3: Еженедельный immutable бэкап (другой провайдер)
0 3 * * 0 root /opt/backup/immutable-weekly.sh

Реализация бэкапов с Restic

Мы выбрали Restic — инкрементальный бэкап-инструмент с дедупликацией, шифрованием и поддержкой S3:

# Установка
apt install restic

# Инициализация репозитория в S3
export AWS_ACCESS_KEY_ID="XXXXXXXXXX"
export AWS_SECRET_ACCESS_KEY="YYYYYYYYYY"
export RESTIC_REPOSITORY="s3:https://s3.selcdn.ru/buhservice-backup"
export RESTIC_PASSWORD="strong-encryption-passphrase"

restic init

# Скрипт бэкапа /opt/backup/s3-backup.sh
#!/bin/bash
set -euo pipefail

export AWS_ACCESS_KEY_ID="XXXXXXXXXX"
export AWS_SECRET_ACCESS_KEY="YYYYYYYYYY"
export RESTIC_REPOSITORY="s3:https://s3.selcdn.ru/buhservice-backup"
export RESTIC_PASSWORD_FILE="/root/.restic-password"

LOG="/var/log/backup/restic-$(date +%Y%m%d-%H%M).log"

# Дамп базы 1С перед бэкапом
pg_dump -U postgres onec_db | gzip > /var/backup/1c_dump.sql.gz

# Бэкап с тегами для удобного поиска
restic backup \
    --tag "scheduled" \
    --tag "$(date +%A)" \
    --exclude-file=/opt/backup/exclude.txt \
    /var/lib/1c \
    /var/www/crm \
    /home/shared \
    /etc \
    /var/backup/1c_dump.sql.gz \
    2>&1 | tee "$LOG"

# Ротация: храним 7 ежедневных, 4 еженедельных, 12 ежемесячных
restic forget \
    --keep-daily 7 \
    --keep-weekly 4 \
    --keep-monthly 12 \
    --prune

# Проверяем целостность (раз в неделю — полная, остальное — выборочная)
if [ "$(date +%u)" = "7" ]; then
    restic check --read-data
else
    restic check
fi

# Уведомление в Telegram
BACKUP_SIZE=$(restic stats --json | jq -r '.total_size' | numfmt --to=iec)
curl -s -X POST "https://api.telegram.org/bot${TG_TOKEN}/sendMessage" \
    -d chat_id="${TG_CHAT}" \
    -d text="Бэкап БухСервис: OK, размер: ${BACKUP_SIZE}"

Immutable бэкапы: защита от шифровальщиков

Immutable (неизменяемые) бэкапы невозможно удалить или зашифровать даже при полном компрометации сервера. Мы реализовали их через S3 Object Lock:

# Настройка Object Lock на бакете (Selectel/MinIO/AWS S3)
# Включается при создании бакета, нельзя добавить после
aws s3api create-bucket \
    --bucket buhservice-immutable \
    --object-lock-enabled-for-bucket

# Политика Compliance — даже root не может удалить
aws s3api put-object-lock-configuration \
    --bucket buhservice-immutable \
    --object-lock-configuration '{
        "ObjectLockEnabled": "Enabled",
        "Rule": {
            "DefaultRetention": {
                "Mode": "COMPLIANCE",
                "Days": 90
            }
        }
    }'

Альтернатива для BorgBackup — append-only режим на отдельном сервере:

# На сервере бэкапов: /etc/ssh/sshd_config
Match User borgbackup
    ForceCommand borg serve --restrict-to-repository /backup/buhservice --append-only
    PasswordAuthentication no
    X11Forwarding no
    AllowTcpForwarding no

В append-only режиме клиент может создавать новые бэкапы, но не может удалять старые. Ротацию (prune) выполняет отдельный скрипт на сервере бэкапов, запускаемый по расписанию от другого пользователя.

Автоматическое тестирование восстановления

Ноль ошибок при восстановлении — последняя цифра в правиле 3-2-1-1-0. Бэкап, который нельзя восстановить — не бэкап. Мы автоматизировали тестирование:

# /opt/backup/test-restore.sh
#!/bin/bash
set -euo pipefail

TEST_DIR=$(mktemp -d /tmp/backup-test.XXXXX)

# Восстанавливаем последний бэкап во временную директорию
restic restore latest \
    --target "$TEST_DIR" \
    --include "/var/backup/1c_dump.sql.gz" \
    --include "/var/www/crm/config"

# Проверяем целостность SQL дампа
gunzip -t "$TEST_DIR/var/backup/1c_dump.sql.gz"
if [ $? -ne 0 ]; then
    echo "ОШИБКА: SQL дамп повреждён!"
    curl -s -X POST "https://api.telegram.org/bot${TG_TOKEN}/sendMessage" \
        -d chat_id="${TG_CHAT}" \
        -d text="КРИТИЧНО: тест восстановления бэкапа ПРОВАЛЕН!"
    exit 1
fi

# Проверяем наличие ключевых файлов
for f in "var/www/crm/config/database.php" "var/www/crm/config/app.php"; do
    if [ ! -f "$TEST_DIR/$f" ]; then
        echo "ОШИБКА: отсутствует $f"
        exit 1
    fi
done

# Пробуем загрузить дамп в тестовую базу
createdb -U postgres test_restore_db 2>/dev/null || true
gunzip -c "$TEST_DIR/var/backup/1c_dump.sql.gz" | \
    psql -U postgres test_restore_db > /dev/null 2>&1

ROW_COUNT=$(psql -U postgres -t -c "SELECT count(*) FROM test_restore_db.public.documents" 2>/dev/null || echo "0")

if [ "$ROW_COUNT" -lt 1000 ]; then
    echo "ПРЕДУПРЕЖДЕНИЕ: в базе всего $ROW_COUNT записей, ожидалось >1000"
fi

# Очистка
dropdb -U postgres test_restore_db 2>/dev/null || true
rm -rf "$TEST_DIR"

echo "Тест восстановления пройден: SQL OK, файлы OK, БД: $ROW_COUNT записей"

# Запускаем каждую субботу в 5 утра
# 0 5 * * 6 root /opt/backup/test-restore.sh >> /var/log/backup/test.log 2>&1

Итоги и рекомендации

Стоимость построения системы бэкапов для «БухСервис»:

КомпонентСтоимость/мес
S3-хранилище (Selectel, 500 ГБ)1 200 руб
Immutable-хранилище (отдельный провайдер, 200 ГБ)800 руб
VPS для тестирования восстановления0 руб (используем dev-сервер)
Итого2 000 руб/мес

2 000 рублей в месяц против 480 000 рублей убытков от потери данных. Соотношение 1:240.

Чек-лист для любой компании:

  • Оплата хостинга — автоплатёж + резервная карта + уведомления минимум двум людям
  • Бэкапы — отдельно от хостера, минимум у двух провайдеров
  • Immutable — хотя бы еженедельная неизменяемая копия
  • Тестирование — ежемесячное восстановление в тестовую среду
  • Документация — пароли в менеджере паролей, доступ у 2+ человек
  • Мониторинг бэкапов — алерт в Telegram/почту, если бэкап не выполнен

Часто задаваемые вопросы

Restic обеспечивает дедупликацию на уровне блоков данных, AES-256 шифрование, инкрементальные бэкапы и встроенную проверку целостности. Rsync копирует файлы как есть, без шифрования и дедупликации. Для 200 ГБ данных с ежедневным изменением 5% Restic передаёт 10 ГБ, а rsync — до 200 ГБ без --link-dest.
Object Lock — функция S3-совместимых хранилищ, запрещающая удаление или перезапись объекта в течение заданного срока. В режиме Compliance даже администратор не может удалить бэкап. Это защищает от шифровальщиков, злонамеренного удаления и ошибок оператора.
Минимум ежемесячно — полное восстановление в тестовую среду с проверкой работоспособности приложений. Еженедельно — автоматическая проверка целостности (restic check). После каждого бэкапа — верификация контрольных сумм. Для критичных данных (базы, финансы) — еженедельное восстановление.
Категорически нет. Бэкап хостера — это удобство для быстрого отката, но не защита данных. Он может быть удалён вместе с аккаунтом, находится в том же датацентре, не защищён от ошибок провайдера. Всегда имейте offsite-копию у другого провайдера.
От 1 500 до 3 000 рублей в месяц: S3-хранилище (Selectel, VK Cloud) для 200-500 ГБ — 800-1 500 руб, плюс второй провайдер для immutable-копий — 500-1 000 руб. Инструменты (Restic, BorgBackup) бесплатны. Настройка занимает 4-6 часов.

Нужна помощь с проектом?

Специалисты АйТи Фреш помогут с архитектурой, DevOps, безопасностью и разработкой — 15+ лет опыта

📞 Связаться с нами
#backup#disaster recovery#3-2-1 rule#immutable backups#restic#borgbackup#offsite backup#single point of failure
Комментарии 0

Оставить комментарий

загрузка...