Возвращаем проект из заморозки: порядок расконсервации, чтобы ничего не рассыпалось
Проект пролежал в заморозке несколько месяцев или год, и вот наконец нашлось время и причина его оживить. Первое желание — включить всё разом: поднять снимок, запустить docker compose up -d, вернуть DNS на место и продолжить с того места, где остановились. Это самый быстрый путь к новой проблеме поверх старой: за время простоя незаметно изменилось многое — от версий пакетов до состояния самих данных, — и «включить всё одним движением» означает узнать о всех этих изменениях одновременно, в проде, на глазах у первых вернувшихся пользователей. Разберём порядок, в котором стоит расконсервировать проект, чтобы каждая проблема ловилась на своём шаге, а не превращалась в снежный ком.
Содержание
- Почему расконсервация — не «включить всё обратно», а последовательность проверок
- Шаг 1: восстановить доступ и вспомнить, как всё было устроено
- Шаг 2: проверить данные и бэкапы — до того, как что-то начнёт их перезаписывать
- Шаг 3: обновить систему и зависимости — но сначала в изолированной среде
- Шаг 4: поднимать сервисы поэтапно, а не разом
- Шаг 5: переключать публичный трафик — только в самом конце
Почему расконсервация — не «включить всё обратно», а последовательность проверок
Заморозка проекта — это не пауза во времени, в которой ничего не происходит. Пока сервер стоял выключенным или проект жил на минимальном архивном тарифе, менялось окружение вокруг него: вышли новые версии ОС и пакетов, истекли или скоро истекут SSL-сертификаты, устарели API сторонних сервисов, изменились правила у платёжных провайдеров и антиспам-фильтров, а сами данные могли незаметно испортиться на диске, даже если никто их не трогал. Ни одно из этих изменений не видно, пока вы просто смотрите на выключенный сервер или архив в холодном хранилище — они обнаруживаются только в момент, когда что-то снова начинает работать.
Отсюда и главный принцип расконсервации: каждый шаг возврата должен быть обратимым и проверяемым до того, как вы делаете следующий. Сначала — доступ и документация, чтобы понимать, с чем вы имеете дело. Затем — данные, потому что они самое ценное и невосстановимое в проекте, и их нельзя подвергать риску ради скорости запуска. Затем — обновление системы и зависимостей, но не в боевом окружении, а в изолированной копии, где ошибка ничего не сломает. Затем — сервисы, поднятые поэтапно, с проверкой на каждом шаге. И только в самом конце — публичный трафик, причём не сразу на полную мощность. Нарушение этого порядка — самая частая причина, по которой «просто включили и всё разом сломалось»: сервисы стартуют раньше, чем проверены бэкапы, публичный DNS переключается раньше, чем стабилизировалось приложение, обновления накатываются прямо в проде, потому что «когда ещё тестировать».
Шаг 1: восстановить доступ и вспомнить, как всё было устроено
Прежде чем что-либо запускать, нужно восстановить полный доступ и заново сложить в голове (или на бумаге) картину того, как проект был устроен на момент заморозки. За полгода-год детали забываются даже у того, кто сам всё настраивал.
Если перед заморозкой был оставлен «паспорт» проекта — письменная инструкция с версиями окружения, списком сервисов, портами, переменными окружения и порядком запуска, — начните именно с него. О том, что такую инструкцию стоит готовить заранее, а не пытаться восстановить по памяти через год, подробно разобрано в статье про экономику заморозки проекта — там же чек-лист, что нужно было зафиксировать перед выключением сервера.
Если такой документации не осталось (частая ситуация, если заморозка была экстренной, а не плановой), придётся восстанавливать картину вручную:
# Что должно было запускаться при старте системы
systemctl list-unit-files --state=enabled
# Что реально crontab планировал выполнять
crontab -l
cat /etc/cron.d/* 2>/dev/null
# Docker-проекты и их состояние на момент остановки
docker ps -a
docker compose ls
cat docker-compose.yml 2>/dev/null
# Какие порты и веб-сервисы были настроены
cat /etc/nginx/sites-enabled/*
ss -tulpn
Параллельно стоит проверить организационную часть доступа: не истекли ли SSH-ключи, актуален ли пароль от панели провайдера, не истёк ли срок регистрации домена и не ушёл ли он в parking после списания оплаты. Ничего из перечисленного не требует запуска сервисов — это чисто инвентаризационный шаг, и лучше потратить на него час, чем потом полдня разбираться, почему что-то не запускается из-за забытой детали конфигурации.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверШаг 2: проверить данные и бэкапы — до того, как что-то начнёт их перезаписывать
Это самый важный шаг во всей последовательности, и его нельзя пропускать ради скорости. Данные — единственное в проекте, что нельзя пересобрать заново: код разворачивается из репозитория, зависимости переустанавливаются, а база клиентов или пользовательские файлы, если испорчены или потеряны, не восстанавливаются ничем. Именно поэтому проверка данных должна пройти раньше, чем запустится хоть один сервис, способный в них писать — иначе повреждённый архив рискует быть перезаписан «свежими» пустыми данными ещё до того, как вы заметите проблему.
Порядок проверки:
# 1. Убедиться, что архив читается и не повреждён
tar -tzf project_files_backup.tar.gz > /dev/null && echo "архив читается корректно"
# 2. Сверить контрольные суммы, если они были сохранены при заморозке
sha256sum -c checksums.sha256
# 3. Развернуть дамп базы в изолированный контейнер — не в боевую БД
docker run --rm -d --name db_check -e POSTGRES_PASSWORD=temp postgres:16
sleep 5
pg_restore -h localhost -U postgres -d postgres project_db_backup.dump
# 4. Свериться, что данные действительно там, а не просто "файл распаковался"
psql -h localhost -U postgres -c "SELECT count(*) FROM users;"
psql -h localhost -U postgres -c "SELECT max(created_at) FROM orders;"
Отдельно стоит проверить сами файлы на диске сервера, если сервер не выключался полностью, а простаивал — за долгий период без активности возможна тихая порча данных на файловой системе, которая никак себя не проявляет, пока файл не попытаются прочитать. Как ловить такую порчу без ZFS и без специализированного FIM-агента — в статье про контроль целостности файлов: подход применим и как разовая проверка перед возвратом проекта в строй, не только как постоянный мониторинг.
Если на этом шаге обнаружится, что архив повреждён, дамп не разворачивается или контрольные суммы не совпадают — остановитесь здесь и разбирайтесь до конца, прежде чем двигаться дальше. Запуск сервисов поверх сомнительных данных — тот случай, когда сэкономленный час оборачивается неделями восстановления.
Шаг 3: обновить систему и зависимости — но сначала в изолированной среде
К моменту расконсервации операционная система, пакеты и зависимости почти наверняка отстали от актуальных версий на месяцы, а то и на год. Это не мелочь: чем дольше система не обновлялась, тем выше шанс, что за это время закрыли критичную уязвимость или сторонний сервис отключил старую версию API, на которую опирался код. Но и обновление одним махом — «apt update && apt upgrade -y» прямо на проде — рискует не меньше: слишком много изменений накопится за раз, и если что-то сломается, будет неочевидно, какой именно из полусотни обновлённых пакетов тому виной.
Правильный порядок — сначала поднять изолированную копию окружения и обкатать обновления там, а не в боевом контуре. Как именно организовать такую копию сайта или сервиса — разобрано в статье про настройку staging-копии: те же принципы синхронизации и разделения окружений применимы и к разовому обновлению после долгого простоя, не только к постоянной практике тестирования.
# В изолированной копии — сначала смотрим, что вообще устарело
apt list --upgradable
docker compose pull --dry-run 2>/dev/null || docker compose config --images
# Для языковых зависимостей — аналогично, не применяя сразу
npm outdated
pip list --outdated
# Снимок состояния перед обновлением — на случай отката
tar -czf pre_update_snapshot_$(date +%F).tar.gz /var/www/project /etc/nginx
После обновления в изолированной среде — обязательно прогнать приложение целиком: убедиться, что оно стартует, отвечает на основные запросы и не падает при первых операциях с базой. Только после этого те же обновления переносятся на боевой сервер, причём тем же контролируемым способом: сначала снимок для отката, потом обновление, потом проверка.
Отдельная больная тема — зависимости, автор которых мог за это время вовсе перестать поддерживать пакет: удалить его из реестра, закрыть репозиторий или просто прекратить выпускать обновления безопасности. После долгого простоя стоит не просто обновить версии, а свериться, какие из используемых библиотек вообще ещё живы. Подход к такой ревизии — в статье про квартальный аудит зависимостей: после года простоя это тем более актуально, чем при обычной регулярной проверке.
Шаг 4: поднимать сервисы поэтапно, а не разом
Даже после того, как данные проверены, а обновления обкатаны в изоляции, не стоит поднимать весь стек одной командой docker compose up -d или systemctl start по списку. При разовом старте всего сразу невозможно понять, какой именно сервис не готов к работе — все ошибки посыпятся одновременно, вперемешку.
Разумный порядок этапов:
- Инфраструктурный слой — сеть, firewall, DNS-резолвер, если он свой. Убедиться, что базовая связность и правила доступа работают так, как задумано, прежде чем на них будет что-то опираться.
- Вспомогательные сервисы без публичного трафика — база данных, кэш, очередь сообщений. Запустить и проверить их состояние напрямую, не через приложение:
docker compose up -d --no-deps postgres redis
docker compose exec postgres pg_isready
docker compose exec redis redis-cli ping
- Основное приложение — но без публичного доступа. Поднять в закрытом режиме: только по внутреннему IP, через VPN или с ограничением по списку IP на уровне firewall. На этом этапе цель — увидеть, что приложение вообще стартует и корректно работает с уже проверенными данными, а не то, как оно ведёт себя под реальной нагрузкой.
# Пример ограничения доступа к порту приложения только с одного IP
iptables -A INPUT -p tcp --dport 8080 -s 203.0.113.10 -j ACCEPT
iptables -A INPUT -p tcp --dport 8080 -j DROP
- Проверка логов и health-check'ов на каждом этапе, прежде чем переходить к следующему. Если приложение стартовало, но в логах есть повторяющиеся ошибки подключения к внешним сервисам, просроченный сертификат или предупреждения о несовместимости версий — это сигнал остановиться и разобраться, а не «само пройдёт после следующего шага».
- Фоновые и некритичные задачи — почтовые рассылки, обработчики очередей, cron-задачи. Их разумно включать последними и по одной, особенно если среди них есть операции, необратимо меняющие данные (например, массовая рассылка уведомлений «неактивным» пользователям, которые на самом деле давно должны были её получить, но не получили из-за простоя).
Между этапами не обязательно ждать часами — но обязательно проверять фактическое состояние (логи, health-check, ответ на тестовый запрос), а не полагаться на то, что команда запуска отработала без ошибки. Отсутствие ошибки при старте контейнера не означает, что сервис внутри действительно работает корректно.
Шаг 5: переключать публичный трафик — только в самом конце
Переключение DNS обратно на восстановленный сервис или снятие заглушки — последний шаг, а не один из первых, и делать его стоит только после того, как все предыдущие этапы подтверждены. К этому моменту у вас уже должна быть уверенность, что данные целы, окружение обновлено и проверено в изоляции, а приложение стабильно работает в закрытом режиме без публичного трафика.
Практические детали переключения:
- Заранее снизить TTL DNS-записи (например, до 300 секунд), если он был увеличен на время заморозки — это сокращает время, за которое изменение дойдёт до всех резолверов, и даёт возможность быстро откатиться, если сразу после открытия что-то пойдёт не так.
- Проверить работу приложения через реальный домен до переключения основного трафика — например, временно добавив запись в локальный
/etc/hostsна своей машине, указывающую домен на новый сервер, не трогая публичную DNS-запись:
# На своей машине, не на сервере
echo "203.0.113.20 example.ru" | sudo tee -a /etc/hosts
- Открывать доступ постепенно, если это возможно техническически — например, сначала для части трафика или конкретного региона через настройки DNS/CDN, а не сразу для всех. Не любой проект может себе это позволить, но там, где инфраструктура позволяет, постепенное открытие снижает риск того, что первая волна реальных пользователей столкнётся с ещё не до конца стабилизированным сервисом.
- Держать план быстрого отката под рукой: если сразу после переключения DNS начинают расти ошибки 5xx или падает база под реальными запросами — вернуть старую запись (или заглушку) проще и быстрее, чем разбираться в проде на глазах у пользователей.
Не спешите открывать проект полностью сразу после первого успешного запуска. Первый успешный старт означает только то, что стек поднялся и ответил на тестовый запрос — это не то же самое, что «готово к реальной нагрузке». Разумная практика — дать сервису поработать в закрытом или ограниченном режиме от нескольких часов до нескольких дней, наблюдая за логами, потреблением ресурсов и поведением под небольшим контролируемым трафиком, прежде чем возвращать полноценный публичный доступ. Именно на этом окне обычно всплывают проблемы, не видные на первом запуске: медленная утечка памяти, неожиданный рост очереди задач, забытая переменная окружения, которая давала о себе знать только через несколько часов работы.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Сколько времени держать проект в закрытом режиме перед полным открытием?
Единого правила нет — ориентируйтесь на критичность проекта и на то, есть ли у вас возможность наблюдать за метриками. Для небольшого сайта может хватить нескольких часов стабильной работы, для проекта с деньгами или персональными данными пользователей разумнее заложить день-два наблюдения под контролируемой нагрузкой.
Что делать, если документации о том, как всё было устроено до заморозки, не осталось совсем?
Восстанавливать вручную по следам в системе: включённые unit-файлы systemd, crontab, конфиги nginx, docker-compose файлы и переменные окружения в них. Это дольше, чем работа по готовой инструкции, но выполнимо — и хороший повод на этот раз задокументировать конфигурацию, прежде чем проект снова окажется без присмотра.
Обязательно ли обновлять систему и зависимости до последних версий, или можно поднять всё как было?
Поднять «как было» без единого обновления — рискованно, если простой длился долго: за это время могли закрыть уязвимости, от которых старая версия не защищена. Но и обновлять всё до самых последних версий бездумно тоже не стоит — двигайтесь постепенно, тестируя в изолированной копии, и обновляйте в первую очередь то, что напрямую влияет на безопасность.
Бэкап не проходит проверку восстановлением — что делать дальше?
Не запускать боевые сервисы, пока не разберётесь. Проверьте, есть ли более ранняя резервная копия, которая всё же разворачивается корректно, и сколько данных в этом случае будет потеряно между датой этой копии и моментом заморозки. Запуск поверх непроверенного архива — риск потерять данные окончательно вместо того, чтобы их вернуть.
Стоит ли сначала протестировать проект на временном поддомене, а не на основном домене?
Да, если это возможно технически — тестовый поддомен (например, staging.example.ru) с отдельной DNS-записью позволяет проверить работу через реальный домен и HTTPS, не рискуя основным адресом и не показывая недоделанное состояние тем, кто может случайно зайти на старый URL раньше времени.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →