АйТи Фреш
Главная / Статьи / Серверы и хостинг
Серверы и хостинг

Обновили Dovecot с 2.3 до 2.4, и сервер не стартует: что именно надо переписать в конфиге

Автор: Семёнов Евгений Сергеевич, директор ООО «АйТи-Фреш» · · ~22 мин чтения
Обновили Dovecot с 2.3 до 2.4, и сервер не стартует: что именно надо переписать в конфиге
Иллюстрация к статье «Обновили Dovecot с 2.3 до 2.4, и сервер не стартует: что именно надо переписать в конфиге».

Это статья для того, кто уже нажал dist-upgrade на почтовом сервере и теперь смотрит на «dovecot.service: Failed with result exit-code» в три часа ночи, а также для того, кто пока не нажал и хочет пройти это без простоя. Dovecot 2.4 — не косметический апдейт: старый конфиг он не читает принципиально, а автоматического конвертера у проекта нет. Покажу, какие блоки переписываются механически за десять минут, какие требуют головы, что выкинули совсем, и разберу реальную миграцию небольшого офисного почтовика на 14 ящиков — с цифрами, ошибками и тем, чем всё закончилось.

Это не обновление пакета, это переезд

Разберёмся с главным заблуждением сразу. Обновление Dovecot с ветки 2.3 на 2.4 в голове администратора лежит рядом с обновлением nginx или Postfix: пакет прилетел, сервис перезапустился, всё работает. С Dovecot это не так. Проект переделал язык конфигурации целиком — не отдельные директивы, а структуру файла, синтаксис переменных, правила именования секций и логику плагинов. Старый dovecot.conf не деградирует до «работает с предупреждениями». Он не парсится. Сервис не поднимается, IMAP и POP3 отваливаются мгновенно, а если у вас через Dovecot LMTP заведена доставка от Postfix — почта начинает копиться в очереди, и вы об этом узнаёте не от мониторинга, а от директора.

Второе, что важно понимать: официальный гайд по переходу требует сначала обновиться до последнего выпуска ветки 2.3 и только потом идти на 2.4. Это не формальность. Часть настроек в поздних 2.3 уже переименована и помечена как deprecated, и вы получаете предупреждения в логах ещё на старой ветке — то есть бесплатный чек-лист того, что придётся править. Прыжок с условного 2.3.13 сразу на 2.4 лишает вас этой подсказки и превращает миграцию в угадайку.

Почему это стало массовой болью именно сейчас. Дистрибутивы дотянулись: Ubuntu 25.10 приехала уже с Dovecot 2.4, Debian 13 trixie тащит 2.4.1, а официальный репозиторий проекта раздаёт свежие выпуски ветки 2.4. То есть обычный планово-безопасный apt full-upgrade на давно живущем почтовике теперь по умолчанию ломает почту. Пакетный менеджер ваш конфиг не конвертирует и заботливо его сохранит — просто Dovecot откажется его читать.

И третье, о чём молчат в чейнджлогах: откат назад тоже не бесплатный. В ветке на Ubuntu Community Hub люди описывают ровно это — вернули пакеты 2.3, а сервис всё равно не стартует, потому что при обновлении поменялось не только содержимое /etc/dovecot. Спасает только восстановление каталога conf.d из бэкапа. Поэтому первое действие в этой истории — не читать документацию, а сделать копию /etc/dovecot целиком.

Автоматического конвертера конфигов 2.3 → 2.4 у проекта нет. Ни doveconf, ни пакетные скрипты вашу конфигурацию не перепишут. Это ручная работа на несколько часов — планируйте окно, а не «после обеда докачу».
Порядок действий: Это не обновление пакета, это переезд — схема
Порядок действий: Это не обновление пакета, это переезд. Открыть схему в полном размере

Две строки в начале файла, без которых не стартует ничего

Самая первая настройка в dovecot.conf теперь обязана быть dovecot_config_version. Не «желательно первой» — именно первой, до всех include и до любой другой директивы. Смысл простой: вы явно фиксируете, под какую версию синтаксиса написан ваш конфиг, и Dovecot при следующих обновлениях знает, как трактовать неоднозначные места, вместо того чтобы молча поменять поведение у вас под ногами. Значение — строка версии в том же формате, в котором нумеруются релизы Dovecot.

Вторая обязательная настройка — dovecot_storage_version. Она про другое: про формат файлов в хранилище. По документации это самая старая версия Dovecot, которая должна уметь прочитать файлы, записанные текущим инстансом. Механизм придуман для кластеров и будущих обновлений внутри 2.4: вы поднимаете значение только тогда, когда откат на предыдущий выпуск больше не нужен. Для переезда с 2.3 ставьте 2.4.0 — это стартовая точка новой ветки. Важно не обмануть себя: эта настройка не делает хранилище читаемым для 2.3, поэтому план Б при переезде с 2.3 — снапшот ВМ и бэкап индексов, а не магическая строка в конфиге.

Выглядит начало файла так:

# /etc/dovecot/dovecot.conf — ПЕРВЫЕ строки, до любых include
dovecot_config_version = 2.4.0

# формат хранилища: для переезда с 2.3 — стартовая версия ветки 2.4
dovecot_storage_version = 2.4.0

# протоколы в 2.4 по умолчанию пустые — перечисляем явно
protocols = imap lmtp

Ещё одна мелочь, которая ловит почти всех: в 2.4 настройка protocols по умолчанию пустая. В 2.3 у большинства сборок протоколы включались дистрибутивным конфигом, и вы про них не думали. Теперь, если явно не написать, что нужны imap, pop3 и lmtp, сервис поднимется совершенно здоровым, доволен собой, с чистым логом — и не будет слушать ничего. Диагностика на этом месте занимает больше времени, чем ошибка парсинга, потому что ошибки-то нет.

Прежде чем перезапускать сервис, я всегда прогоняю парсер вручную. doveconf -n показывает только настройки, отличающиеся от значений по умолчанию, и заодно валит все синтаксические ошибки с номером строки. doveconf -d выводит значения по умолчанию вместо настроенных — полезно, чтобы увидеть, что Dovecot 2.4 думает о protocols, listen или auth-worker, если вы их не задали. Сравнение двух выводов быстро показывает, какие из ваших старых привычек теперь совпадают с дефолтом и их можно просто удалить.

# синтаксис и ненулевые настройки — до рестарта
doveconf -n > /root/doveconf-24-n.txt && echo OK

# значения по умолчанию для конкретных настроек
doveconf -d protocols listen

# только после чистого вывода
systemctl restart dovecot && journalctl -u dovecot -n 50 --no-pager
dovecot_config_version должна быть буквально первой строкой конфигурации. Если она стоит после include или после безобидного listen — Dovecot ругнётся и не запустится, а сообщение об ошибке будет указывать не туда, куда вы ожидаете.
Обновили Dovecot с 2.3 до 2.4, и сервер не стартует: что именно надо переписать в конфиге — схема
Схема к статье. Открыть схему в полном размере

Механическая часть: SSL, listener, mail_location

Хорошая новость: примерно половина правок — это тупой поиск и замена, которую можно сделать за один заход. Начните с TLS. Все ssl-настройки получили префиксы, разделяющие серверную и клиентскую роль, и заодно перестали требовать хитрый синтаксис с угловой скобкой для чтения файла. То есть привычное ssl_cert = </etc/letsencrypt/... превращается в ssl_server_cert_file = /etc/letsencrypt/... — без <. Забыть убрать скобку — типовая ошибка первого запуска.

# было (2.3)
ssl = required
ssl_cert = </etc/letsencrypt/live/mail.example.ru/fullchain.pem
ssl_key  = </etc/letsencrypt/live/mail.example.ru/privkey.pem
ssl_ca   = </etc/ssl/certs/ca-bundle.crt
ssl_dh   = </etc/dovecot/dh.pem

