Почему готовых шаблонов для Kerio Connect нет
Если набрать «kerio connect zabbix» в поиске, обнаруживается странная пустота. Сама Zabbix Sia рассказывает на странице zabbix.com/integrations/kerio про шаблон для Kerio Control — это файрвол, SNMP-метрики там работают штатно. А вот Kerio Connect (почтовый сервер) на этой же странице упоминается единственным предложением: «если нужен шаблон — мы готовы разработать индивидуально, обратитесь за расчётом». Бесплатной версии нет.
В официальном zabbix/community-templates Kerio Connect отсутствует. Поиск по issues и PR — ничего жизнеспособного. На linux.org.ru человек предлагает регулярки по графическому DAT-файлу, который Kerio хранит на диске для веб-консоли. Идея рабочая, но это парсинг бинарного формата, который вендор не обещает стабильным. В руководстве Kerio Connect Multi-Server (это коммерческое расширение) есть инструкция по мониторингу через Puppet и SNMP — но только для Multi-Server конфигурации и только для платных установок.
Получается: коммерческий почтовик, в нашей стране крутится в десятках организаций, в открытом доступе шаблона нет.
У меня под рукой одна такая установка — Kerio Connect 10.0.8.9228 на Windows, ~500 учётных записей, обработано 617376 входящих сообщений с момента старта, в очереди обычно 1–3 письма.
Дальше — разбор того, что выяснилось по API, какие методы реально доступны под минимальной ролью, как уложить четыре HTTPS-вызова в один Zabbix-айтем, и где пришлось делать компромиссы.
Что выяснилось про Kerio Admin API
Документация Kerio на API скудная — есть PDF на 200+ страниц с описанием методов, но многие из них работают «иногда» и зависят от роли пользователя. Я создал служебного пользователя с минимально достаточной ролью Auditor (это уровень между «никаких прав» и «администратор»), сел читать.
API живёт на https://<kerio>:4040/admin/api/jsonrpc/. JSON-RPC 2.0.
Первые грабли: формат application. Документация показывает примеры с application: "MyMonitor" — строкой. Так не работает: возвращается -32602 Invalid params. Опытным путём выяснилось, что application должно быть объектом:
{ "jsonrpc": "2.0", "id": 1, "method": "Session.login", "params": { "userName": "zabbix_api", "password": "...", "application": {"name": "Zabbix Monitoring", "vendor": "Zabbix", "version": "7.0"} } }
В ответе приходит {"result": {"token": "<hex>"}} и в HTTP-заголовке Set-Cookie: SESSION_CONNECT_WEBADMIN=...; Path=/. Дальше при каждом вызове нужно передавать и cookie, и токен в заголовке X-Token. Если что-то пропустить, Kerio начинает возвращать 1003 Access denied без подробностей.
Вторые грабли: имена методов. В документации указан метод ProductRegistration.get. Он не работает: -32602 Invalid params при любых параметрах. Правильное имя — ProductRegistration.getFullStatus. Это вообще не упомянуто в открытом PDF, нашёл его в обсуждениях на форуме разработчиков плагинов Kerio Operator.
Третьи грабли — самые болезненные: что Auditor НЕ умеет. Проверил по очереди:
Метод | Что хотелось | Что получили |
|---|---|---|
| CPU/RAM/swap сервера |
|
| Per-domain storage |
|
| Сами сообщения в очереди | Timeout. Зависают. |
SystemHealth.get оказался полностью закрыт для Auditor. Полез в логи Kerio после нескольких попыток — там видно, что вызов даже не доходит до обработчика метрик. Попытался обойти через Batch.run (Kerio Admin API позволяет упаковать несколько вызовов в один батч, который при удачном раскладе исполняется в контексте чуть других проверок прав) — тот же -32602 Invalid params, даже когда сам батч содержит только SystemHealth.get. Пробовал с пустыми параметрами, с {}, с конкретными ключами вроде cpu, memory, disk — всё бесполезно. Это означает, что CPU, память и swap через Kerio API получить невозможно под минимальной ролью. Дальше будет про это, спойлер: проблема решается параллельным OS-шаблоном.
Domains.get мог бы дать per-domain quotas и storage usage. Под Auditor — 1000 internal database error. Поднимать на Admin ради этого не хочется: Admin даёт полный доступ к конфигурации почтовика, для скрапинга метрик это перебор.
Queue.get и его варианты теоретически возвращали бы тела сообщений в очереди. На практике на Kerio Connect 10.0.8 они зависают наглухо, и единственное спасение — оборвать соединение и заново залогиниться. К счастью, размер очереди есть в Statistics.get (поле storedInQueue.count), а тела сообщений для мониторинга и не нужны.
Что в итоге работает. Четыре метода, и больше, как выяснилось, не нужно:
Statistics.get— главное блюдо: storage, очередь, uptime, счётчики соединений по протоколам, SMTP-сообщения in/out, неудачные SMTP-аутентификации, спам checked/rejected, антивирус scanned/found, greylisting, antibombingServices.get— список сервисов (SMTP, IMAP, POP3, LDAP, Web, XMPP и их Secure-варианты — всего обычно 15) с полемisRunning: booleanProductRegistration.getFullStatus— лицензия: количество мест, дата истечения, оставшиеся дниServer.getVersion— версия сервера (информационное поле, полезно для отчётов и Auto-discovery)
Statistics.get возвращает примерно 8 КБ JSON на нагруженном почтовике — там около 40 числовых полей. Большинство из них при этом — строки, а не числа: "617376", "91714". Это надо учитывать при настройке Zabbix dependent items.
Архитектура: один master-айтем, четыре вызова

