dkayumov.ru
Все статьи журнала
RCA · инфраструктура9 мин чтения

RCA. 12 минут даунтайма почты после apt purge dovecot-sieve и 3 шага, которые спасли бы заранее

Команда apt purge dovecot-sieve казалась безопасной. Через 14 секунд почта не работала. Через 12 минут я её вернул из бэкапа в 03:00 ночи. RCA, который я устроил себе сам.

RCALinuxDovecotинфраструктура

Что случилось

В апреле я чистил техдолг на собственном VPS. Сносил два пакета Dovecot, которыми не пользуюсь. Команда apt purge dovecot-sieve dovecot-managesieved казалась безопасной. Через несколько секунд почта легла. Через 12 минут я поднял её из ночного бэкапа в 03:00.

Это RCA, который я устроил себе сам. Для всех, кто думает, что apt purge без --dry-run на проде сойдёт с рук. И для CIO, у которого схожий боевой стек на Debian.

Контекст

VPS у Timeweb, Debian 13, multi-tenant. На нём живёт почта и сайт действующего бизнеса, плюс мои личные проекты. Не песочница, а прод с живыми пользователями. Я веду этот сервер сам, чтобы не терять hands-on.

Стек на момент инцидента: Postfix 3.10, Dovecot 2.4, Rspamd, Roundcube. Бэкап ежедневный, в 03:00, через собственный full_backup.sh по таймеру systemd. В архив идут /etc, /var/vmail и дамп MariaDB. Год назад настроил и забыл. Этот «забыл» меня и спас.

Зашёл я в 02:30, закрыть один пункт техдолга. Sieve-фильтры на этом сервере не используются, вся фильтрация на Rspamd. Логика была простой. Нет пакетов, нет лишней поверхности атаки.

Команда, которая всё сломала

bash
apt purge dovecot-sieve dovecot-managesieved

Я набрал её на автопилоте. В голове держал зависимость задом наперёд. Думал, dovecot-sieve это изолированный аддон поверх ядра, снести и забыть. На Dovecot 2.4 в Debian 13 всё ровно наоборот. Это dovecot-core объявляет Depends: dovecot-sieve. Ядро держится на sieve, а не sieve на ядре.

bash
apt-cache depends dovecot-core | grep -i sieve # Depends: dovecot-sieve

Удалить sieve, не тронув core, нельзя по определению зависимости. А раз уходит core, за ним каскадом летят dovecot-imapd, dovecot-lmtpd и dovecot-mysql. Голый purge двух названных пакетов утащил шесть. И добил конфиг. purge сносит не только бинарники, но и conffiles, а conffile ядра это /etc/dovecot/dovecot.conf, главный файл почты. Не сброс на дефолт, а стёртый с диска файл.

Подтверждение APT я прокликал бегло. Глаз поймал короткий sieve, а в списке «The following packages will be REMOVED» стояло шесть строк, и среди них dovecot-core. Нажал Y. Команда сделала ровно то, что я сказал. Я неверно понимал, что именно говорю.

Полная хронология

ВремяСобытиеИсточник
02:48:50Запустил apt purge -y dovecot-sieve dovecot-managesieved. Нажал Y без вдумчивого чтения списка.apt history.log
02:49:00APT удалил шесть пакетов: dovecot-core, dovecot-imapd, dovecot-lmtpd, dovecot-mysql, dovecot-sieve, dovecot-managesieved. /etc/dovecot/dovecot.conf стёрт с диска. Dovecot перестал слушать 143/993/110/995.apt history.log + journalctl
02:49:10Прочитал /var/log/apt/history.log. Шесть пакетов в строке Purge, не два. Решил восстанавливаться из daily-backup от 03:00 прошлой ночи. RPO 24 часа, для личного проекта допустимо.apt history.log
02:49:30apt install dovecot-core dovecot-imapd dovecot-lmtpd. Пакеты вернулись, лёг дефолтный dovecot.conf.apt history.log
02:52Распаковал бэкап в /tmp/restore/. Заметил, что dovecot-mysql не вернулся. Без него Dovecot не достучится до ящиков в MariaDB.tar log
02:53:38apt install dovecot-mysql. Отдельным шагом вернул драйвер userdb/passdb для MariaDB.apt history.log
02:58Скопировал /etc/dovecot/ из бэкапа поверх дефолтного. Вернул рабочий конфиг.tar log
02:59doveconf -n показал валидный конфиг без ошибок. systemctl start dovecot.journalctl
03:00Dovecot слушает 143/993, MySQL-userdb отвечает. Открыл Mail.app, почта пришла.Mail.app
03:00:50Полная функциональность восстановлена. 12 минут от точки отказа.

Восстановление по шагам