# стало (2.4)
ssl = required
ssl_server_cert_file = /etc/letsencrypt/live/mail.example.ru/fullchain.pem
ssl_server_key_file  = /etc/letsencrypt/live/mail.example.ru/privkey.pem
ssl_server_ca_file   = /etc/ssl/certs/ca-bundle.crt
ssl_server_dh_file   = /etc/dovecot/dh.pem

Дальше — хранилище. Монолитная mail_location разобрана на отдельные настройки: отдельно драйвер, отдельно путь. Внутри namespace тоже поменялось: старая location превращается в пару mail_driver и mail_path. Здесь я советую не переносить конструкцию один в один, а заодно перечитать, что у вас в namespace вообще написано — за годы там часто накапливается мусор от давно снесённых shared-папок и публичных ящиков.

# было (2.3)
mail_location = maildir:~/Maildir

# стало (2.4)
mail_driver = maildir
mail_path = ~/Maildir
# ~ раскрывается в домашний каталог пользователя, эквивалент %{home}/Maildir

Третий механический кусок — сокеты и слушатели. Настройка address внутри inet_listener убрана, её роль забрала глобальная listen. Если у вас почтовик слушает только петлю и один внутренний адрес — это правка на две строки. Если у вас там были хитрости с разными адресами для разных сервисов — вот здесь придётся думать, и лучше сделать это на тестовом стенде, а не на боевом. И сразу отметьте себе: anvil больше не работает в chroot и запускается от root, а лимит процессов auth-worker поднят с 1 до 30 — если вы когда-то руками тюнили эти сервисы, ваши старые значения теперь либо избыточны, либо вредны.

Разделение ssl_ca на серверный и клиентский — не косметика. Если вы через Dovecot проксируете или ходите наружу (dict, LDAP по TLS, проксирование IMAP), CA для проверки чужих сертификатов теперь описывается отдельной настройкой, и слепая замена на ssl_server_ca_file сломает валидацию.
Памятка: Механическая часть: SSL, listener, mail_location — схема
Памятка: Механическая часть: SSL, listener, mail_location. Открыть схему в полном размере

Вдумчивая часть: passdb, userdb, SQL и %-переменные

Здесь начинается настоящая работа. Первое: секции passdb и userdb теперь обязаны иметь имя. Голый passdb { driver = sql } — синтаксическая ошибка. Надо passdb sql { ... } или любое другое осмысленное имя. Плюс сам драйвер SQL описывается иначе: соединение с базой выносится в отдельный именованный блок, а в passdb остаётся только запрос. Мне такая структура нравится больше старой, потому что одно подключение к MySQL теперь честно переиспользуется несколькими секциями, а не дублируется в трёх .ext-файлах с разъезжающимися паролями.

# было (2.3), dovecot-sql.conf.ext
driver = mysql
connect = host=127.0.0.1 dbname=mailserver user=mailserver password=пароль_из_сейфа
password_query = SELECT password FROM virtual_users WHERE email='%u'

# стало (2.4)
sql_driver = mysql

mysql 127.0.0.1 {
  user = mailserver
  password = пароль_из_сейфа
  dbname = mailserver
}

passdb sql {
  query = SELECT password, email AS user FROM virtual_users WHERE email='%{user}'
}

Второе и куда более коварное: все однобуквенные %-переменные удалены. Совсем. Вместо них — синтаксис с фигурными скобками и фильтрами через вертикальную черту. %u стал %{user}, %d — %{user | domain}, %n — %{user | username}, %Lu — %{user | lower}, %Mu — %{user | md5}. Проблема в том, что эти переменные разбросаны у вас не только в SQL-запросах: они сидят в путях к почте, в шаблонах логов, в конфигах sieve, в LDAP-фильтрах, в настройках квот. Я всегда прогоняю по всему /etc/dovecot grep вида grep -rnE '%[A-Za-z]' /etc/dovecot и правлю каждое совпадение осознанно, потому что автозамена тут делает больно: формально %h превращается в %{home}, но у многих в 2.3 путь строился из %d/%n, и после разбиения mail_location такие конструкции проще переписать заново, чем механически перевести.

