mailcow restore: ящики пустые, хотя место занято
АйТи Фреш
Linux, Docker и DevOps

Восстановили mailcow — ящики пустые в SOGo и Thunderbird, хотя место на диске занято

Автор: , директор ООО «АйТи-Фреш» · · ~15 мин чтения
После восстановления mailcow Dovecot ищет письма не в том подкаталоге тома — ящики выглядят пустыми, хотя файлы на месте
Письма никуда не делись — Dovecot просто смотрит не в ту полку.

Restore mailcow прошёл без ошибок, диск показывает те же гигабайты, что и до аварии, а сотрудники видят пустые папки. Прежде чем паниковать и запускать восстановление заново — сначала проверьте один параметр в mailcow.conf. В девяти случаях из десяти письма никуда не делись, Dovecot просто ищет их не в том подкаталоге.

Симптом: диск занят, а в почте пусто

«Оттиск Мастер» — производство печатей и штампов на 27 рабочих мест, почта на mailcow: заказы от типографий-партнёров, переписка с дизайнерами макетов, обращения клиентов с эскизами оттисков во вложениях. Мы обслуживаем их корпоративную почту, и в феврале у хостера случился отказ диска на исходной ВМ. Восстанавливали на новом сервере из штатного бэкапа mailcow — backup_and_restore.sh restore отработал без единой ошибки, все компоненты выбраны, лог чистый.

Первая проверка после восстановления — обычно du -sh по тому с почтой, и она обманчиво успокаивает: том vmail-vol-1 занимал ровно столько же места, сколько занимал до аварии, с точностью до мегабайта. Значит, физически файлы писем скопировались все. Но когда бухгалтер открыла SOGo проверить старый счёт от поставщика бумаги — папка «Входящие» была пустой. Та же картина в Thunderbird у остальных сотрудников: аккаунт подключается, авторизация проходит, а писем ноль.

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

Не удаляйте и не переинициализируйте том с почтой, если restore прошёл без ошибок, но письма не видны. В подавляющем большинстве случаев это конфигурационная, а не физическая потеря.
Схема несовпадения MAILDIR_SUB: письма лежат в корне тома, а Dovecot после restore ищет их в подкаталоге Maildir
Несовпадение одного параметра — и Dovecot смотрит мимо реальных файлов писем.

Матчасть: что такое MAILDIR_SUB и почему он решает всё

Dovecot в mailcow ищет письма ящика по пути /var/vmail/<домен>/<пользователь>/, к которому добавляется подкаталог из параметра MAILDIR_SUB в mailcow.conf — это видно прямо в userdb-запросе, который собирает docker-entrypoint.sh контейнера dovecot-mailcow. Документация формулирует это без обиняков: Dovecot загружает письма из указанного подкаталога тома mailcowdockerized_vmail-vol-1, и если этот параметр отличается от исходного состояния — писем в интерфейсе не будет вообще, при этом сами файлы никуда не денутся с диска.

Проблема в том, что на старых установках mailcow этот параметр был пустым или отсутствовал — то есть Dovecot искал письма прямо в каталоге ящика. А свежая установка получает его от generate_config.sh уже заполненным: скрипт пишет в новый mailcow.conf строку MAILDIR_SUB=Maildir. Формально это просто путь. Практически — если на исходном сервере параметра не было (пустое значение), а на новом он появился как Maildir, Dovecot после restore будет упорно смотреть в .../Maildir/, а все реальные файлы писем так и остались лежать уровнем выше.

Официальная документация именно поэтому выносит предупреждение отдельным блоком с заголовком «Danger for older installations» — то есть разработчики знают об этой ловушке и явно предупреждают о ней до того, как вы нажмёте restore, а не после. Проблема в том, что предупреждение читают не все, особенно когда восстановление делается в спешке посреди инцидента, как это было у «Оттиск Мастера» — сервер лежал, клиенты ждали, читать changelog построчно было не до того.

Документация mailcow прямо предупреждает об этом перед restore на новый сервер — но предупреждение легко пропустить в разгар инцидента. Проверяйте MAILDIR_SUB до восстановления, а не после.

Как проверить и починить: сравнение старого и нового mailcow.conf

Первым делом я поднял архивную копию mailcow.conf с упавшего сервера (она у нас всегда лежит отдельно от самого бэкапа, в рамках регламента резервного копирования) и сравнил значение параметра построчно с новым конфигом:

grep MAILDIR_SUB /path/to/old-backup/mailcow.conf
grep MAILDIR_SUB mailcow.conf

У «Оттиск Мастера» старый конфиг вообще не содержал строки MAILDIR_SUB — параметр отсутствовал полностью, то есть письма изначально лежали в корне тома. Новый конфиг после развёртывания на чистом сервере содержал MAILDIR_SUB=Maildir — generate_config.sh ставит это значение всем новым установкам. Ровно то расхождение, которое документация называет главной опасностью восстановления на старых инсталляциях: если в исходной установке значение не задано, в новой конфигурации его нужно либо не задавать вообще, либо явно удалить, если оно там уже появилось.