bash
# 1. Распаковка бэкапа в безопасное место mkdir -p /tmp/restore && cd /tmp/restore tar -xzf /root/backups/site_2026-04-23_0300.tar.gz # 2. Переустановка пакетов (поставит дефолтный dovecot.conf) apt install -y dovecot-core dovecot-imapd dovecot-lmtpd apt install -y dovecot-mysql # драйвер MariaDB — отдельным пакетом # 3. Свой конфиг из бэкапа ПОВЕРХ дефолтного cp -r /tmp/restore/etc/dovecot/ /etc/ # 4. Проверка конфига до старта doveconf -n >/dev/null || { echo "Config broken, abort"; exit 1; } # 5. Старт systemctl start dovecot && systemctl status dovecot # 6. Smoke test — IMAP-логин openssl s_client -connect localhost:993 -quiet <<< "A001 LOGIN user pass"

Два нюанса, на которых легко получить вторичный фейл.

Драйвер MySQL ставится отдельно. Первый apt install вернул ядро и порты, но не dovecot-mysql. А логины ящиков лежат в MariaDB. Запусти я сервис тогда, порты бы открылись, но ни один ящик не залогинился бы. Драйвер доставил вторым заходом.

Порядок не косметика. Сначала apt install с дефолтным конфигом, и только потом конфиг из бэкапа поверх. Наоборот нельзя, dpkg упрётся в уже лежащий файл и либо задаст conffile-вопрос, либо перетрёт восстановленный конфиг дефолтным. И обязательно doveconf -n перед стартом. На смене минорной версии синтаксис местами уезжает, а doveconf -n падает с ненулевым кодом на незнакомом параметре. У меня расхождений не было, но проверка стоит секунду.

RCA. Почему так получилось

Корневая причина. Я выполнил apt purge на проде без --dry-run и без снапшота conffiles. Дальше три фактора, которые сошлись.

Усталость. 02:48 ночи. Концентрация ниже дневной. Подтверждение APT прокликал не глядя.

Зависимость задом наперёд. Считал sieve аддоном поверх ядра. На деле ядро держится на sieve, и снос двух пакетов по Depends-цепочке утащил шесть. Никакого autoremove для этого не нужно, хватило прямой обязательной зависимости core → sieve.

Нет процесса. На клиентских серверах у меня чек-лист на деструктивные операции есть и обязателен. На своём VPS его почему-то не было. Сделай я ту же операцию у клиента, чек-лист бы сработал. То, что я наступил на грабли дома, а не на проде клиента, по сути везение. Урок стоил 12 минут моей почты, а не доверия.

3 шага, которые не дали бы этому случиться

1. apt-get purge --dry-run

bash
apt-get purge --dry-run dovecot-sieve dovecot-managesieved

Весь мой инцидент закрывается этим одним шагом. Сухой прогон с тем же набором пакетов вывел бы шесть строк в REMOVED и dovecot-core среди них. Тридцать секунд чтения вместо нажатого вслепую Y. Если в списке только целевые пакеты, идём дальше. Если APT тянет что-то ещё, особенно -core или -common, стоп. Гасим функционал через config или systemctl disable, оставив пакет на месте.

2. Снапшот conffiles перед операцией

bash
tar -czf /root/backups/dovecot-conffiles-$(date +%F-%H%M).tar.gz \ $(dpkg-query -W -f='${Conffiles}\n' dovecot-* | awk '{print $1}')

Две-три секунды, меньше 100 КБ. Страховка на случай, если --dry-run чего-то не показал.

3. Постфактум smoke test

bash
ss -tlnp | grep -E ':(143|993|110|995)\b' # слушает ли Dovecot openssl s_client -connect localhost:993 -quiet <<< 'A1 LOGIN x x' # принимает ли логин echo "Subject: test" | sendmail me@example.ru && tail /var/log/mail.log # доставка

30–60 секунд проверки против 12 минут восстановления и ночного пробуждения.

Что записал в свои правила

У меня для каждого проекта есть файл CLAUDE.md с правилами для AI-ассистента (Claude Code). Веду его около двух лет, вношу всё, на чём обжёгся. После этого инцидента добавился блок:

Тот же файл я отдаю командам клиентов, у которых внедряю AI-ассистента в инженерные процессы. Ассистент с таким правилом не запустит apt purge на проде без --dry-run. А если инженер про протокол забыл, напоминает за него.

Для кого это важно

Если у вас прод на Debian или Ubuntu, этот класс рисков ваш. Любая apt на хосте под нагрузкой может стоить минут даунтайма. Особенно ночью, когда инженер устал и отвлекается на телефон.

Если за инфраструктуру у вас отвечает vCIO, у вас должна быть уверенность, что такой протокол у него прописан. Свой CLAUDE.md я отдаю каждому клиенту целиком, без купюр. Больше тысячи строк, выработанных за два года практики.

Если хотите ещё скучных инфраструктурных разборов с реальными командами и реальным ущербом, загляните в журнал. Про методологию аудита писал в записи про карту ИТ-зрелости.

Первый разговор

Я работаю с этим напрямую — ознакомительный звонок 30 минут

Расскажете ситуацию — отвечу за 4 часа в рабочее время. Звонок бесплатный, без обязательств. Если задача не моя — порекомендую коллег, у которых она хорошо ляжет.

Мы используем cookies для анализа, как вы пользуетесь сайтом, и создания других удобств на сайте.