Третье: checkpassword как бэкенд аутентификации выкинут. Если у вас была самописная обвязка на shell или Python, которая ходила в чужую базу или в API — её надо переписывать на Lua-аутентификацию. Это, честно говоря, самая дорогая часть миграции, если вы на checkpassword сидели. Если не сидели — вы даже не заметите. Отдельно порадуйтесь, что Lua-скрипт получается сильно быстрее: у меня на одном стенде среднее время аутентификации упало с 40–60 мс до единиц миллисекунд, просто потому что перестал форкаться внешний процесс на каждый логин.

Не делайте автозамену %-переменных скриптом. Ищите grep-ом и правьте руками, глядя на контекст: часть переменных сменила не только запись, но и смысл, а часть строк с процентом — вообще не переменные Dovecot, а форматы strftime в логах.

Секции plugin больше нет — и это ломается тише всего

Блок plugin { } удалён как класс. Все настройки плагинов стали обычными глобальными настройками — на одном уровне со всем остальным. И заодно многие из них переименованы: старая строка вида quota = maildir:User quota внутри plugin превращается в именованный блок quota "User quota" { driver = maildir } плюс отдельные настройки лимитов вроде quota_storage_size. Документация при этом рекомендует драйвер count, который считает квоту внутри индексов Dovecot. То же самое с sieve, с fts, с mail_log, с acl.

Почему я называю это самой тихой поломкой. Ошибка синтаксиса в SSL или в passdb честно валит сервис — вы увидите её через тридцать секунд после рестарта. А неправильно перенесённая квота даёт запустившийся, работающий, отвечающий на IMAP сервер, у которого просто выключены лимиты. Или наоборот — лимит применился не там, где вы думали. Об этом вы узнаете через неделю, когда ящик секретаря съест 400 ГБ, или когда пользователь пожалуется, что ему пишут «квота превышена» при пустом ящике. Поэтому после миграции квоты я проверяю явно, а не «на глаз»: doveadm quota get -u user@example.ru по десятку ящиков из разных доменов.

Сюда же — mail_plugins. Раньше это был список через пробел, теперь это блок. Порядок и состав плагинов стоит пересмотреть заодно: imap_zlib выкинут, потому что сжатие COMPRESS теперь работает автоматически; old_stats выкинут в пользу нового механизма статистики; fts_lucene и fts_squat удалены целиком. Если у вас на fts_lucene висел полнотекстовый поиск по ящикам — это отдельный проект по переезду на Solr или на flatcurve, и его надо планировать до обновления, а не после.

# 2.4: плагины — блок, квота — именованная секция
mail_plugins {
  quota = yes
}
protocol imap {
  mail_plugins {
    imap_quota = yes
  }
}

quota_storage_size = 10G
quota "User quota" {
  driver = count
}

И глобальные ACL-каталоги (тот самый /etc/dovecot/acls/) объявлены устаревшими. Права теперь описываются инлайн, внутри блоков mailbox. Синтаксис читаемее, но перенос ручной — файлов в каталоге обычно немного, а вот проверить результат надо обязательно, потому что молча потерянные права на shared-папки в компании обнаруживаются очень громко.

После первого успешного старта на 2.4 обязательно проверьте квоты, ACL на общих папках и работу sieve-правил. Именно эти три вещи мигрируют «успешно» с точки зрения парсера и при этом полностью нерабочими с точки зрения бизнеса.

Что выкинули совсем: проверьте до окна обновления

Часть функциональности из community-версии убрали, и никакой правкой конфига это не лечится. Список короткий, но если вы в него попадаете — обновление превращается из ночной работы в проект на пару недель. Пробегитесь по нему до того, как трогать пакеты.

Отдельно про dsync. Команда dsync как самостоятельный бинарник удалена, её функции живут в doveadm sync. Функционально ничего не потеряно, но у половины админов dsync зашит в скрипты бэкапа и миграции ящиков, и эти скрипты после обновления молча возвращают ненулевой код возврата в cron, а cron молча пишет в почту, которую никто не читает. Проверьте свой /etc/cron.d и /usr/local/bin на предмет вызовов dsync до, а не после.