Правка простая — закомментировать или удалить строку MAILDIR_SUB=Maildir в mailcow.conf, затем пересоздать контейнер dovecot: docker compose up -d dovecot-mailcow. Проверка заняла минуту: после пересоздания контейнера обновил страницу SOGo — вся переписка на месте, письма от февраля и раньше видны с правильными датами. Старые файлы трогать не пришлось. Но была одна тонкость, о которой почти не пишут: за три часа между restore и правкой на сервер пришло около сорока новых писем, и Dovecot честно сложил их в новый подкаталог Maildir/ — после возврата пустого значения они «пропали» уже из интерфейса. В треде «Cannot access old/migrated mails» описан ровно этот эффект наоборот: новые письма видны, старые нет. Эти письма я перенёс вручную из Maildir/cur и Maildir/new в соответствующие каталоги ящика с сохранением владельца vmail и потом выполнил docker compose exec dovecot-mailcow doveadm force-resync -u user@example.com '*' по каждому затронутому ящику.

Держите архивную копию mailcow.conf отдельно от самого бэкапа почты — на форумах регулярно всплывают случаи, когда именно конфиг терялся вместе с упавшим сервером, и сравнивать восстановленный MAILDIR_SUB было не с чем.
Пошаговый чек-лист проверки параметра MAILDIR_SUB до и после восстановления mailcow
Пять шагов и одна команда — быстрее, чем повторный запуск restore с нуля.

Это не единичный случай: два похожих разбора с форума mailcow

История «Оттиск Мастера» не уникальна — в официальном сообществе mailcow есть минимум два независимых разбора с тем же корнем проблемы. В обсуждении «Issue after migration» администратор столкнулся с точно такой же картиной: письма физически на месте, но невидимы после переноса на новый сервер. Разбор показал ту же причину — несовпадение MAILDIR_SUB, у старой установки пустое значение, у новой — Maildir; возврат к пустому значению вернул письма в интерфейс.

Второй тред, «Cannot access old/migrated mails», независимо подтверждает тот же симптом и то же решение на другой инсталляции — то есть это не разовый баг конкретной версии, а системная ловушка самого механизма восстановления, о которой явно предупреждает официальная документация именно потому, что она воспроизводится у разных людей на разных серверах. Официальная документация по миграции (docs.mailcow.email/maintenance/migration/) отдельно рекомендует переносить mailcow.conf со старого сервера на новый как есть, а не создавать его заново с нуля — это исключает саму возможность расхождения MAILDIR_SUB.

Практический вывод для восстановления после аварии, когда старого сервера уже физически нет: если у вас сохранилась хотя бы копия mailcow.conf (в бэкапе, в git, в архиве настроек) — переносите его значения, а не полагайтесь на значения по умолчанию свежей установки. Если копии конфига нет вообще — это повод в первую очередь проверить, действительно ли на диске лежит Maildir/ как подкаталог, командой docker compose exec dovecot-mailcow ls -la /var/vmail/domain.ru/user/ и сверить с фактической структурой, прежде чем менять параметр вслепую.

Если ваш случай не совпадает буквально — папки пустые, но занятого места вообще не прибавилось после restore — это, скорее всего, другая проблема: смотрите на шифрование почты (mail_crypt) или на служебные файлы Dovecot, об этом ниже.

Как правильно выполнить restore, чтобы не попасть в эту ловушку

Штатная процедура восстановления в mailcow запускается на уже поднятой и пустой инсталляции: ./helper-scripts/backup_and_restore.sh restore, дальше скрипт интерактивно просит путь к бэкапам (/opt/backup, например), показывает список найденных точек восстановления с датами и позволяет выбрать, какие компоненты восстанавливать — весь бэкап целиком или отдельные части: Crypt data, Rspamd data, каталог почты, Redis, Postfix, SQL. Для полного восстановления после аварии я всегда беру пункт «all», а не собираю восстановление по частям вручную — риск забыть компонент и получить рассинхронизацию между базой и файлами выше, чем экономия времени.

Отдельный нюанс, о котором нужно знать заранее: если бэкап делался на одной архитектуре процессора (например, x86), а восстанавливаете вы на другой (ARM64), скрипт сам обнаружит несовместимость и предложит пропустить восстановление данных Rspamd — это ожидаемое поведение, а не ошибка, и Rspamd просто соберёт свою статистику заново с нуля.

И последнее правило, которое я довёл до автоматизма после кейса «Оттиск Мастера»: перед восстановлением на новом сервере я сначала поднимаю пустой mailcow тем же способом, что и исходный (docker compose up -d), и только потом запускаю restore поверх него, предварительно скопировав mailcow.conf со старого сервера или сверив вручную ключевые параметры — MAILDIR_SUB в их числе, но не единственный. Это на порядок надёжнее, чем чинить расхождения постфактум по жалобам сотрудников.

