Набор команд ниже я собрал, пока разбирал другую задачу — почему у пользователей в Thunderbird часть папок оказалась пустой. Сервер тогда был ни при чём, но научиться смотреть на IMAP-сессии пришлось, и пригодилось потом.
Выкладываю как рабочий набор: что показывает срез, что показывает движение, и одна грабля, на которую я наступил по дороге.
Коротко
doveadm who— кто подключён и сколько сессий на ящик.- Шесть и пятнадцать подключений на ящик — это офисный NAT, а не аномалия.
- Старые PID — долгоживущие IDLE-сессии, так и должно быть.
docker compose logs -fбез имени сервиса выдаёт много текста и ни строчки Dovecot.
Срез: кто вообще подключён
Первое, что показывает картину целиком — doveadm who:
docker compose exec dovecot-mailcow doveadm who
username # proto (pids) (ips)
otdel@example.com 6 imap (1021 1188 2210 ...) (198.51.100.7)
it@example.com 15 imap (344 351 402 ...) (198.51.100.7)
У меня там обнаружилось шесть одновременных подключений на одном ящике и пятнадцать на другом. Выглядит тревожно ровно до того момента, пока не посмотришь на адреса: все из-за офисного NAT, то есть с одного внешнего IP. Это не атака и не поломка, это один офис.
У части процессов оказались очень старые PID. Это тоже нормально: долгоживущие сессии в режиме IDLE так себя и ведут — клиент держит соединение открытым, чтобы мгновенно получать новые письма, и не переподключается неделями.
Обе эти детали стоит знать заранее, иначе первый же взгляд на doveadm who рождает ложную тревогу. Много сессий с одного адреса и старые процессы — это описание нормально работающего офиса, а не диагноз.
Движение: что происходит прямо сейчас
Срез отвечает на вопрос «кто», но не на вопрос «чем занят». Для этого другие инструменты.
verbose_proctitle. С ним в обычном ps видно, какую команду процесс выполняет в данный момент. Дешёвый способ понять, кто из сессий реально работает, а кто просто висит.
Счётчики /proc/<pid>/io. Разница значения wchar, снятая дважды с интервалом, показывает, идёт ли реальная передача данных:
docker compose exec dovecot-mailcow sh -c \
'grep wchar /proc/1188/io; sleep 10; grep wchar /proc/1188/io'
Два числа выросли — процесс работает. Не выросли — висит. Это ответ на вопрос «завис или медленно работает», на который взгляд в ps не отвечает никогда.
doveadm mailbox status. Состояние ящика по папкам — сколько сообщений и сколько занимают:
docker compose exec dovecot-mailcow doveadm mailbox status \
-u otdel@example.com "messages vsize" '*'
Полезно, когда надо сравнить то, что видит сервер, с тем, что видит клиент. Именно это сравнение и показало в моём случае, что сервер отдаёт письма, а клиент их не показывает.
verbose_proctitle и rawlog_dir включаются в data/conf/dovecot/extra.conf:
verbose_proctitle = yes
protocol imap {
rawlog_dir = /tmp/rawlog/%u
}
rawlog — тяжёлая артиллерия: полный дамп протокола, каждая команда IMAP и каждый ответ. После него вопросов «а что клиент вообще просил» не остаётся.
Но с ним есть условие, которое нельзя пропускать: в дамп попадает содержимое писем. То есть на диске появляется незашифрованная копия чужой переписки. Включать — только на время отладки, только на конкретного пользователя, и удалять сразу после. Это тот случай, когда забыть выключить диагностику дороже, чем не включать её вовсе.
Логика набора такая: сначала срез, потом движение, потом протокол. Каждый следующий шаг дороже предыдущего и включается только тогда, когда предыдущий не ответил.
Грабля с логами
А теперь то, на чём я честно потерял время.
docker compose logs -f # мешанина nginx, ofelia, rspamd
docker compose logs -f --tail=200 dovecot-mailcow # правильно
Первая команда вывалила много текста. Логов Dovecot там не было ни строчки.
Правильно — указывать сервис явно. Либо смотреть лог через Redis, ключ DOVECOT_MAILLOG.
Случай мелкий, но показательный, и я записал его себе отдельно. Команда отработала без ошибки и выдала много текста, а ответа на мой вопрос в этом тексте не было. Это худший вид обратной связи: молчание хотя бы честно, а поток нерелевантных строк выглядит как результат и заставляет их читать.
Общее правило, которое я из этого вывел: если инструмент выдал много данных, первым делом надо проверить, что среди них есть хотя бы одна строка того типа, который вы ищете. Не «есть ли ответ», а «есть ли вообще нужный источник в выводе». Это две разные проверки, и вторая дешевле.