Самое болезненное — director. Механизм балансировки IMAP-сессий по нодам в community-редакции 2.4 отсутствует, его место в коммерческой линейке занял другой продукт. Если у вас кластер из нескольких почтовых нод за балансировщиком и общий NFS — вы не можете просто обновиться. Вам нужно либо оставаться на 2.3 и планировать другую архитектуру, либо переходить на закрепление сессий средствами балансировщика по source IP и логину, что для больших инсталляций работает хуже. Это, пожалуй, единственное место, где я честно говорю клиенту: спешить некуда, ветка 2.3 ещё живёт, планируйте на следующий год.

Если ваш почтовик — кластер с director, обновление на 2.4 CE сейчас не ваш сценарий. Это не «сложно», это «нет такой функции». Не начинайте миграцию, пока не решён вопрос с балансировкой сессий.

Как это выглядело у дизайн-студии «Планировка»: 14 ящиков, окно 3 часа

Дизайн-студия интерьеров «Планировка», 12 рабочих мест, свой небольшой почтовый сервер на виртуалке: Debian 12, Postfix 3.7 + Dovecot 2.3.19 из штатного репозитория, виртуальные пользователи в MySQL, maildir на отдельном LVM-томе, 14 ящиков (сотрудники плюс общие info@ и projects@), суммарно около 180 ГБ почты — дизайнеры годами пересылают друг другу визуализации и планы в вложениях. Веб-почта Roundcube, доставка от Postfix в Dovecot через LMTP-сокет. Обычная инсталляция, которую собрали несколько лет назад и с тех пор почти не трогали. Задача пришла как «обновите нам ОС до Debian 13, хотим свежие патчи». То есть Dovecot 2.4.1 приезжал бонусом, о котором клиент даже не подозревал.

Порядок, которым я это делал. Сначала клон боевой ВМ в изолированную сеть — на нём и происходило всё интересное. На клоне обновился до последнего 2.3, собрал предупреждения из лога, потом ушёл на 2.4.1 и два с половиной часа переписывал конфиг с нуля, глядя в старый как в справочник, а не копируя из него. Именно так, с чистого листа на базе нового примерного конфига — потому что попытка «поправить старый файл» на первом заходе съела у меня час и закончилась мусором. Только когда doveconf -n на клоне отдал осмысленный вывод и Thunderbird с телефоном зашли по IMAP, я начал планировать боевое окно.

Что сломалось на боевом, несмотря на прогон на клоне. Первое — sieve-правила у четырёх сотрудников, в том числе у руководителя проектов: в шаблоне пути к скриптам жил %u, который я на клоне не заметил, потому что пользовательские sieve-скрипты туда не скопировал. Правила молча перестали раскладывать письма подрядчиков и поставщиков мебели по папкам, и обнаружилось это утром по звонку офис-менеджера. Второе — Postfix продолжал стучаться в LMTP по старому пути сокета, потому что в 2.4 я переименовал сервис в конфиге, а в main.cf не поправил. Очередь Postfix за 20 минут набрала около 60 писем, все доставились после правки, ничего не потерялось, но нервы это стоило.

Итог: боевое окно заняло 2 часа 50 минут вместо запланированных двух, из них около часа — разбор двух описанных косяков. Простой IMAP для сотрудников — 25 минут в интервале с 23:40 до 00:05, внешняя почта не терялась, потому что Postfix честно держал очередь. Снапшот ВМ до обновления хранили две недели как план отката и удалили только после стабильной работы. Вывод, который я забрал себе на все следующие такие переезды: клон должен включать не только конфиг, но и несколько реальных ящиков с sieve-скриптами и общими папками — иначе вы тестируете не свою систему, а её упрощённую модель.