Отдельно фиксирую в регламенте обслуживания клиента, где именно лежит архивная копия mailcow.conf и с какой периодичностью она обновляется — после каждого изменения конфигурации вручную, не по расписанию раз в месяц. Для «Оттиск Мастера» мы сейчас храним копию конфига в зашифрованном приватном репозитории отдельно от бэкапов почты и от самого сервера mailcow, именно чтобы не оказаться в ситуации «сервер упал, бэкап почты есть, а сверить MAILDIR_SUB не с чем».

Тестовое восстановление на отдельной ВМ раз в квартал — единственный способ узнать про такие ловушки заранее, а не во время реального инцидента с клиентом на линии.
Дерево диагностики трёх разных причин пустых или нечитаемых почтовых ящиков в mailcow
Три похожих на вид симптома — три разные причины и три разных решения.

Когда причина другая: не путайте с шифрованием и служебными файлами

MAILDIR_SUB — не единственная причина «пустых» ящиков после операций с почтовым хранилищем mailcow, и важно уметь отличить её от двух похожих на первый взгляд, но совсем других по природе проблем. Первая — шифрование писем через mail_crypt. Если на исходном сервере оно было включено, простое копирование файлов vmail без соответствующих EC-ключей делает содержимое писем нечитаемым в принципе, а не невидимым — это принципиально другая история, я разбирал её отдельно в тексте про архив vmail и ключи шифрования. Отличить один случай от другого просто: при проблеме с MAILDIR_SUB письма после правки конфига появляются мгновенно и полностью читаемы; при отсутствующих ключах шифрования doveadm и клиенты будут либо давать ошибку доступа, либо показывать нечитаемую кашу вместо текста.

Вторая соседняя история — повреждённые или удалённые служебные файлы Dovecot вроде dovecot-uidlist и dovecot-keywords. Это не про restore mailcow, а про ситуацию, когда служебные файлы конкретной папки стёрты или испорчены руками администратора или сторонним скриптом резервного копирования, который случайно задел служебные файлы вместе с письмами. В таком случае папка не пустая, но клиенты перекачивают всю почту заново и теряют метки прочитанности — симптом внешне похож на «сломанную почту после операции», но причина и лечение другие, там всё описано в разборе про служебные файлы Dovecot.

Практическое правило разделения для дежурного администратора: если это именно restore на новый сервер и папки пусты полностью — сначала MAILDIR_SUB. Если папки читаются наполовину криво, часть писем в порядке, а часть выдаёт ошибки — смотрите на ключи шифрования. Если ни restore, ни миграции не было, а «сломалось само» после ручной чистки диска — это, скорее всего, повреждённые control-файлы Dovecot, а не MAILDIR_SUB. На практике первый вопрос, который я задаю дежурному инженеру перед тем как открывать конфиг: было ли восстановление или перенос на новый сервер в последние сутки. Если да — MAILDIR_SUB проверяется раньше любых других гипотез, потому что стоит один grep и не требует прав на изменение чего-либо, кроме одной строки конфига.

Не смешивайте эти три случая в одном тикете поддержки. Правильный диагноз за одну минуту экономит часы неправильного восстановления.

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

После восстановления mailcow ящики пустые, но место на диске занято — письма потеряны?

Скорее всего нет. Это классический симптом несовпадения параметра MAILDIR_SUB в mailcow.conf между старой и новой установкой: Dovecot ищет письма в другом подкаталоге тома vmail-vol-1, чем там, где они физически лежат. Сравните MAILDIR_SUB в старом и новом конфиге и приведите к одному значению.

Что такое MAILDIR_SUB в mailcow.conf?

Параметр, задающий подкаталог внутри тома vmail-vol-1, откуда Dovecot загружает письма. Если он не задан — Dovecot ищет прямо в каталоге ящика /var/vmail/<домен>/<пользователь>/. Если задан, например, как Maildir — ищет только в этом подкаталоге. Несовпадение значения между старой и новой установкой после restore делает письма невидимыми в интерфейсе при том, что файлы остаются на диске.

Как проверить MAILDIR_SUB перед восстановлением на новом сервере?

Сравните значение в архивной копии mailcow.conf со старого сервера и в конфиге новой установки: grep MAILDIR_SUB mailcow.conf для обоих файлов. Если в старом параметр отсутствовал — не задавайте его и в новом (или удалите, если он там появился по умолчанию), затем пересоздайте контейнер dovecot-mailcow.

Чем проблема с MAILDIR_SUB отличается от потери писем из-за шифрования mail_crypt?

При несовпадении MAILDIR_SUB письма после правки конфига появляются мгновенно и полностью читаемы — файлы были на месте, менялся только путь поиска. При отсутствии ключей шифрования mail_crypt письма либо не открываются вовсе, либо отображаются нечитаемой кашей — это проблема доступа к содержимому, а не пути к файлам, и лечится она иначе.

Нужно ли пересоздавать индекс или базу данных после правки MAILDIR_SUB?

Нет, в типовом случае достаточно поправить значение в mailcow.conf и выполнить docker compose up -d dovecot-mailcow, чтобы контейнер Dovecot переподхватил конфигурацию. Файлы писем при этом не трогаются и не переиндексируются принудительно — Dovecot просто начинает смотреть в правильный подкаталог.

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

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

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

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

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

Источники

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