Перейти к содержимому

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_infonode
Очередиqueue_messages, queue_domains, queue_oldest_age_secondsqueue (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_messageslevel (от 0 до 10; 10 объединяет всё выше)
Вирусыvirus_detections (первая десятка дня)virus
Карантиныquarantine_messages, quarantine_bytes, quarantine_avg_spam_levelkind (spam, virus, attachment)
Службыservice_running (1 или 0; серии нет вообще для неустановленного юнита)node, service
Сигнатурыsignature_age_seconds, signature_count, signature_update_availablenode, family (virus, spam), database (main, daily, bytecode или канал SpamAssassin)
Сертификатыcertificate_expires_in_secondsnode, certificate
Кластерcluster_nodes, cluster_node_insync, cluster_node_healthy (все отсутствуют на автономном шлюзе)node, role
Подпискаsubscription_active (метки несут точный статус)node, status, level
Обновленияnode_updates_pending, node_updates_security_pendingnode
Сбор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. Уведомления называют соответствующую очередь, службу, базу или узел.

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

  1. В веб-интерфейсе: Configuration → User Management → Users → Add. Назовите учётную запись так, как указано ниже, задайте длинный пароль, нигде больше не используемый, и отметьте Enabled.

    dumbmonit@pmg
  2. Установите её Role в Audit. Это точный минимум только для чтения для всего, что читает DumbMonit: статус узла, службы, очереди postfix, статистика почты, количества в карантине, возраст баз ClamAV и SpamAssassin, статус кластера, сертификаты, подписка и ожидающие обновления. Audit ничего не может изменить, ничего не освобождает из карантина и не читает ни одного письма.

  3. Предпочитаете оболочку? Та же учётная запись одной командой, затем задайте пароль.

    pmgsh create /access/users --userid dumbmonit@pmg --role audit --enable 1 --comment "DumbMonit monitoring"
  4. В DumbMonit введите адрес шлюза, например “mail.lan” или “mail.lan:8006”, затем имя пользователя этой учётной записи (включая realm) и пароль.

  5. Proxmox Mail Gateway, в отличие от Proxmox VE и Proxmox Backup Server, не выдаёт токены API: входить нужно по имени пользователя и паролю. DumbMonit открывает одну двухчасовую сессию и продлевает её, а не входит при каждом измерении.

Адрес: 10.0.0.40, mail.lan, mail.lan:8006, [fd00::4] или полный URL. Схема https и порт 8006 добавляются, если отсутствуют.

КлючНазваниеПо умолчаниюСправка
portAPI port8006Используется, если в адресе не указан порт.
insecure_tlsAccept an unverifiable certificatefalseProxmox Mail Gateway по умолчанию поставляется с самоподписанным сертификатом: включите это, если соединение отклоняется по этой причине.
request_timeout_secondsTimeout per request (seconds)15Время, отведённое на каждый вызов API, от 1 до 120. Чтение очереди запускает на шлюзе команду Postfix и может занять несколько секунд.
nodeMonitored node(пусто)Имя узла кластера для мониторинга. Пусто: каждый узел, который перечисляет шлюз.
recent_hoursTraffic window (hours)12Насколько далеко назад идёт кривая трафика, от 1 до 24. Суточные итоги всегда охватывают текущий день.
queuesWatch the mail queuestrueЧитает очереди incoming, active, deferred и hold и возраст самого старого сообщения в каждой.
quarantineCount the quarantinestrueЧитает, сколько сообщений содержат карантины спама и вирусов и сколько диска они занимают. Только количества.
attachment_quarantineAlso count the attachment quarantinefalseУ этого карантина нет вызова подсчёта: чтобы посчитать, его нужно перечислить. По умолчанию выключено; сохраняется только число записей.
signaturesWatch the signature databasestrueЧитает возраст баз вирусов ClamAV и каналов правил SpamAssassin.
servicesWatch the servicestrueЧитает состояние postfix, pmg-smtp-filter, pmgpolicy и других юнитов каждого узла.
certificatesWatch the certificatestrueЧитает сертификаты, которые отдаёт веб-интерфейс, и предупреждает до их истечения.
updatesCount pending updatestrueПеречисляет пакеты, ожидающие обновления, на каждом узле.
subscriptionRead the subscriptiontrueЧитает статус подписки каждого узла.
СимптомВероятная причина
У 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 на шлюзе; вторичный канал, который настроен, но ни разу не загружался, намеренно остаётся без даты.
Нет ни одной базы ClamAVClamAV не установлен или freshclam ни разу не завершил загрузку. Конечная точка отвечает пустым списком, что не является ошибкой.
Нет метрик кластераШлюз автономный. /config/cluster/status отвечает пустым списком, и ни одно правило кластера не может сработать.
“Mail stuck in the queue” срабатывает поздноqueue_oldest_age_seconds — нижняя граница самого старого занятого интервала возраста qshape, поэтому она по замыслу занижает значение.
Отсутствует quarantine_messages{kind="attachment"}Опция attachment_quarantine выключена: у этого карантина нет конечной точки подсчёта, поэтому чтобы посчитать его, нужно его перечислить.