Самое прямолинейное решение для такого набора — HTTP Agent items, по одному на метрику. Получилось бы 24 отдельных HTTP-вызова в минуту, каждый со своим логином, своим JSON в обе стороны и своим состоянием. Kerio API при этом не безлимитный — у нагруженного почтовика на каждый логин уходит 150–300 ms (TLS handshake + аутентификация). 24 параллельных Session.login в минуту — это уже заметная нагрузка на сервис, и каждый из них видим в audit-логе.
Поэтому реализация другая — pattern «master + dependent items»:
Один master-айтем выполняет последовательность
Session.login → 4 вызова → Session.logoutВозвращает один склеенный JSON-объект ~8 КБ
24 dependent items извлекают свои значения через JSONPath из этого объекта
Один LLD-айтем тем же путём дискаверит запущенные сервисы
В Zabbix 7 master-айтем можно сделать одним из двух способов:
HTTP Agent + Pre-processing script (JavaScript на Duktape) — Zabbix server/proxy ходит сам
Script item — то же, но без promise-цепочки, проще читать
Я выбрал Script item: код укладывается в 60 строк JS, диагностика прозрачнее (всё, что бросаешь как throw, видно прямо в Zabbix UI в поле Value of last check). Вот сердцевина:
var loginResult = apiCall('Session.login', { userName: params.username, password: params.password, application: { name: 'Zabbix Monitoring', vendor: 'Zabbix', version: '7.0' } }); token = loginResult.token; var statsResp = apiCall('Statistics.get'); var svcsResp = apiCall('Services.get'); var licResp = apiCall('ProductRegistration.getFullStatus'); var serverResp = apiCall('Server.getVersion'); try { apiCall('Session.logout'); } catch (e) {} return JSON.stringify({ statistics: statsResp.statistics || {}, services: svcsResp.services || [], license: licResp.status || {}, server: serverResp || {} });
Внутри apiCall — обычный JSON-RPC: построить тело, отправить POST, проверить статус и result.error, для Session.login дополнительно вытащить cookie из заголовка Set-Cookie и прицепить его ко всем последующим запросам через Cookie: ... и X-Token: ....
function apiCall(method, callParams) { reqId++; var body = { jsonrpc: '2.0', id: reqId, method: method }; if (callParams) body.params = callParams; if (token) body.token = token; var http = new HttpRequest(); http.addHeader('Content-Type: application/json'); if (cookie) http.addHeader('Cookie: ' + cookie); if (token) http.addHeader('X-Token: ' + token); var resp = http.post(baseUrl, JSON.stringify(body)); var status = http.getStatus(); if (status < 200 || status >= 300) throw 'HTTP ' + status + ' on ' + method; var result = JSON.parse(resp); if (result.error) throw method + ' error: ' + result.error.message; return result.result; }
Master-айтем опрашивается раз в минуту с таймаутом 30 секунд (про таймаут чуть ниже — это важно). Dependent items привязаны к нему по master_item и получают данные мгновенно при каждом обновлении master.
JSONPath в Zabbix 7 поддерживает фильтры массивов, что критично для LLD сервисов. Master возвращает массив services[], в каждом элементе name и isRunning. Чтобы достать статус для конкретного дискаверенного сервиса:
$.services[?(@.name=="{#SERVICE}")].isRunning.first()
Фильтр [?(@.name=="{#SERVICE}")] отбирает элемент массива с подходящим именем, .isRunning.first() достаёт значение из единственного результата. На выходе — true/false. После Pre-processing «Boolean to decimal» получается 0/1, на котором уже строится триггер «service is not running».
Грабли счётчиков: рестарт, отрицательная дельта и IN_RANGE
Все счётчики в Statistics.get — кумулятивные с момента запуска сервера. Точно как /proc/diskstats или ifconfig RX bytes. На запущенном почтовике это выглядит так:
{ "received": {"count": "617376", ...}, "transmitted": {"count": "319307", ...}, "smtpServer": {"totalIncomingConnections": "1506226", "authenticationFailures": "334700", ...}, "spam": {"checked": "91714", "rejected": "10895", ...}, "antivirus": {"checkedAttachments": "579391", "foundViruses": "147", ...} }
617376 принятых писем — это не «за сегодня», это с момента рестарта почтовика. Чтобы получить осмысленный rate (например, «сколько спама пришло за последние 5 минут»), на каждое такое поле в Zabbix вешается preprocessing шаг Change per second — он считает дельту относительно предыдущего значения и делит на интервал.
И тут — четвёртые грабли: что происходит, когда Kerio перезапустился. Счётчик уходит с 617376 в 0. Следующий опрос приносит, скажем, 50. Change per second даёт дельту (50 - 617376) / 60 = -10288. Огромное отрицательное число, которое уезжает в график и портит всю аналитику.
Решение — после Change per second добавить второй preprocessing шаг In range:
In range: min=0, max=1e9, custom-on-fail=Discard value
Если расчётный rate отрицательный или абсурдно большой — значение отбрасывается, в график идёт пропуск (gap), на следующем опросе всё уже считается от новой базы. Это маскирует ровно одну точку после рестарта, что приемлемо. Альтернативы хуже: либо мириться с отрицательным выбросом, либо переписывать препроцессинг на JavaScript с хранением состояния (Zabbix умеет, но сложнее в отладке).
Пятые грабли, мелкие, но раздражающие — типы данных. Kerio в JSON возвращает большинство счётчиков строками: "617376", не 617376. Zabbix умеет преобразовывать строки в числа на лету, но storage.percentage приходит как "92" (без знака процента, просто число в строке) — для него надо явно поставить preprocessing «Trim» или «Matches regex (\d+)», иначе будет ругань про невалидное значение.
И ещё один сюрприз: uptime.days приходит числом (1), а не строкой. Единственное поле, выпадающее из общего паттерна. Если разрабатывать тесты — обязательно положить такой кейс в фикстуру, иначе сломается.
Шестые грабли — единицы измерения, которые меняются на лету. Kerio возвращает объёмы данных в формате {"value": N, "units": "..."}, где units может быть "Bytes", "KiloBytes", "MegaBytes" в зависимости от размера. На пустой очереди в JSON будет:
"storedInQueue": {"count": "0", "volume": {"value": 0, "units": "Bytes"}, "recipients": "0"}
А при наполненной очереди — "units": "MegaBytes". Это значит, что просто брать volume.value нельзя, без нормализации к единым единицам Zabbix получит мусор: то 50 байт, то 50 мегабайт в одном и том же графике. В шаблоне для метрик объёма я взял за правило брать count (количество сообщений) — оно всегда в штуках и не плавает. А там, где объём действительно нужен (storage диска), Kerio удачно возвращает фиксированные MegaBytes, и тут можно не дёргаться. Но если кто-то решит расширить шаблон метриками вроде «объём входящего трафика SMTP» — придётся писать препроцессинг с нормализацией, иначе будут грабли. Это, кстати, ещё одна причина, по которой я не стал тащить в шаблон всё подряд: тридцать метрик с понятной семантикой лучше пятидесяти с подводными камнями.
Вариант 1 — без агента: Zabbix server или proxy ходит сам
Если Zabbix server (или proxy) видит почтовик по сети — :4040 доступен, фаервол пропускает — никакого агента ставить не нужно. Шаблон Kerio Connect by Script живёт в Templates → Applications, импортируется как обычный YAML, на хост вешаются пять макросов:
Макрос | Значение |
|---|---|
| IP или DNS-имя сервера Kerio |
|
|
|
|
| служебный пользователь (Auditor достаточен) |
| пароль (Secret macro) |
Через минуту в Monitoring → Latest data появляются значения дисков, версия, лицензия. Счётчики становятся не-нулевыми после второго опроса (потому что Change per second нужен предыдущий замер).
Этот вариант я и рекомендую как основной. Из плюсов — ноль изменений на самом почтовом сервере: ни нового пакета, ни конфига, ни перезапуска. Из минусов — путь по сети от Zabbix proxy до Kerio должен быть открыт по 4040/tcp, что не всегда возможно в больших организациях.
Вариант 2 — через Zabbix agent (когда сеть закрыта)
Часть моих клиентов держит почтовик в DMZ или сегменте, до которого централизованный Zabbix proxy просто не дотягивается через NAT и фаервол. Открывать дополнительные правила ради мониторинга — лишний согласование с безопасниками и потенциальный риск. Для таких случаев в репозитории второй шаблон — Kerio Connect by Zabbix agent. На самом сервере с Kerio (или соседнем) ставится zabbix_agent2, в него прописывается UserParameter:
UserParameter=kerio.api.master, /usr/bin/python3 /opt/zabbix-kerio-connect/src/kerio_collector.py collect /etc/zabbix/kerio_connect.conf UserParameter=kerio.services.discovery, /usr/bin/python3 /opt/zabbix-kerio-connect/src/kerio_collector.py lld_services /etc/zabbix/kerio_connect.conf
Логика та же — login, четыре вызова, logout, склейка JSON. Только теперь это kerio_collector.py на чистом stdlib (urllib, json, ssl), без сторонних зависимостей. Чтобы можно было прогнать вне Zabbix:
python3 kerio_collector.py collect /etc/zabbix/kerio_connect.conf | jq .
Шестые грабли — самые интересные с точки зрения безопасности. Очевидное решение «давайте передадим пароль через макрос Zabbix» не работает: Zabbix host-макросы не разворачиваются внутри zabbix_agent2.conf. То есть прописать password={$KERIO.API.PASSWORD} в строке UserParameter нельзя — на агент придёт буквальный текст {$KERIO.API.PASSWORD}. Можно было бы передавать пароль аргументом в момент опроса с server’а — но тогда секрет утекает в ps aux и в логи zabbix_agent2 на уровне DEBUG.
Решение, которое в шаблоне — отдельный конфиг-файл на хосте:
# /etc/zabbix/kerio_connect.conf — chmod 0600, owner zabbix:zabbix [api] host = 127.0.0.1 port = 4040 scheme = https username = zabbix_api password = <секрет>
chmod 0600 + chown zabbix:zabbix — файл читается только агентом и root. Не идеально (всё-таки plaintext), но это паттерн, по которому живут десятки других Zabbix UserParameter-скриптов; на практике компромисс приемлемый.
Седьмые грабли — таймаут. По умолчанию zabbix_agent2.conf ставит Timeout=3 секунды. Четыре последовательных HTTPS-вызова с TLS handshake и парсингом ответов — это в среднем 800–1500 мс на нагруженном почтовике, но на холодный старт может уйти и больше. С Timeout=3 каждый второй опрос обрывался на полпути, мастер-айтем уходил в nodata, все триггеры начинали мигать. В zabbix_agent2.conf нужно ставить:
Timeout=30
И не забыть рестартнуть агента, потому что Timeout читается только при старте.
В коллекторе явно отключена проверка сертификата (ssl.CERT_NONE). На внутреннем почтовике, который никто не выставлял в интернет, это обычно нормально — Kerio из коробки идёт с самоподписанным сертификатом. Если кому-то этот компромисс не нравится — в коллекторе одна строчка правки, чтобы включить проверку по корпоративному CA.
К коллектору есть 60 unit-тестов на pytest, которые гоняются в CI на каждый коммит. Тестируются: парсинг конфига, корректное построение payload для Session.login, корректное прицепление токена и cookie, обработка ошибок API, выход с кодом и валидным JSON в случае любого исключения. Это важно для production: если коллектор падает с stack trace в stderr — Zabbix получит мусор и закрасит весь экран.
Перед тем как привязывать шаблон к хосту, имеет смысл прогнать коллектор вручную и убедиться, что он возвращает осмысленный JSON. На самом сервере достаточно одного шага:
sudo -u zabbix python3 /opt/zabbix-kerio-connect/src/kerio_collector.py \ collect /etc/zabbix/kerio_connect.conf | jq '.statistics.storage'
Получите блок с total, occupied, percentage — значит логин прошёл и API отвечает. Если на этом шаге {"error": "..."} — значит дальше Zabbix тоже не сможет. Гораздо лучше увидеть это сразу, чем минут через десять, наблюдая nodata в Latest data и роясь в zabbix_agent2.log.
Триггеры и каскадные зависимости

