Proxmox Mail Gateway
Почтовый шлюз: очереди Postfix и возраст самого старого ожидающего письма, почта, подсчитанная и отфильтрованная сегодня, размеры карантинов, возраст баз сигнатур антивируса и антиспама, службы, сертификаты и состояние кластера.
Страница монитора
Заголовок раздела «Страница монитора»Помимо общих графиков, монитор Proxmox Mail Gateway показывает три панели, которые читаются из сохранённых опросом данных — открытие страницы никогда не обращается к самому шлюзу:
- Mail queues — четыре очереди Postfix в том порядке, в котором их читает почтовый администратор: incoming (только что принято), active (доставляется), deferred (доставка не удалась, будет повторена) и hold (задержано правилом). Для каждой показано, сколько в ней сообщений, сколько доменов назначения, самый загруженный из этих доменов и как долго ждёт самое старое сообщение. Очередь, в которой просто есть почта, — нормальный трафик; очередь, удерживающая сообщение более четырёх часов, помечается как Stuck.
- Mail filtered today — входящие и исходящие сообщения, байты, спам, вирусы, возвраты (bounces), среднее время обработки и то, что было отклонено до доставки (greylisting, чёрные списки, SPF, pregreeting). Столбец на каждый отрезок недавнего окна рисует кривую трафика без запросов к базе временных рядов. Затем три карантина с количеством сообщений и использованием диска и пойманные сегодня вирусы по названиям.
- Gateway — сначала остановленные службы, затем члены кластера и их состояние синхронизации, затем каждый узел: аптайм, CPU, память, диск, смещение часов, базы сигнатур с их возрастом и вердиктом, сертификаты, истекающие в течение двух недель, ожидающие обновления и статус подписки.
Только количества, никогда содержимое. DumbMonit читает, сколько сообщений
лежит в каждом карантине, но никогда тему, отправителя, получателя или тело.
Конечные точки статистики по адресам (/statistics/sender,
/statistics/receiver, /statistics/contact) не вызываются вообще.
Сегодня, а не последние двадцать четыре часа
Заголовок раздела «Сегодня, а не последние двадцать четыре часа»GET /statistics/mail агрегирует по локальному дню на шлюзе: PMG игнорирует
конец запрошенного окна, день выбирает только starttime. Поэтому DumbMonit
запрашивает “сейчас”, что даёт итоги с полуночи — ровно то, что показывает
собственная панель PMG. Эти серии — gauge, которые сбрасываются в ноль в
полночь, а не счётчики: не оборачивайте их в rate(). Недавняя кривая
(/statistics/recent) читает сырую таблицу и действительно скользит.
Что отслеживается
Заголовок раздела «Что отслеживается»Все метрики имеют префикс dumbmonit_pmg_.
| Семейство | Метрики | Метки |
|---|---|---|
| Узел | node_cpu_percent, node_iowait_percent, node_cpu_count, node_load1/5/15, node_memory_used/total_bytes, node_memory_used_percent, node_swap_used/total_bytes, node_rootfs_used/total/avail_bytes, node_rootfs_percent, node_uptime_seconds, node_clock_offset_seconds (положительное, когда шлюз опережает DumbMonit), node_insync, node_kernel_info, node_version_info (версия API этого узла — в кластере здесь виден тот, что отстал после последнего обновления), version_info | node |
| Очереди | queue_messages, queue_domains, queue_oldest_age_seconds | queue (incoming, active, deferred, hold) |
| Почта сегодня | mail_count_in/out, mail_bytes_in/out, mail_spam_in/out, mail_virus_in/out, mail_bounces_in/out, mail_junk_in, mail_junk_out (ваши собственные пользователи рассылают мусор: первый признак скомпрометированной учётной записи), mail_junk_percent (отсутствует в день без входящей почты), mail_greylisted, mail_spf_rejects, mail_rbl_rejects, mail_pregreet_rejects, mail_avg_processing_seconds | |
| Пропускная способность | mail_rate_in_per_minute, mail_rate_out_per_minute (по последнему полному отрезку недавней кривой) | |
| Оценки спама | spam_score_messages | level (от 0 до 10; 10 объединяет всё выше) |
| Вирусы | virus_detections (первая десятка дня) | virus |
| Карантины | quarantine_messages, quarantine_bytes, quarantine_avg_spam_level | kind (spam, virus, attachment) |
| Службы | service_running (1 или 0; серии нет вообще для неустановленного юнита) | node, service |
| Сигнатуры | signature_age_seconds, signature_count, signature_update_available | node, family (virus, spam), database (main, daily, bytecode или канал SpamAssassin) |
| Сертификаты | certificate_expires_in_seconds | node, certificate |
| Кластер | cluster_nodes, cluster_node_insync, cluster_node_healthy (все отсутствуют на автономном шлюзе) | node, role |
| Подписка | subscription_active (метки несут точный статус) | node, status, level |
| Обновления | node_updates_pending, node_updates_security_pending | node |
| Сбор | up, scrape_errors, scrape_duration_seconds |
queue_oldest_age_seconds — это нижняя граница. qshape сообщает
интервалы возраста (менее 5 мин, 5–10 мин, 10–20 мин и так далее, с
удвоением), поэтому DumbMonit хранит нижнюю границу самого старого занятого
интервала: сообщение, отнесённое к “не менее 20 минут”, может быть возрастом 39
минут. Занижение означает, что оповещение сработает позже, а не раньше, и
никогда — по сообщению, которое на самом деле не запоздало.
queue_domains точно на одиночном шлюзе. В кластере очереди по узлам
объединяются, а подсчёт ведётся по самым загруженным доменам каждого узла, не
более двадцати на узел: сверх этого значение занижено. Дедупликация здесь лучше
суммирования, так как два узла одного кластера принимают почту для одних и тех
же доменов.
Автономный шлюз отвечает на /config/cluster/status пустым списком. Это шлюз
без кластера, а не деградировавший кластер: серия не публикуется, и ни одно
правило не может сработать.
Только daily-база ClamAV оценивается по возрасту — и панелью, и правилом.
main пересобирается раз или два в год, а bytecode немногим чаще: оценка их
по двум дням выводила бы “out of date” круглый год на совершенно актуальном
шлюзе. Они по-прежнему показывают возраст, версию и количество сигнатур — но
без вердикта. Аналогично, у канала SpamAssassin, который ни разу не загружался,
нет даты вообще, а “никогда не обновлялся” — это не “устарел”: нет серии, нет
вердикта, нет оповещения.
ClamAV записывает дату сборки в собственном формате внутри заголовка .cvd
(16 Dec 2025 23-18 +0000, с дефисом там, где все остальные ставят двоеточие),
и PMG передаёт её как есть. Если этот формат когда-нибудь изменится, возраст
просто будет отсутствовать, а не окажется неверным на пятьдесят лет. То же
правило действует везде: значение, которое API не вернул, даёт одной метрикой
меньше, но никогда не ноль, выдающий себя за измерение.
Применяемые встроенные правила: Monitor unreachable, Mail queue growing, Mail stuck in the queue, Mail gateway service stopped, Virus signatures out of date, Spam rules out of date, Quarantine filling up, Mail gateway cluster degraded, Mail gateway certificate expiring, Mail gateway updates pending. Уведомления называют соответствующую очередь, службу, базу или узел.
Что подготовить в Proxmox Mail Gateway
Заголовок раздела «Что подготовить в Proxmox Mail Gateway»Приведённые ниже шаги совпадают с теми, что показывает уведомление рядом с формой. Принцип: пользователь, выделенный для мониторинга, с ролью только для чтения — никогда не та учётная запись, под которой вы входите.
-
В веб-интерфейсе: Configuration → User Management → Users → Add. Назовите учётную запись так, как указано ниже, задайте длинный пароль, нигде больше не используемый, и отметьте Enabled.
dumbmonit@pmg -
Установите её Role в
Audit. Это точный минимум только для чтения для всего, что читает DumbMonit: статус узла, службы, очереди postfix, статистика почты, количества в карантине, возраст баз ClamAV и SpamAssassin, статус кластера, сертификаты, подписка и ожидающие обновления.Auditничего не может изменить, ничего не освобождает из карантина и не читает ни одного письма. -
Предпочитаете оболочку? Та же учётная запись одной командой, затем задайте пароль.
pmgsh create /access/users --userid dumbmonit@pmg --role audit --enable 1 --comment "DumbMonit monitoring" -
В DumbMonit введите адрес шлюза, например “mail.lan” или “mail.lan:8006”, затем имя пользователя этой учётной записи (включая realm) и пароль.
-
Proxmox Mail Gateway, в отличие от Proxmox VE и Proxmox Backup Server, не выдаёт токены API: входить нужно по имени пользователя и паролю. DumbMonit открывает одну двухчасовую сессию и продлевает её, а не входит при каждом измерении.
Адрес: 10.0.0.40, mail.lan, mail.lan:8006, [fd00::4] или полный URL.
Схема https и порт 8006 добавляются, если отсутствуют.
| Ключ | Название | По умолчанию | Справка |
|---|---|---|---|
port | API port | 8006 | Используется, если в адресе не указан порт. |
insecure_tls | Accept an unverifiable certificate | false | Proxmox Mail Gateway по умолчанию поставляется с самоподписанным сертификатом: включите это, если соединение отклоняется по этой причине. |
request_timeout_seconds | Timeout per request (seconds) | 15 | Время, отведённое на каждый вызов API, от 1 до 120. Чтение очереди запускает на шлюзе команду Postfix и может занять несколько секунд. |
node | Monitored node | (пусто) | Имя узла кластера для мониторинга. Пусто: каждый узел, который перечисляет шлюз. |
recent_hours | Traffic window (hours) | 12 | Насколько далеко назад идёт кривая трафика, от 1 до 24. Суточные итоги всегда охватывают текущий день. |
queues | Watch the mail queues | true | Читает очереди incoming, active, deferred и hold и возраст самого старого сообщения в каждой. |
quarantine | Count the quarantines | true | Читает, сколько сообщений содержат карантины спама и вирусов и сколько диска они занимают. Только количества. |
attachment_quarantine | Also count the attachment quarantine | false | У этого карантина нет вызова подсчёта: чтобы посчитать, его нужно перечислить. По умолчанию выключено; сохраняется только число записей. |
signatures | Watch the signature databases | true | Читает возраст баз вирусов ClamAV и каналов правил SpamAssassin. |
services | Watch the services | true | Читает состояние postfix, pmg-smtp-filter, pmgpolicy и других юнитов каждого узла. |
certificates | Watch the certificates | true | Читает сертификаты, которые отдаёт веб-интерфейс, и предупреждает до их истечения. |
updates | Count pending updates | true | Перечисляет пакеты, ожидающие обновления, на каждом узле. |
subscription | Read the subscription | true | Читает статус подписки каждого узла. |
Типичные ошибки
Заголовок раздела «Типичные ошибки»| Симптом | Вероятная причина |
|---|---|
У ClamAV main огромный возраст | Ожидаемо: он пересобирается раз или два в год. Вердикт несёт только daily. |
| Ошибка сертификата | Самоподписанный сертификат: установите доверенный (ACME встроен в PMG) или включите insecure_tls. |
| Ошибка аутентификации | Неверный realm в имени пользователя — должно быть dumbmonit@pmg, а не dumbmonit — или учётная запись не Enabled. Весь опрос признаётся неудачным, только если не удался GET /version; любой другой неудавшийся вызов учитывается в scrape_errors. |
| Недостаточно прав | Роль учётной записи ниже Audit. quser видит только собственную почту; helpdesk не может читать ни узел, ни статистику. |
Все метрики mail_* равны нулю | Шлюз действительно ничего не фильтровал с полуночи. Итоги охватывают текущий локальный день на шлюзе и сбрасываются в его полночь, а не в вашу. |
Нет серий service_running вообще | Опция services выключена или роль не может их перечислить. Один юнит, отсутствующий в списке, просто не установлен на этом узле (например, chrony на машине с systemd-timesyncd) и намеренно не сообщается как остановленный. |
Нет signature_age_seconds для канала SpamAssassin | Этот канал ни разу не обновлялся, поэтому PMG не возвращает дату. Выполните sa-update на шлюзе; вторичный канал, который настроен, но ни разу не загружался, намеренно остаётся без даты. |
| Нет ни одной базы ClamAV | ClamAV не установлен или freshclam ни разу не завершил загрузку. Конечная точка отвечает пустым списком, что не является ошибкой. |
| Нет метрик кластера | Шлюз автономный. /config/cluster/status отвечает пустым списком, и ни одно правило кластера не может сработать. |
| “Mail stuck in the queue” срабатывает поздно | queue_oldest_age_seconds — нижняя граница самого старого занятого интервала возраста qshape, поэтому она по замыслу занижает значение. |
Отсутствует quarantine_messages{kind="attachment"} | Опция attachment_quarantine выключена: у этого карантина нет конечной точки подсчёта, поэтому чтобы посчитать его, нужно его перечислить. |