Держите Postfix и Dovecot в одном окне работ. Половина «пропавшей почты» при таких переездах — это не Dovecot, а несовпадение путей LMTP-сокета и SASL-сокета в main.cf и master.cf Postfix, которое всплывает только под нагрузкой.
Порядок действий: Как это выглядело у дизайн-студии «Планировка»: 14 ящиков, окно 3 часа — схема
Порядок действий: Как это выглядело у дизайн-студии «Планировка»: 14 ящиков, окно 3 часа. Открыть схему в полном размере

Частые вопросы

Можно ли как-то автоматически сконвертировать конфиг 2.3 в 2.4?

Нет. Официального конвертера у проекта нет, пакетные скрипты дистрибутивов конфиг не трогают. Есть только официальный пример конфигурации, один раз переведённый разработчиками на синтаксис 2.4 — от него и пляшите. Я рекомендую писать конфиг заново на базе нового примера, а старый держать открытым рядом как справочник: попытка отредактировать старый файл на месте почти всегда заканчивается смесью двух синтаксисов и потерянным вечером.

Какое значение ставить в dovecot_storage_version?

Это строка версии в том же формате, что и релизы Dovecot, и означает она самую старую версию, которая должна уметь прочитать файлы, записанные вашим сервером. При переезде с 2.3 ставлю 2.4.0 — это стартовая точка ветки. Повышать значение имеет смысл при следующих обновлениях внутри 2.4, когда откат на предыдущий выпуск уже не нужен. Возможность вернуться на 2.3 эта настройка не гарантирует: на время миграции держите снапшот ВМ и копию /etc/dovecot.

Сервис запустился без ошибок, но клиенты не подключаются. Что смотреть?

В первую очередь настройку protocols: в 2.4 её значение по умолчанию пустое, и без явного перечисления imap, pop3, lmtp сервис поднимается, но ничего не слушает. Ошибок в логе при этом нет вообще. Проверяйте `doveconf -n | grep -i protocols` и `ss -ltnp | grep dovecot`. Вторая по частоте причина — переехавший синтаксис слушателей: address внутри inet_listener убран, его роль забрала глобальная настройка listen.

У нас кластер с director. Что делать?

Оставаться на 2.3 и планировать архитектуру отдельно. Director в community-редакции 2.4 отсутствует, его заменили коммерческим продуктом. Обходной путь — закрепление сессий на балансировщике по логину или source IP, но для крупных инсталляций с общим хранилищем это заметно хуже по поведению индексов. Это тот редкий случай, когда я советую не торопиться с обновлением: ветка 2.3 ещё поддерживается, а сломать работающий кластер ради версии — плохая сделка.

Сколько времени закладывать на миграцию?

На типовом почтовике до 50–100 ящиков с виртуальными пользователями в SQL: 3–4 часа на переписывание конфига и прогон на клоне, плюс боевое окно 2–4 часа. Простой самого IMAP при аккуратной подготовке укладывается в 20–30 минут. Внешняя почта при этом не теряется — Postfix держит очередь и доставит всё после того, как Dovecot поднимется. Если у вас checkpassword или fts-lucene, закладывайте не часы, а недели: это отдельные проекты по переписыванию.

Что проверить сразу после успешного старта на 2.4?

Мой короткий список: логин по IMAP и POP3 с реального клиента, доставка тестового письма снаружи через LMTP, `doveadm quota get` по нескольким ящикам из разных доменов, права на общих папках, работа пользовательских sieve-правил и вызовы doveadm/dsync в cron-скриптах бэкапа. Именно квоты, ACL и sieve мигрируют «успешно» с точки зрения парсера и при этом могут быть полностью нерабочими.

Столкнулись с похожей задачей? Обращайтесь — решим

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

Возьмёмся и за разовую задачу, и за постоянное обслуживание. Первичная консультация — бесплатно и без обязательств.

📞 +7 903 729-62-41 💬 MAX: +7 903 729-62-41 ✈ Telegram @ITfresh_Boss

С уважением, Семёнов Евгений Сергеевич, директор «АйТи Фреш» — IT-аутсорсинг для компаний до 50 рабочих мест, 15+ лет практики

Источники

© ООО «АйТи-Фреш» · Москва · Все статьи