Метрики ради метрик никому не нужны. Девять триггеров, которые в шаблоне:
API data collection failed (nodata 5 мин на master) — общий no-data корневой триггер
Disk usage > WARN/AVG/HIGH/DISASTER (80/90/95/99%) — четыре ступени по диску. Высший подавляет нижние, поэтому при заполненном на 96% диске виден один High-алерт, а не четыре одновременно
High message queue depth — очередь больше порога (по умолчанию 100 писем)
High SMTP authentication failure rate — частота неудачных логинов в среднем за 5 минут выше порога (по умолчанию 1/сек). Это первый признак того, что кто-то пытается перебирать пароли через ваш SMTP submission
Antivirus infection detected — KAV нашёл вирус хотя бы в одном письме за период (полезно, если у организации политика «при любом срабатывании AV — пересмотреть SPF/DKIM источника»)
License expires in less than 30 days — пора писать в закупки
Service
{#SERVICE}is not running — какой-то из 15 дискаверенных сервисов остановлен
В Disaster-уровне диска есть смысл: на 99% Kerio начинает отбивать SMTP с 452 Insufficient system storage. То есть письмо отскочит обратно отправителю с временной ошибкой — и в худшем случае попадёт в DSN после 5-дневной retry-сессии. Это не «нужно реагировать в течение дня», это «нужно реагировать в течение часа».
И тут — самое полезное архитектурное решение шаблона. Все non-master триггеры зависят от master nodata-триггера. Это значит, что когда Kerio API недоступен (например, перезагрузка сервера), Zabbix получает один корневой алерт «API data collection failed», а 16 остальных (4 disk × 4 уровня + queue + auth + license + AV + сервисы) автоматически подавляются.
Без зависимостей выглядело бы так: API лёг → все dependent items уходят в nodata → у дисковых триггеров nodata тоже триггерит → срабатывают все четыре уровня диска одновременно, плюс «очередь зависла», плюс «лицензия не определена», плюс «каждый сервис остановлен»… В sosial-сети-для-сисадминов это называется «алерт-шторм».
Cascade конфигурируется в YAML шаблона прямо в triggers:
- uuid: 8d6b3e7a4f1c4e6da9b2c0517e4d3a91 expression: 'last(/Kerio Connect by Script/kerio.disk.pct)>{$KERIO.DISK.WARN}' name: 'Disk usage > {$KERIO.DISK.WARN}%' priority: WARNING dependencies: - name: 'API data collection failed' expression: 'nodata(/Kerio Connect by Script/kerio.api.master,5m)=1'
В Zabbix UI Cause/Symptom после 6.0 — но в YAML удобнее как dependencies. Один корневой алерт на весь шаблон.
Тестирование шаблона перед production
Шаблон мониторинга — это код, и относиться к нему стоит как к коду. Особенно к шаблону, чьи триггеры будут будить дежурного в три ночи. Ложный алерт убивает доверие быстрее, чем пропущенный инцидент: после двух-трёх «опять зря разбудили» дежурный начнёт молча отщёлкивать уведомления, а в следующий раз пропустит настоящий пожар.
В репозитории три уровня проверок, которые имеет смысл прогонять перед каждым релизом шаблона.
Юнит-тесты Python-коллектора (60 шт., pytest tests/). Проверяют все ветки kerio_collector.py: парсинг конфига, отсутствующая секция [api], отсутствующий ключ port, числовая конверсия, корректность payload для Session.login, прицепление токена и cookie ко всем последующим вызовам, корректная обработка result.error, корректное падение в JSON-формат при сетевой ошибке. Это страховка от «коллектор крашится из-за неожиданного формата конфига», что в production выглядит как тихий nodata.
Static check JS-коллектора. master_collector.js крутится внутри Zabbix через Duktape, и Duktape-движок отличается от Node — там нет современного JS, нет async/await. Чтобы хотя бы синтаксические ошибки не доехать до production-сервера, в CI прогоняется:
node --check src/master_collector.js node --check src/lld_services.js
node --check парсит файл без исполнения и ругается на любую синтаксическую ошибку. Не идеально (Duktape всё равно может споткнуться на специфике), но 80% опечаток ловятся бесплатно.
Парность JS ↔ YAML. Самая болезненная история при поддержке Zabbix-шаблонов: JS-код хранится внутри YAML-файла шаблона (как поле script у master-айтема). Если разработчик правит .js-файл и забывает синхронизировать YAML — на production уезжает старая версия скрипта, а на репозиторий смотрят с гневом «у меня всё работает». Скрипт tools/sync_template_js.py --check сравнивает содержимое и падает в CI, если они разъехались. Финальная команда команды и для разработки — встроена в Makefile, гоняется одним make check.
После всего этого — ручной smoke на staging-хосте: импорт шаблона, привязка к тестовому Kerio, минута ожидания, проверка Monitoring → Latest data. Этим шагом нельзя пренебрегать: я однажды зарелизил версию, в которой LLD сервисов работал, но один из сервис-прототипов случайно был помечен Disabled, и на production в течение часа никто этого не заметил.
Что мониторится вне шаблона (и почему так)
В шаблоне намеренно нет CPU, RAM, swap и per-domain метрик. Это не упущение — это решение, основанное на ограничениях API под ролью Auditor (см. выше) и здравом смысле:
CPU/RAM/swap — Zabbix испокон веков умеет это собирать через стандартный шаблон Linux by Zabbix agent или Windows by Zabbix agent. Не надо изобретать велосипед поверх Kerio API (которое для этого всё равно не работает). Привязываете к хосту оба шаблона — application-уровневый Kerio и OS-уровневый Linux/Windows — и получаете полную картину без дублирования.
Per-domain storage — Domains.get требует Admin-роль, а Admin даёт полные права на редактирование конфигурации почтовика. Создавать API-пользователя с Admin ради per-domain метрик мне показалось плохой идеей: каждый зловред, получивший доступ к pickup-файлу с этими credentials, получает полный контроль над почтовой системой. Если для конкретной организации эти метрики критичны — можно их прикрутить отдельным шаблоном «Kerio Connect by Script (Admin)» и принять на себя риски. В моём варианте этого пути нет.
Per-message данные в очереди — Queue.get зависает (см. раздел про API). Если очень нужно — есть kerio_admin.exe (Windows) или kerio-admin (Linux) CLI, но это уже не Zabbix-юзкейс, это разовая диагностика, и она прекрасно живёт через SSH/RDP.
То, что описано в шаблоне — это application-layer метрики Kerio, и не более. Без претензии «закрыть весь observability одним шаблоном». Такой подход даёт меньше точек отказа и лучше живёт с обновлениями Kerio.
Выводы и репозиторий
Что получилось в итоге:
24 dependent items, покрывающих диски, очередь, соединения по 6 протоколам, SMTP-сообщения in/out, SMTP-auth failures, спам, антивирус, greylisting, antibombing, лицензию и версию сервера
1 LLD-правило, дискаверящее запущенные сервисы и создающее по prototype’у статус-айтем на каждый
9 триггеров с каскадной зависимостью от master nodata
Два варианта: с прямым опросом из Zabbix server/proxy и через локальный Zabbix agent с UserParameter
60 unit-тестов на pytest для Python-коллектора,
node --checkдля JS Script itemMIT-лицензия
Проверено и работает на:
Kerio Connect 10.0.8.9228 (Windows Server)
Zabbix 7.0
Сбор через Zabbix proxy на отдельной машине
Около 5000 учётных записей, средняя нагрузка 600+ тысяч принятых сообщений и 90+ тысяч проверок спама с момента старта
Чего пока нет, но хотелось бы:
Сбор по нескольким серверам в Multi-Server-конфигурации Kerio (это коммерческий вариант, в моей установке не используется)
Готовый Grafana-дашборд с тем же набором метрик (Zabbix Grafana datasource, JSON в репозиторий)
Если у вас Kerio Connect и Zabbix — забирайте, пробуйте, присылайте issues. Шаблон проверен только на 10 версии и трез установках; на других версиях могут вылезти грабли, которых я не видел. PR с фиксами и расширениями принимаются.
Репозиторий: github.com/IT-for-Prof/zabbix-kerio-connect
В репозитории найдёте YAML обоих шаблонов, Python и JS коллекторы, документацию по полям API (docs/api_fields.md — то, что я выяснил опытным путём при разработке), 60 юнит-тестов и краткий setup-гайд.
