Сервер без обновлений три года: как обновлять, чтобы он не лёг насовсем
apt list --upgradable выводит не десяток строк, а несколько сотен, uname -r показывает ядро трёхлетней давности, а мысль «давайте уже обновим всё разом» пугает больше, чем сами дыры в безопасности. Это правильный страх: один большой full-upgrade через три года простоя с высокой вероятностью не «обновит систему», а уронит её так, что откатывать придётся не пакет, а весь сервер целиком. О том, чем именно опасен сам факт многолетнего простоя без патчей, есть отдельный разбор — чем на самом деле опасен принцип «работает — не трогай». Здесь же — конкретный план, как безопасно закрыть уже накопленное отставание: снять точку возврата, обновляться маленькими проверяемыми шагами и тестировать сервисы после каждого, а не после всех сразу.
Содержание
- Почему один большой прыжок — худший из вариантов
- Шаг 0: снапшот и бэкап раньше, чем что-либо ещё
- Инвентаризация: что должно продолжать работать
- План поэтапного обновления: сначала патчи, потом версии по одной ступеньке
- Тестирование критичных сервисов после каждого этапа
- Откат: что делать, если этап пошёл не так
- Что делать дальше, чтобы не оказаться здесь снова через три года
Почему один большой прыжок — худший из вариантов
Три года простоя — это не «одно накопленное обновление», а несколько десятков минорных релизов и, скорее всего, один-два мажорных перехода, слипшихся в одну кучу. У пакетного менеджера нет отдельной команды «обнови аккуратно, по одной ступеньке» — apt full-upgrade или dnf upgrade в лоб попытается дотянуть всё до последних доступных версий за один проход, включая ядро, СУБД, веб-сервер, PHP или Python, системные библиотеки — и применит сразу все изменения конфигов, все миграции зависимостей, все смены дефолтов.
Проблема не в объёме работы, а в диагностике после сбоя. Если после одного шага «обновили только nginx» сайт перестал отвечать — подозреваемый один. Если после full-upgrade, который переустановил четыреста пакетов и два ядра, перестало работать всё — вы не знаете, что из четырёхсот изменений виновато: несовместимая версия PHP-FPM, новый дефолтный конфиг nginx, изменившееся поведение библиотеки, от которой зависит бэкенд, или banально то, что новое ядро не поднимает сеть на этом конкретном железе. Расследование растягивается на часы, пока сервис лежит.
Второй риск — необратимость. Пакетный менеджер, обновляя систему за один проход, обычно не хранит откат назад как штатную операцию: старые версии пакетов могут быть уже вычищены из кеша, конфиги — переписаны поверх без сохранения оригиналов (если вы не ответили правильно на диалоги dpkg о конфликте конфигов), а миграция схемы БД, если она успела применится, может быть необратима без бэкапа. У большого прыжка нет промежуточных точек, куда можно откатиться частично — только «было» и «после всего».
Правильная альтернатива — то же самое количество обновлений, но разбитое на шаги с проверкой между ними. Это не быстрее в моменте, зато предсказуемо: каждый шаг маленький, у каждого есть точка возврата, и если что-то ломается — вы точно знаете, что именно.
Шаг 0: снапшот и бэкап раньше, чем что-либо ещё
Прежде чем ставить хоть один пакет, должна существовать точка, к которой можно быстро вернуться. Без этого условия весь дальнейший план не имеет смысла — «поэтапно» ничем не поможет, если после третьего шага откатываться некуда.
Если сервер виртуальный и хостер даёт снапшоты на уровне гипервизора — это самый надёжный и самый быстрый по времени восстановления вариант, потому что откатывает разом диск, пакеты и конфиги:
# libvirt/qcow2 — снапшот перед первым шагом обновления
sudo virsh snapshot-create-as legacy-server pre-update-stage0 --disk-only --atomic
# после успешного шага снапшот можно снять и снять новый перед следующим
sudo virsh snapshot-list legacy-server
Если снапшотов на уровне гипервизора нет (или сервер физический), опирайтесь на дамп БД и бэкап конфигов/данных, снятый непосредственно перед началом работы, а не «вчера ночью по расписанию»:
# дамп СУБД с меткой времени
sudo -u postgres pg_dump -Fc mydb > /backups/mydb-pre-legacy-update-$(date +%F-%H%M).dump
# конфиги — в архив, поштучно, чтобы не гадать потом, что менялось
sudo tar czf /backups/etc-pre-update-$(date +%F).tar.gz /etc
# если /etc не под git — самое время завести хотя бы локальный репозиторий
cd /etc && sudo git init -q && sudo git add -A && sudo git commit -q -m "state before legacy update"
Второе обязательное условие — бэкап должен быть проверен на восстановление хотя бы раз, а не существовать теоретически. Разворачивание дампа на тестовой машине до начала работы — не бюрократия, а единственный способ узнать, что бэкап реально рабочий, а не битый файл, который никогда не пробовали открыть.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверИнвентаризация: что должно продолжать работать
Прежде чем что-либо обновлять, нужен список того, что на сервере вообще есть и что из этого критично — иначе после каждого шага непонятно, что проверять. На сервере с трёхлетней историей документации почти наверняка нет, поэтому инвентаризацию нужно снять с живой системы.
# что слушает порты прямо сейчас — реальная карта работающих сервисов
sudo ss -tulpn
# что запущено под systemd и в каком состоянии
systemctl list-units --type=service --state=running
# версии ключевого софта до начала работ — зафиксировать, чтобы потом сравнить
dpkg -l | grep -E 'nginx|postgresql|php|mysql-server' # Debian/Ubuntu
rpm -qa | grep -E 'nginx|postgresql|php|mariadb' # RHEL/AlmaLinux
# сайты и виртуальные хосты, если это веб-сервер
ls /etc/nginx/sites-enabled/ 2>/dev/null
ls /etc/httpd/conf.d/ 2>/dev/null
Отдельно стоит выписать всё, что запущено вручную и не оформлено как systemd-юнит — такие процессы не переживут даже штатный systemctl restart, не говоря об обновлении с перезагрузкой, а их пропажу заметят не сразу. Как составить полную карту того, что реально крутится на малознакомом сервере, подробно разобрано в статье как понять, что крутится на чужом сервере — если сервер достался вам недавно и без документации, стоит пройти её целиком перед тем, как переходить к обновлению.
Результат инвентаризации — короткий список из 3-10 пунктов «что не должно сломаться»: сайт отвечает 200 на главной и на паре ключевых URL, API отдаёт корректный ответ на тестовый запрос, СУБД принимает подключения и отдаёт ожидаемые данные, крон-задачи, от которых зависит бизнес, продолжают запускаться. Этот список станет чек-листом, который вы будете прогонять после каждого шага ниже.
План поэтапного обновления: сначала патчи, потом версии по одной ступеньке
Вся стратегия строится на одном принципе: между двумя проверенными состояниями — минимальный набор изменений, а не максимальный. Практически это означает разделение на четыре последовательных этапа, каждый из которых заканчивается тестированием и, при необходимости, откатом именно этого этапа, а не всей работы.
Этап 1 — патчи безопасности внутри текущей версии, без смены мажорных релизов. Цель — закрыть самую горящую часть риска, ничего не меняя в архитектуре. На Debian/Ubuntu это установка только из security-репозитория, без апгрейда до новых мажорных версий пакетов:
sudo apt update
sudo apt list --upgradable | grep -i security
sudo unattended-upgrade --dry-run # посмотреть, что встанет, не применяя
sudo unattended-upgrade
На RHEL-подобных системах — аналогично, через фильтр по advisory:
sudo dnf updateinfo list security
sudo dnf update --security
Этап 2 — минорные обновления в пределах текущей мажорной версии. Здесь уже можно поднимать некритичный софт (утилиты, второстепенные библиотеки) до последних минорных релизов, оставляя ядро, СУБД и веб-сервер на месте до отдельного шага. Полезно держать критичные компоненты на паузе на время этого этапа:
sudo apt-mark hold linux-image-generic postgresql-14 nginx
sudo apt full-upgrade # обновит всё, кроме удержанных пакетов
Этап 3 — мажорные переходы, по одной ступеньке за раз. Если между установленной версией СУБД, языкового рантайма или самой ОС и актуальной — несколько мажорных релизов, проходите их последовательно: с 12 на 13, потом на 14, а не сразу на актуальную. У большинства проектов миграционные пути и changelog тестируются авторами именно на переход между соседними версиями — прыжок через несколько сразу может упереться в путь, который никто не проверял.
# пример: PostgreSQL, переход на одну версию вперёд
sudo apt install postgresql-13
sudo pg_upgradecluster 12 main
# проверка, тестирование — и только потом следующая ступенька на 14
Этап 4 — обновление ядра и перезагрузка отдельным, последним шагом. Новое ядро — самый рискованный элемент из всех: сетевые драйверы, схема именования интерфейсов и модули могут повести себя иначе на конкретном железе, а проверить это можно только после реальной перезагрузки. Именно поэтому ядро обновляется последним, когда остальная система уже стабилизирована на новых версиях, и делается это отдельным окном, с готовностью к тому, что сервер может не подняться с первого раза: забытые процессы вне автозапуска и правила, применённые «на лету» без сохранения в конфиг, всплывают именно на этом шаге.
| Этап | Что меняется | Типичный риск | Когда переходить дальше |
|---|---|---|---|
| 1. Security-патчи | Только патчи безопасности, версия та же | Минимальный | Сразу после теста сервисов |
| 2. Минорные версии | Некритичные пакеты до актуальных минорных релизов | Низкий-средний | После суток наблюдения |
| 3. Мажорные версии | СУБД/рантайм/ОС — по одной ступеньке | Высокий | После полного прогона чек-листа |
| 4. Ядро + перезагрузка | Новое ядро, реальный ребут | Высокий, специфичный | В отдельное окно, с готовым планом B |
Тестирование критичных сервисов после каждого этапа
Тестирование — не финальный аккорд после всей работы, а обязательный шаг между каждым из четырёх этапов выше. Пропуск теста после «маленького» этапа — самая частая причина, почему поэтапный план всё равно приводит к долгому разбору: проблема, внесённая на этапе 2, обнаруживается только на этапе 4, и тогда снова непонятно, что из трёх прошедших шагов виновато.
Минимальный прогон после каждого этапа занимает несколько минут и должен затрагивать список из инвентаризации, а не «на глаз всё вроде работает»:
# сервисы живы и не в состоянии failed
systemctl --failed
# ключевые эндпоинты отвечают ожидаемым кодом
curl -sfo /dev/null -w "%{http_code}\n" https://example.com/
curl -sfo /dev/null -w "%{http_code}\n" https://example.com/api/health
# СУБД принимает подключения и отдаёт разумный ответ
sudo -u postgres psql -c "select count(*) from key_table;"
# логи за последние минуты — на предмет новых ошибок, которых не было до этапа
sudo journalctl --since "10 min ago" -p err
Если после этапа что-то не проходит проверку — не переходите к следующему этапу, пока не разберётесь: либо чините найденное на месте, если причина ясна и локальна, либо откатываете именно этот этап (см. следующий раздел) и разбираетесь на копии, не блокируя весь план. Смешивать неразобранную проблему одного этапа с изменениями следующего — то, что превращает поэтапный план обратно в один большой неразбираемый ком.
Откат: что делать, если этап пошёл не так
Готовность к откату — не отдельная задача, а условие, без которого поэтапный план не работает: если откатывать нечего, «маленький шаг» ничем не лучше большого прыжка в момент, когда что-то сломалось.
Если перед этапом был снят снапшот на уровне гипервизора — откат самый быстрый и самый надёжный, потому что возвращает всё разом: пакеты, конфиги, данные.
sudo virsh snapshot-revert legacy-server pre-update-stage2 --running
Если снапшота нет, но версии пакетов были зафиксированы через apt-mark hold до этапа — откат на уровне пакетного менеджера возможен, если нужная версия ещё доступна в локальном кеше или репозитории:
sudo apt-get install --allow-downgrades nginx=1.24.0-2ubuntu7.3
sudo systemctl restart nginx
Отдельный и самый неприятный случай — если на этапе с мажорным переходом СУБД миграция схемы уже частично применилась. Откат бинарника приложения на старую версию здесь не поможет: старый код не понимает новую схему. Единственный надёжный путь — восстановление из дампа, снятого перед этим конкретным этапом (см. шаг 0), а не попытка вручную «дособрать» промежуточное состояние. Подробный разбор механики быстрого отката, включая диагностику по типу поломки и готовый runbook, — в статье обновление положило прод: как откатиться: логика там применима один в один к каждому отдельному этапу поэтапного обновления, а не только к обновлению целиком.
Практическое правило: если диагностика проблемы после этапа не даёт ясной картины за 10-15 минут — откатывайте этот этап и разбирайтесь на копии, не держа боевой сервис в неопределённом состоянии дольше, чем необходимо для решения «откатываем/чиним».
Что делать дальше, чтобы не оказаться здесь снова через три года
Одноразовый забег до актуального состояния решает проблему на сегодня, но не защищает от того, что через год-два сервер снова окажется настолько же отстал — если не появится регулярный цикл после того, как поэтапный план завершён.
Практический минимум на выходе из этой работы:
- Зафиксировать регламент, а не держать решение в голове. Что ставится сразу (security-патчи), что через паузу на созревание, что по отдельному плану с тестовым стендом — разбор такой градации есть в статье про регламент обновлений, и его стоит адаптировать под конкретный сервер, а не изобретать заново.
- Настроить автоматическую установку security-патчей, чтобы разрыв по критичным уязвимостям не накапливался между плановыми окнами, даже если на минорные и мажорные обновления не хватает времени регулярно.
- Не ставить непроверенные релизы день в день. Выдержанная пауза перед установкой обычных (не security) обновлений снижает риск словить чужой баг раньше остальных.
- Завести таблицу версий и дат конца поддержки для ключевого софта — ОС, СУБД, рантайм. Это не требует отдельной системы, достаточно строки в внутренней wiki с датой EOL и напоминанием за пару месяцев до неё.
- Держать снапшоты и зафиксированные версии как рутину, а не как то, что вспоминают только перед большим обновлением — тогда следующий плановый апдейт снова будет маленьким шагом, а не поводом для отдельной многодневной операции.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Сколько времени реально займёт весь план на трёхлетнем сервере?
Зависит от количества мажорных версий, которые нужно пройти, и от объёма данных для тестового прогона — счёт может идти от нескольких дней до нескольких недель календарного времени, если делать это без спешки и с полноценным тестированием между этапами. Пытаться уложиться в один вечер — как раз тот риск, которого план призван избежать.
Можно ли пропустить этап 2 (минорные обновления) и сразу перейти к мажорным версиям?
Не стоит: минорные обновления внутри текущей мажорной версии часто содержат исправления, на которые опирается сама процедура мажорного перехода (миграционные утилиты, инструменты проверки совместимости). Пропуск этого этапа увеличивает риск на следующем, самом дорогом шаге.
Что если тестового окружения нет и взять его негде?
Минимум — временный клон на другом VPS с тем же дистрибутивом и копией данных достаточного объёма, поднятый на несколько дней специально под эту задачу. Прогонять мажорные переходы прямо на проде без предварительной проверки — риск, который перечёркивает всю пользу от поэтапного плана.
Стоит ли отдавать такое обновление на аутсорс, если своей команды не хватает?
Да, если план требует специфичного опыта (например, мажорный переход СУБД с продовыми данными) и внутри команды такого опыта нет — цена ошибки на проде обычно выше стоимости разовой консультации специалиста, который такие переходы уже делал.
Что если сервер за три года без обновлений уже прошёл конец поддержки (EOL) своей версии ОС?
Тогда патчей безопасности для текущей версии больше не выйдет никогда, и поэтапный план внутри той же мажорной версии на этапе 1 не имеет смысла — переход на поддерживаемую версию ОС становится обязательным, а не одним из вариантов. Это меняет масштаб работы, но не саму логику: снапшот, инвентаризация, шаги по одной ступеньке, тесты между ними.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →