Мониторинг домена в zabbix
Created on: April 15, 2026
Answered using GPT-5.4 Thinking by Chat01
Created on: April 15, 2026
Answered using GPT-5.4 Thinking by Chat01
Шаблон мониторинга домена в zabbix
https://github.com/a-stoyanov/zabbix-domain-expiry
Шаблон загружен и настроен
Скрипт отрабатывает
root@SRV-ZABBIX:/usr/lib/zabbix/externalscripts# ./check_domain.sh -d artek-braiding.ru
{"state":"OK","days_left":178,"days_since_expired":0,"expire_date":"2026-10-11","message":"State: OK ; Days left: 178 ; Expire date: 2026-10-11"}
При запуске выполнения из WEB Zabbix получаем ошибку : Timeout wcheck_domain.shhile executing a shell script.
Лог скрипта
Ср 15 апр 2026 16:33:20 MSK: Starting check for
Ср 15 апр 2026 16:37:51 MSK: Starting check for
Ср 15 апр 2026 16:38:05 MSK: Starting check for
Как решить проблему
Проблема почти наверняка не в самом check_domain.sh, а в том, что Zabbix запускает его без аргумента домена. Это видно из вашего лога: Starting check for — после for пусто. И это совпадает с шаблоном из репозитория: master item вызывает скрипт как check_domain.sh["-d",{HOST.HOST},...], а в README прямо сказано, что нужно создать host, у которого Host name = domain name. (GitHub)
Почему из WEB получается timeout: для template item тестирование в Zabbix возможно, но значения для таких тестов часто нужно вводить вручную; они не всегда берутся из реального host-контекста. В документации сказано, что для template items поля теста “have to be filled manually”, а на практике в похожих кейсах макросы вроде {HOST.*} при тесте шаблона не подставляются, пока не открыть item уже на конкретном host. (Zabbix)
Что делать.
Проверьте Host name.
Для этого шаблона host должен называться именно так:
textartek-braiding.ru
а не SRV-ZABBIX или что-то ещё. Иначе {HOST.HOST} передаст не домен. README шаблона требует именно такой сценарий. (GitHub)
Тестируйте item не на уровне шаблона, а на уровне host.
Откройте уже привязанный к host item Check Domain и нажмите Test там. Для template-level теста Zabbix не всегда может корректно подставить host-контекст. (Zabbix)
Лучшее решение — убрать зависимость от {HOST.HOST} и использовать макрос {$DOMAIN}.
Замените ключ master item на:
textcheck_domain.sh["-d","{$DOMAIN}","-r","{$RDAP_SERVER}","-s","{$WHOIS_SERVER}","-w","{$EXP_WARN}","-c","{$EXP_CRIT}"]
и на host задайте:
text{$DOMAIN}=artek-braiding.ru
Так шаблон будет работать даже если host называется не как домен.
Проверьте запуск от пользователя zabbix, а не от root.
External checks выполняются тем же пользователем, что и Zabbix server/proxy, а не root. Поэтому ручная проверка должна быть такой:
bashsudo -u zabbix /usr/lib/zabbix/externalscripts/check_domain.sh -d artek-braiding.ru
Если host обслуживается через proxy, скрипт должен лежать и выполняться на proxy, потому что external checks в этом случае запускаются именно там. (Zabbix)
Проверьте путь и права.
bashgrep ^ExternalScripts /etc/zabbix/zabbix_server.conf /etc/zabbix/zabbix_proxy.conf 2>/dev/null ls -l /usr/lib/zabbix/externalscripts/check_domain.sh sudo -u zabbix which whois curl jq awk grep date
Zabbix ищет скрипт только в каталоге ExternalScripts, и у пользователя zabbix должны быть права на выполнение. (Zabbix)
Если после исправления параметра домена всё ещё будет timeout, тогда уже смотрите время выполнения.
В этом случае проблема будет не в подстановке макроса, а в зависании whois/curl. Но по вашему логу первичная причина сейчас именно в пустом домене.
Итог:
самая вероятная причина — вы тестируете шаблонный item из WEB, и {HOST.HOST} там не подставляется, поэтому скрипт стартует с пустым -d, после чего Zabbix убивает процесс по timeout. Исправляется либо тестом на host, либо переводом шаблона на {$DOMAIN}.
Готовый рабочий вариант я бы сделал так: оставить host как угодно, а домен передавать через {$DOMAIN} — это надёжнее и удобнее в сопровождении.
sudo -u zabbix /usr/lib/zabbix/externalscripts/check_domain.sh -d artek-braiding.ru
{"state":"OK","days_left":178,"days_since_expired":0,"expire_date":"2026-10-11","message":"State: OK ; Days left: 178 ; Expire date: 2026-10-11"}
root@SRV-ZABBIX:/usr/lib/zabbix/externalscripts# grep ^ExternalScripts /etc/zabbix/zabbix_server.conf /etc/zabbix/zabbix_proxy.conf 2>/dev/null
root@SRV-ZABBIX:/usr/lib/zabbix/externalscripts# ls -l /usr/lib/zabbix/externalscripts/check_domain.sh
-rwxrwxr-x 1 zabbix zabbix 46155 апр 15 16:32 /usr/lib/zabbix/externalscripts/check_domain.sh
root@SRV-ZABBIX:/usr/lib/zabbix/externalscripts# ls -l /usr/lib/zabbix/externalscripts/check_domain.sh
-rwxrwxr-x 1 zabbix zabbix 46155 апр 15 16:32 /usr/lib/zabbix/externalscripts/check_domain.sh
Ошибка осталась
Причина у вас уже видна на скрине: в ключе item опечатка в макросе.
Сейчас у вас так:
textcheck_domain.sh["-d",{DOMAIN},"-r",{$RDAP_SERVER},"-s",{$WHOIS_SERVER}]
А должно быть либо так, если хотите использовать свой макрос:
textcheck_domain.sh["-d","{$DOMAIN}","-r","{$RDAP_SERVER}","-s","{$WHOIS_SERVER}","-w","{$EXP_WARN}","-c","{$EXP_CRIT}"]
либо вернуть как в оригинальном шаблоне автора:
textcheck_domain.sh["-d",{HOST.HOST},"-r",{$RDAP_SERVER},"-s",{$WHOIS_SERVER},"-w",{$EXP_WARN},"-c",{$EXP_CRIT}]
Почему это ломает проверку:
{$MACRO}, и их можно использовать в параметрах item key; форма {DOMAIN} для user macro неверная. (Zabbix){HOST.HOST}, а README требует создавать host с именем-доменом. (GitHub)Из-за этой опечатки в -d уходит пустое значение, что у вас и видно по логу скрипта:
textStarting check for
После этого Zabbix ждёт ответ до таймаута item и обрывает выполнение. По документации item timeout именно так и работает: по достижении лимита проверка прерывается как failed. (Zabbix)
Что сделать прямо сейчас:
Исправьте ключ на один из двух вариантов выше.
Для вашего случая удобнее через {$DOMAIN}.
Сохраните item и нажмите Обновить host/template.
Запустите тест ещё раз.
На время диагностики поставьте timeout не 4s, а 15s или 30s.
Не потому что это корневая причина, а чтобы исключить вторичный обрыв по времени после исправления макроса. Zabbix поддерживает per-item timeout для таких item types. (Zabbix)
Итог:
ошибка не в правах и не в скрипте, а в том, что у вас в key написано {DOMAIN} вместо {$DOMAIN}.
Готовый правильный ключ для вставки:
textcheck_domain.sh["-d","{$DOMAIN}","-r","{$RDAP_SERVER}","-s","{$WHOIS_SERVER}","-w","{$EXP_WARN}","-c","{$EXP_CRIT}"]
После этого Check Domain должен начать возвращать JSON, а зависимые items — разбирать поля из него.
Ошибка осталась,
Может нужно увеличить тайм-аут ?
Если да, то как это сделать. Опиши подробно по пунктам
Да — сейчас первое, что стоит сделать, это увеличить timeout. На вашем скрине у item стоит 4s, а для External check Zabbix поддерживает гибкие таймауты: на уровне конкретного item, proxy и global. Когда таймаут достигается, Zabbix прерывает проверку, помечает item как unsupported и пишет ошибку. Для External check это штатное поведение. (Zabbix)
Ещё у вас на скрине есть вторая проблема: в Пользовательских интервалах задано 50s на весь период 1-7,00:00-24:00. Для проверки срока домена это слишком часто. Внешние проверки запускаются отдельным процессом, и документация прямо предупреждает, что большое число external checks заметно снижает производительность. При этом число обычных poller-процессов на сервере по умолчанию всего 5. То есть при частом запуске легко получить очередь и повторные timeout’ы даже у рабочего скрипта. (Zabbix)
Сделайте так по шагам.
Check Domain.Глобальный, а Замещение / Override.30s.Для External check это корректно: у item можно задать свой timeout, диапазон допустимых значений — от 1 до 600 секунд. Причём timeout на уровне item имеет наивысший приоритет. (Zabbix)
50stextПеременный | 50s | 1-7,00:00-24:00
Для доменного шаблона этого более чем достаточно. Максимум можно поставить 12h или 1h, но 50s здесь не нужен и только создаёт лишние запуски. Внешние проверки не стоит “долбить” часто. (Zabbix)
После сохранения:
Check Domain,Если хост мониторится через proxy, external check выполняется на proxy, а не на server. Для passive proxy сервер отправляет обновлённую конфигурацию с частотой ProxyConfigFrequency, по умолчанию это 10 секунд. (Zabbix)
Это полезно, если таких проверок несколько.
30s.В этом разделе задаются глобальные таймауты по типам item, допустимый диапазон там тоже 1–600s. Но помните: если у конкретного item включён Override, то он важнее глобального. (Zabbix)
zabbix_server.conf менять обычно не нужноПараметр Timeout в zabbix_server.conf сейчас для вашего случая, скорее всего, не главный. Документация Zabbix прямо говорит, что server/proxy timeout не используется для тех проверок, где настроены flexible timeouts через frontend — на уровне global/proxy/item. У server config timeout диапазон 1–30 сек, но для современных flexible timeout’ов он уже не является основным механизмом. (Zabbix)
Сразу рекомендую такие значения:
textВремя ожидания: Override = 30s Интервал обновления: 1d Пользовательские интервалы: удалить
Это самый логичный набор для доменного шаблона. (Zabbix)
30s ошибка останетсяТогда причина уже не в настройке Zabbix, а в том, что скрипт периодически подвисает на whois/RDAP-запросе. Ручной запуск у вас проходит, но из Zabbix проблема может проявляться из-за сетевой задержки, нагрузки или частых параллельных запусков. В таком случае надо смотреть лог zabbix_server.log или zabbix_proxy.log сразу в момент теста и уже отдельно ограничивать время внутри самого check_domain.sh. Но сначала обязательно сделайте два изменения выше: 30s timeout + убрать 50s interval. (Zabbix)
Если хотите, я могу следующим сообщением дать вам точную последовательность кликов для русской UI Zabbix и отдельно — как проверить по логу, выполняется ли item на server или на proxy.
Выставлено время ожидания
Время ожидания: Override = 30s
Таймаут вы уже устранили. Сейчас проблема другая: зависимые items получают невалидный или пустой JSON от master item, поэтому часть полей падает, а часть показывает 0. В шаблоне автора это поведение штатное: Days Left, Days Since Expired и Expire Date имеют JSONPath и при ошибке подставляют 0, а Message и State такого fallback не имеют, поэтому уходят в Preprocessing failed. В оригинальном шаблоне также есть только один master item — Check Domain; items Message и State должны брать данные именно из него. (GitHub)
У вас на скрине видно сразу две вероятные причины.
State настроен неправильно.
Вы пишете, что у State ошибка по пути $.message. Это неверно. В оригинальном шаблоне должно быть так:
Message → $.messageState → $.stateState стоит $.message, исправьте preprocessing вручную. В YAML шаблона это именно так и задано. (GitHub)У вас, похоже, появился лишний item Get data.
В оригинальном шаблоне из репозитория item Get data вообще отсутствует — там есть только Check Domain как master item и зависимые Days Left, Days Since Expired, Expire Date, Message, State. Если у вас одновременно есть и Check Domain, и Get data, значит шаблон был изменён или рядом создан дублирующий item. Тогда очень вероятно, что один item получает JSON, а зависимые items смотрят в другой — пустой. (GitHub)
Что сделать по шагам.
ts-support.ru → Элементы данных.Days Left, Days Since Expired, Expire Date, Message, State должны быть Зависимый элемент данных / Dependent item.Check Domain, и Get data, оставьте один рабочий master item. Второй либо удалите, либо убедитесь, что все dependent items привязаны именно к нему.Message проверьте preprocessing:
textJSONPath: $.message
State проверьте preprocessing:
textJSONPath: $.state
Days Left:
textJSONPath: $.days_left
Days Since Expired:
textJSONPath: $.days_since_expired
Expire Date:
textJSONPath: $.expire_date
Если там пустая строка или текст ошибки — зависимые items будут вести себя ровно так, как сейчас. В external checks Zabbix берёт в item value stdout/stderr скрипта, а при timeout или ошибке item становится unsupported. (Zabbix)json{"state":"OK","days_left":178,"days_since_expired":0,"expire_date":"2026-10-11","message":"State: OK ; Days left: 178 ; Expire date: 2026-10-11"}
Ещё один важный момент по вашему ts-support.ru: раньше вы поменяли key на {$DOMAIN}. На хосте artek-braiding.ru у вас макрос {$DOMAIN} был, а на скрине ts-support.ru видно уже 3 макроса, а не 4. Проверьте, что на этом хосте тоже есть:
text{$DOMAIN}=ts-support.ru
Если key использует {$DOMAIN}, а макроса на хосте нет, master item будет работать некорректно. Это уже видно не из документации, а по вашим скринам.
Теперь по пункту “доступность в Zabbix неактивна”.
Для этого шаблона активировать ничего не нужно. External check выполняется на Zabbix server или proxy, и не требует агента на проверяемом хосте. Иконка доступности host interface относится к интерфейсам Agent/SNMP/IPMI/JMX, а не к external checks. (Zabbix)
Поэтому:
ts-support.ru — это просто “хост-заглушка” для контроля срока домена, игнорируйте agent availability;zabbix-agent на сервере за этим DNS, открыть 10050/tcp, указать в интерфейсе хоста реальный IP/DNS этого сервера и иметь agent items. Иначе доступность агента зелёной не станет. Статусы интерфейсов меняются только для агентских/SNMP/IPMI/JMX проверок. (Zabbix)Самый быстрый путь к исправлению сейчас такой:
ts-support.ru добавьте {$DOMAIN}=ts-support.ru, если key использует {$DOMAIN}.Get data или привяжите все dependent items к одному master item.State на $.state.Почти наверняка после этого Message и State оживут, а нули исчезнут.
Пришлите скрин карточки item State (вкладка “Предобработка”) и карточки item Get data / Check Domain, и я скажу точно, что именно у вас лишнее и что удалить.
Еще раз по порядку:
Домен artek-braiding.ru
К домену привязаны два шаблона: Website certificate by Zabbix agent 2 и Domain Expiry
item Get data принадлежит шаблону Website certificate by Zabbix agent 2
Домен ts-support.ru
Спасибо, теперь картина понятна.
Главное: у вас смешались два разных шаблона.
Domain ExpiryЭто шаблон для проверки срока регистрации домена.
Для него важны только:
Check Domain — master itemDays LeftDays Since ExpiredExpire DateMessageStateWebsite certificate by Zabbix agent 2Это другой шаблон.
Get data относится к нему, а не к Domain Expiry.
То есть ошибку у Get data не надо сейчас смешивать с проблемой Check Domain.
artek-braiding.ruУ вас в Check Domain сейчас ключ такой логики:
textcheck_domain.sh["-d",{$HOSTNAME},"-r",{$RDAP_SERVER},"-s",{$WHOIS_SERVER}]
И на хосте есть макрос:
text{$HOSTNAME}=artek-braiding.ru
Это может работать, но я бы не советовал использовать {$HOSTNAME}.
Он слишком похож на системные макросы Zabbix и потом путает диагностику.
Лучше сделать отдельный макрос:
text{$DOMAIN}=artek-braiding.ru
и использовать его в key.
Days Left / Expire Date = 0, а Message / State падаютЭто почти всегда означает следующее:
Check Domain не отдает нормальный JSON0Message и State падают на JSONPathТо есть проблема сейчас не в preprocessing Message/State — у них он у вас уже правильный:
Message → $.messageState → $.stateПроблема в родительском item Check Domain.
Get dataДля Domain Expiry сейчас смотрим только на:
Check DomainGet data пока игнорируем.
{$HOSTNAME} на {$DOMAIN}На хосте artek-braiding.ru:
text{$DOMAIN}=artek-braiding.ru
{$HOSTNAME} пока можно, но лучше потом удалить, чтобы не путатьсяCheck DomainВ Check Domain поставьте такой ключ:
textcheck_domain.sh["-d","{$DOMAIN}","-r","{$RDAP_SERVER}","-s","{$WHOIS_SERVER}","-w","{$EXP_WARN}","-c","{$EXP_CRIT}"]
Именно в таком виде, с кавычками.
50sУ вас на скрине он до сих пор стоит.
Это надо убрать.
Сделайте так:
Check DomaintextПеременный | 50s | 1-7,00:00-24:00
textИнтервал обновления = 1d
Для домена этого достаточно.
Это правильно:
textВремя ожидания = Замещение = 30s
Оставляем как есть.
У вас на скрине открыта вкладка “Макросы узла сети”, а не “Макросы узла сети и унаследованные”.
Нужно обязательно проверить, что от шаблона Domain Expiry реально приходят:
{$RDAP_SERVER}{$WHOIS_SERVER}{$EXP_WARN}{$EXP_CRIT}Откройте:
Хост → Макросы → Макросы узла сети и унаследованные
И проверьте, что эти макросы там есть и не пустые.
Если их нет — Check Domain будет отрабатывать криво.
Check DomainПосле изменений:
Check DomainCheck DomainДолжен прийти JSON примерно такого вида:
json{"state":"OK","days_left":178,"days_since_expired":0,"expire_date":"2026-10-11","message":"State: OK ; Days left: 178 ; Expire date: 2026-10-11"}
Значит проблема всё ещё в key/macro.
Тогда Days Left, Expire Date, Message, State начнут заполняться.
Это лучший тест, чтобы сразу понять, где ошибка — в макросе или нет.
Временно поставьте в Check Domain такой key:
textcheck_domain.sh["-d","artek-braiding.ru","-r","{$RDAP_SERVER}","-s","{$WHOIS_SERVER}","-w","{$EXP_WARN}","-c","{$EXP_CRIT}"]
Потом нажмите Тест или Выполнить сейчас.
Значит проблема точно в макросе {$HOSTNAME} / {$DOMAIN}.
Тогда уже надо смотреть, что реально получает item при выполнении.
ts-support.ruDomain ExpiryТогда доступность агента можно вообще не трогать.
Для External check она не нужна.
То есть:
Check DomainТогда это уже отдельная задача.
Нужно, чтобы на том узле, который указан в интерфейсе хоста, реально работал zabbix-agent или zabbix-agent2.
У вас интерфейс хоста выглядит как:
text127.0.0.1:10050
Это значит: Zabbix пытается достучаться до агента на локальном сервере.
10050Server=...ServerActive=...Hostname=...bashzabbix_get -s 127.0.0.1 -p 10050 -k agent.ping
Если вернет 1, агент доступен.
Для artek-braiding.ru:
text{$DOMAIN}=artek-braiding.ru
textcheck_domain.sh["-d","{$DOMAIN}","-r","{$RDAP_SERVER}","-s","{$WHOIS_SERVER}","-w","{$EXP_WARN}","-c","{$EXP_CRIT}"]
Удалить интервал 50s
Оставить timeout 30s
Проверить вкладку унаследованных макросов
Нажать Выполнить сейчас у Check Domain
Посмотреть сырое значение Check Domain
Сейчас у вас:
Get data — это другой шаблон, его не трогаемMessage и State настроены правильноCheck Domain не возвращает нормальный JSON в самом ZabbixПришлите одним сообщением:
Check DomainТогда я скажу уже точно, что именно у вас ломает Check Domain.
скрипт возвращает нулевое значение
Сейчас у вас уже не проблема тайм-аута.
Проблема в другом: master item Check Domain отдает в Zabbix невалидный JSON, поэтому:
Days Left, Days Since Expired, Expire Date показывают 0, потому что в шаблоне у этих dependent items задан JSONPath с fallback-значением 0 при ошибке предобработки;Message и State уходят в Unsupported, потому что у них такого fallback нет. Это ровно так и описано в YAML шаблона. (GitHub)То есть скрипт не “возвращает ноль”.
0 подставляет сам Zabbix, когда не может распарсить ответ Check Domain. (GitHub)
Самая вероятная причина у вас такая: в ответ Check Domain попадает не только JSON, а еще какой-то лишний текст. Это особенно похоже на вашу раннюю строку лога Starting check for .... Для external checks Zabbix берет stdout вместе со stderr как значение item, а в самом check_domain.sh еще и стоит exec 2>&1, то есть stderr принудительно смешивается со stdout. Если в скрипте есть любые echo, debug или логирование в stderr/stdout, JSON ломается. (Zabbix)
Плюс у вас пустые {$RDAP_SERVER} и {$WHOIS_SERVER} — это нормально для этого шаблона: README и сам скрипт допускают пустые значения для стандартного lookup, а check_domain.sh специально преобразует пустые -r "" и -s "" во внутреннее значение 0. Это не выглядит корневой причиной. (GitHub)
Что сделать по порядку.
textcheck_domain.sh["-d","{$DOMAIN}","-r","{$RDAP_SERVER}","-s","{$WHOIS_SERVER}","-w","{$EXP_WARN}","-c","{$EXP_CRIT}"]
или оригинальный из шаблона:
textcheck_domain.sh["-d",{HOST.HOST},"-r",{$RDAP_SERVER},"-s",{$WHOIS_SERVER},"-w",{$EXP_WARN},"-c",{$EXP_CRIT}]
Оригинальный шаблон вообще рассчитан на вариант, где домен — это Host name. (GitHub)
bashsudo -u zabbix /usr/lib/zabbix/externalscripts/check_domain.sh \ -d ts-support.ru \ -r "" \ -s "" \ -w 14 \ -c 7 | sed -n 'l'
Нормальный результат должен быть одной строкой JSON, которая начинается с { и ничем, кроме JSON, не сопровождается.
textStarting check for ts-support.ru {"state":"OK", ...}
или любые INFO, DEBUG, ERROR, пустые строки перед JSON — это и есть причина. Для dependent items нужен чистый JSON и только JSON. Zabbix для external checks использует и stdout, и stderr, так что лишний текст ломает JSONPath. (Zabbix)
check_domain.sh, уберите все обычные echo из stdout/stderr. Лог пишите только явно в файл, например так:shecho "$(date): Starting check for $domain" >> /var/log/check_domain.log
и не используйте вывод в консоль для служебных сообщений. С учетом exec 2>&1 в этом скрипте любая консольная диагностика попадет в значение item. (GitHub)
Check Domain:Check DomainHistory не 0, а 1dВыполнить сейчасИсторияТак вы увидите сырой текст, который реально получил Zabbix. Если там не чистый JSON — причина подтверждена.
Days Left перестанет быть 0Expire Date заполнится датойMessage и State выйдут из UnsupportedИ еще отдельно: если хост используется только под Domain Expiry, доступность агента вам не нужна — external checks выполняются на Zabbix server/proxy и не требуют агента на самом домене. (Zabbix)
Итог:
у вас сейчас ломается не логика вычисления даты, а формат ответа master item Check Domain. Почти наверняка в него попадает лишний текст помимо JSON.
Пришлите вывод вот этой точной команды:
bashsudo -u zabbix /usr/lib/zabbix/externalscripts/check_domain.sh \ -d ts-support.ru \ -r "" \ -s "" \ -w 14 \ -c 7 | sed -n 'l'
По нему сразу будет видно, что именно портит JSON.
Все заработало, кроме доменов pjys .pro
root@SRV-ZABBIX:# sudo -u zabbix /usr/lib/zabbix/externalscripts/check_domain.sh -d readsense.pro# sudo -u zabbix /usr/lib/zabbix/externalscripts/check_domain.sh -d ca.greengene.pro
{"state":"UNKNOWN","days_left":0,"days_since_expired":0,"expire_date":"unknown","message":"State: UNKNOWN ; No expiration date found for readsense.pro"}
root@SRV-ZABBIX:
{"state":"UNKNOWN","days_left":0,"days_since_expired":0,"expire_date":"unknown","message":"State: UNKNOWN ; No expiration date found for ca.greengene.pro"}
root@SRV-ZABBIX:~# sudo -u zabbix /usr/lib/zabbix/externalscripts/check_domain.sh -d fablab.pro
{"state":"UNKNOWN","days_left":0,"days_since_expired":0,"expire_date":"unknown","message":"State: UNKNOWN ; No expiration date found for fablab.pro"}
Да, тут уже не проблема Zabbix.
Для .pro у вас упирается именно в получение даты истечения из публичных данных.
Что видно по вашим примерам:
readsense.pro и fablab.pro возвращают UNKNOWN с текстом No expiration date foundca.greengene.pro — это вообще субдомен, а не отдельно зарегистрированный домен, поэтому у него своей даты регистрации/истечения обычно нет; для такого случая нужно мониторить greengene.pro, а не ca.greengene.pro. Субдомены обычно не регистрируются у регистратора отдельно, а создаются внутри родительского домена через DNS. (World Trademark Review)Почему именно .pro ведет себя иначе:
a-stoyanov/zabbix-domain-expiry сначала пытается взять дату через RDAP, и только если не получилось — падает обратно в WHOIS; это прямо указано в README и видно в коде check_domain.sh. В коде он ищет дату в RDAP через .events[] | select(.eventAction | test("expiration")) | .eventDate, а при пустом результате уходит в WHOIS. (GitHub).pro IANA указывает RDAP-сервер https://rdap.identitydigital.services/rdap/, а оператором зоны указан Identity Digital Domains Limited. (Iana).pro опираться на WHOIS fallback уже ненадежно. (Identity Digital)Что это значит на практике:
ca.greengene.pro уберите из этого шаблона
Мониторьте:
textgreengene.pro
а не:
textca.greengene.pro
Для readsense.pro и fablab.pro явно задайте RDAP-сервер на хосте:
text{$RDAP_SERVER}=https://rdap.identitydigital.services/rdap/
Это соответствует RDAP-серверу для .pro по IANA. (Iana)
После этого проверьте вручную с debug:
bashsudo -u zabbix /usr/lib/zabbix/externalscripts/check_domain.sh \ -d readsense.pro \ -r 'https://rdap.identitydigital.services/rdap/' \ -z
И отдельно:
bashsudo -u zabbix /usr/lib/zabbix/externalscripts/check_domain.sh \ -d fablab.pro \ -r 'https://rdap.identitydigital.services/rdap/' \ -z
Посмотрите, что реально приходит из RDAP:
bashcurl -s 'https://rdap.identitydigital.services/rdap/domain/readsense.pro' | jq '.events' curl -s 'https://rdap.identitydigital.services/rdap/domain/fablab.pro' | jq '.events'
Как интерпретировать результат:
.events есть событие с eventAction вроде expiration или registrar expiration, но скрипт всё равно пишет UNKNOWN, значит нужен патч парсинга в check_domain.sh; скрипт как раз берет дату из events, так что в этом случае дело в формате ответа. (GitHub).events нет никакой даты окончания, значит публичный RDAP для этого домена ее не отдает, и шаблон тут уже ничего не вычислит — это ограничение источника данных, а не Zabbix. С учетом того, что WHOIS для Identity Digital уже убран, fallback тоже не поможет. (Identity Digital)Самый вероятный итог по вашим трём именам такой:
ca.greengene.pro — не подходит для шаблона, потому что это субдомен. (World Trademark Review)readsense.pro и fablab.pro — нужно проверить публичный RDAP-ответ; если там нет даты истечения, этот шаблон их не сможет считать корректно. (GitHub)Пришлите вывод двух команд:
bashcurl -s 'https://rdap.identitydigital.services/rdap/domain/readsense.pro' | jq '.events' curl -s 'https://rdap.identitydigital.services/rdap/domain/fablab.pro' | jq '.events'
По ним можно будет точно сказать: нужен патч скрипта или у регистратора просто нет публичной даты истечения.
readsense.pro и fablab.pro заработало
root@SRV-ZABBIX:~# sudo -u zabbix /usr/lib/zabbix/externalscripts/check_domain.sh -d fablab.pro -r 'https://rdap.identitydigital.services/rdap/' -z
INFO [10:16:32]: Set debug=true
INFO [10:16:32]: Processing argument: --, remaining args: --
INFO [10:16:32]: Entering -- case
INFO [10:16:32]: Successfully completed parsing. domain=fablab.pro, whois_server=0, rdap_server=https://rdap.identitydigital.services/rdap/, warning=30, critical=7
INFO [10:16:32]: Exiting parse_arguments
INFO [10:16:32]: Parsed arguments
INFO [10:16:32]: Checking dependencies
INFO [10:16:32]: Dependencies checked
INFO [10:16:32]: Reached main execution block after parse_arguments
INFO [10:16:32]: Outfile set to: /tmp/check_domain.8A9jUB/whois_output.txt
INFO [10:16:32]: Starting RDAP lookup for fablab.pro
INFO [10:16:32]: No RDAP URL adjustment needed for TLD .pro
INFO [10:16:32]: Using RDAP server: https://rdap.identitydigital.services/rdap/
INFO [10:16:32]: Querying RDAP URL: https://rdap.identitydigital.services/rdap/domain/fablab.pro
INFO [10:16:32]: curl completed with exit code 0
INFO [10:16:32]: Expiration date: 2026-07-01
INFO [10:16:32]: Time calculation: expseconds=1782864000, nowseconds=1776323792, expdays=75, expdate=2026-07-01
INFO [10:16:32]: Days left: 75 ; Exp date: 2026-07-01
INFO [10:16:32]: Entering die() with rc=0, msg='State: OK ; Days left: 75 ; Expire date: 2026-07-01'
INFO [10:16:32]: Cleaning up temporary directory: /tmp/check_domain.8A9jUB and files: /tmp/check_domain.8A9jUB/whois_output.txt /tmp/check_domain.8A9jUB/rdap_bootstrap.json /tmp/check_domain.8A9jUB/error.txt
{"state":"OK","days_left":75,"days_since_expired":0,"expire_date":"2026-07-01","message":"State: OK ; Days left: 75 ; Expire date: 2026-07-01"}
root@SRV-ZABBIX:~# sudo -u zabbix /usr/lib/zabbix/externalscripts/check_domain.sh \
-d readsense.pro
-r 'https://rdap.identitydigital.services/rdap/'
-z
INFO [09:57:44]: Set debug=true
INFO [09:57:44]: Processing argument: --, remaining args: --
INFO [09:57:44]: Entering -- case
INFO [09:57:44]: Successfully completed parsing. domain=readsense.pro, whois_server=0, rdap_server=https://rdap.identitydigital.services/rdap/, warning=30, critical=7
INFO [09:57:44]: Exiting parse_arguments
INFO [09:57:44]: Parsed arguments
INFO [09:57:44]: Checking dependencies
INFO [09:57:44]: Dependencies checked
INFO [09:57:44]: Reached main execution block after parse_arguments
INFO [09:57:44]: Outfile set to: /tmp/check_domain.SLmDL5/whois_output.txt
INFO [09:57:44]: Starting RDAP lookup for readsense.pro
INFO [09:57:44]: No RDAP URL adjustment needed for TLD .pro
INFO [09:57:44]: Using RDAP server: https://rdap.identitydigital.services/rdap/
INFO [09:57:44]: Querying RDAP URL: https://rdap.identitydigital.services/rdap/domain/readsense.pro
INFO [09:57:45]: curl completed with exit code 0
INFO [09:57:45]: Expiration date: 2026-05-11
INFO [09:57:45]: Time calculation: expseconds=1778457600, nowseconds=1776322665, expdays=24, expdate=2026-05-11
INFO [09:57:45]: Days left: 24 ; Exp date: 2026-05-11
INFO [09:57:45]: Entering die() with rc=1, msg='State: WARNING ; Days left: 24 ; Expire date: 2026-05-11'
INFO [09:57:45]: Cleaning up temporary directory: /tmp/check_domain.SLmDL5 and files: /tmp/check_domain.SLmDL5/whois_output.txt /tmp/check_domain.SLmDL5/rdap_bootstrap.json /tmp/check_domain.SLmDL5/error.txt
{"state":"WARNING","days_left":24,"days_since_expired":0,"expire_date":"2026-05-11","message":"State: WARNING ; Days left: 24 ; Expire date: 2026-05-11"}
а greengene.pro нет
root@SRV-ZABBIX:~# sudo -u zabbix /usr/lib/zabbix/externalscripts/check_domain.sh -d greengene.pro -r 'https://rdap.identitydigital.services/rdap/' -z
INFO [10:13:53]: Set debug=true
INFO [10:13:53]: Processing argument: --, remaining args: --
INFO [10:13:53]: Entering -- case
INFO [10:13:53]: Successfully completed parsing. domain=greengene.pro, whois_server=0, rdap_server=https://rdap.identitydigital.services/rdap/, warning=30, critical=7
INFO [10:13:53]: Exiting parse_arguments
INFO [10:13:53]: Parsed arguments
INFO [10:13:53]: Checking dependencies
INFO [10:13:53]: Dependencies checked
INFO [10:13:53]: Reached main execution block after parse_arguments
INFO [10:13:53]: Outfile set to: /tmp/check_domain.GYMIFz/whois_output.txt
INFO [10:13:53]: Starting RDAP lookup for greengene.pro
INFO [10:13:53]: No RDAP URL adjustment needed for TLD .pro
INFO [10:13:53]: Using RDAP server: https://rdap.identitydigital.services/rdap/
INFO [10:13:53]: Querying RDAP URL: https://rdap.identitydigital.services/rdap/domain/greengene.pro
INFO [10:13:54]: curl completed with exit code 22
ERROR [10:13:54]: curl failed for https://rdap.identitydigital.services/rdap/domain/greengene.pro, error: , code: 22, falling back to WHOIS
INFO [10:13:54]: Falling back to WHOIS for greengene.pro
INFO [10:13:54]: Running whois for greengene.pro without specific server
INFO [10:13:55]: Running awk on /tmp/check_domain.GYMIFz/whois_output.txt
INFO [10:13:55]: awk completed with exit code 0, expiration=''
INFO [10:13:55]: No expiration date found in WHOIS data for greengene.pro
INFO [10:13:55]: Entering die() with rc=3, msg='State: UNKNOWN ; No expiration date found for greengene.pro'
INFO [10:13:55]: Cleaning up temporary directory: /tmp/check_domain.GYMIFz and files: /tmp/check_domain.GYMIFz/whois_output.txt /tmp/check_domain.GYMIFz/rdap_bootstrap.json /tmp/check_domain.GYMIFz/error.txt
{"state":"UNKNOWN","days_left":0,"days_since_expired":0,"expire_date":"unknown","message":"State: UNKNOWN ; No expiration date found for greengene.pro"}
root@SRV-ZABBIX:~# curl -s 'https://rdap.identitydigital.services/rdap/domain/greengene.pro' | jq '.events'
null
Да, теперь видно точно: с greengene.pro проблема уже не в Zabbix и не в шаблоне, а в источнике данных.
По вашим логам:
greengene.pro падает с curl exit code 22, то есть сервер вернул HTTP-ошибку при запросе RDAP;UNKNOWN. Для .pro это особенно важно, потому что у зоны .pro официальный RDAP-сервер — https://rdap.identitydigital.services/rdap/, а с 2025 года для gTLD именно RDAP считается основным источником регистрационных данных; при этом Identity Digital отдельно указывает, что традиционный WHOIS у них выведен из эксплуатации для соответствующих зон. (IANA)Что это означает на практике: для readsense.pro и fablab.pro решение найдено правильно — задавать {$RDAP_SERVER}=https://rdap.identitydigital.services/rdap/. Для greengene.pro этот же сервер отвечает ошибкой, а WHOIS не отдает expire_date, значит текущий шаблон неоткуда может взять дату истечения. Это уже ограничение публичных данных, а не ошибка настройки Zabbix. (IANA)
Что делать дальше.
readsense.pro и fablab.pro оставьте на хосте:text{$RDAP_SERVER}=https://rdap.identitydigital.services/rdap/
greengene.pro проверьте, что именно отвечает RDAP, уже не через скрипт, а напрямую:bashcurl -sS -D - -o /tmp/greengene_rdap.json -w '\nHTTP:%{http_code}\n' \ 'https://rdap.identitydigital.services/rdap/domain/greengene.pro' cat /tmp/greengene_rdap.json | jq .
Если там 404, 410 или другой HTTP error, то публичной RDAP-записи для этого имени сейчас нет.
check_domain.sh именно для этого домена/регистратора.greengene.pro лучше не ломать общий мониторинг, а сделать одно из двух:Domain Expiry;UNKNOWN, но отключить/изменить триггеры именно для этого хоста.Итог:
greengene.pro не мониторится через этот шаблон не потому, что он “неправильно настроен”, а потому что публичный RDAP/WHOIS сейчас не отдают для него дату истечения. Для такого домена нужен либо источник от регистратора, либо отдельная логика в скрипте. (ICANN)
Могу помочь написать патч для check_domain.sh, чтобы для greengene.pro он брал дату из API регистратора или из альтернативного источника.
readsense.pro и fablab.pro заработало
root@SRV-ZABBIX:~# sudo -u zabbix /usr/lib/zabbix/externalscripts/check_domain.sh -d fablab.pro -r 'https://rdap.identitydigital.services/rdap/' -z
INFO [10:16:32]: Set debug=true
INFO [10:16:32]: Processing argument: --, remaining args: --
INFO [10:16:32]: Entering -- case
INFO [10:16:32]: Successfully completed parsing. domain=fablab.pro, whois_server=0, rdap_server=https://rdap.identitydigital.services/rdap/, warning=30, critical=7
INFO [10:16:32]: Exiting parse_arguments
INFO [10:16:32]: Parsed arguments
INFO [10:16:32]: Checking dependencies
INFO [10:16:32]: Dependencies checked
INFO [10:16:32]: Reached main execution block after parse_arguments
INFO [10:16:32]: Outfile set to: /tmp/check_domain.8A9jUB/whois_output.txt
INFO [10:16:32]: Starting RDAP lookup for fablab.pro
INFO [10:16:32]: No RDAP URL adjustment needed for TLD .pro
INFO [10:16:32]: Using RDAP server: https://rdap.identitydigital.services/rdap/
INFO [10:16:32]: Querying RDAP URL: https://rdap.identitydigital.services/rdap/domain/fablab.pro
INFO [10:16:32]: curl completed with exit code 0
INFO [10:16:32]: Expiration date: 2026-07-01
INFO [10:16:32]: Time calculation: expseconds=1782864000, nowseconds=1776323792, expdays=75, expdate=2026-07-01
INFO [10:16:32]: Days left: 75 ; Exp date: 2026-07-01
INFO [10:16:32]: Entering die() with rc=0, msg='State: OK ; Days left: 75 ; Expire date: 2026-07-01'
INFO [10:16:32]: Cleaning up temporary directory: /tmp/check_domain.8A9jUB and files: /tmp/check_domain.8A9jUB/whois_output.txt /tmp/check_domain.8A9jUB/rdap_bootstrap.json /tmp/check_domain.8A9jUB/error.txt
{"state":"OK","days_left":75,"days_since_expired":0,"expire_date":"2026-07-01","message":"State: OK ; Days left: 75 ; Expire date: 2026-07-01"}
root@SRV-ZABBIX:~# sudo -u zabbix /usr/lib/zabbix/externalscripts/check_domain.sh \
-d readsense.pro
-r 'https://rdap.identitydigital.services/rdap/'
-z
INFO [09:57:44]: Set debug=true
INFO [09:57:44]: Processing argument: --, remaining args: --
INFO [09:57:44]: Entering -- case
INFO [09:57:44]: Successfully completed parsing. domain=readsense.pro, whois_server=0, rdap_server=https://rdap.identitydigital.services/rdap/, warning=30, critical=7
INFO [09:57:44]: Exiting parse_arguments
INFO [09:57:44]: Parsed arguments
INFO [09:57:44]: Checking dependencies
INFO [09:57:44]: Dependencies checked
INFO [09:57:44]: Reached main execution block after parse_arguments
INFO [09:57:44]: Outfile set to: /tmp/check_domain.SLmDL5/whois_output.txt
INFO [09:57:44]: Starting RDAP lookup for readsense.pro
INFO [09:57:44]: No RDAP URL adjustment needed for TLD .pro
INFO [09:57:44]: Using RDAP server: https://rdap.identitydigital.services/rdap/
INFO [09:57:44]: Querying RDAP URL: https://rdap.identitydigital.services/rdap/domain/readsense.pro
INFO [09:57:45]: curl completed with exit code 0
INFO [09:57:45]: Expiration date: 2026-05-11
INFO [09:57:45]: Time calculation: expseconds=1778457600, nowseconds=1776322665, expdays=24, expdate=2026-05-11
INFO [09:57:45]: Days left: 24 ; Exp date: 2026-05-11
INFO [09:57:45]: Entering die() with rc=1, msg='State: WARNING ; Days left: 24 ; Expire date: 2026-05-11'
INFO [09:57:45]: Cleaning up temporary directory: /tmp/check_domain.SLmDL5 and files: /tmp/check_domain.SLmDL5/whois_output.txt /tmp/check_domain.SLmDL5/rdap_bootstrap.json /tmp/check_domain.SLmDL5/error.txt
{"state":"WARNING","days_left":24,"days_since_expired":0,"expire_date":"2026-05-11","message":"State: WARNING ; Days left: 24 ; Expire date: 2026-05-11"}
а greengene.pro нет
root@SRV-ZABBIX:~# sudo -u zabbix /usr/lib/zabbix/externalscripts/check_domain.sh -d greengene.pro -r 'https://rdap.identitydigital.services/rdap/' -z
INFO [10:13:53]: Set debug=true
INFO [10:13:53]: Processing argument: --, remaining args: --
INFO [10:13:53]: Entering -- case
INFO [10:13:53]: Successfully completed parsing. domain=greengene.pro, whois_server=0, rdap_server=https://rdap.identitydigital.services/rdap/, warning=30, critical=7
INFO [10:13:53]: Exiting parse_arguments
INFO [10:13:53]: Parsed arguments
INFO [10:13:53]: Checking dependencies
INFO [10:13:53]: Dependencies checked
INFO [10:13:53]: Reached main execution block after parse_arguments
INFO [10:13:53]: Outfile set to: /tmp/check_domain.GYMIFz/whois_output.txt
INFO [10:13:53]: Starting RDAP lookup for greengene.pro
INFO [10:13:53]: No RDAP URL adjustment needed for TLD .pro
INFO [10:13:53]: Using RDAP server: https://rdap.identitydigital.services/rdap/
INFO [10:13:53]: Querying RDAP URL: https://rdap.identitydigital.services/rdap/domain/greengene.pro
INFO [10:13:54]: curl completed with exit code 22
ERROR [10:13:54]: curl failed for https://rdap.identitydigital.services/rdap/domain/greengene.pro, error: , code: 22, falling back to WHOIS
INFO [10:13:54]: Falling back to WHOIS for greengene.pro
INFO [10:13:54]: Running whois for greengene.pro without specific server
INFO [10:13:55]: Running awk on /tmp/check_domain.GYMIFz/whois_output.txt
INFO [10:13:55]: awk completed with exit code 0, expiration=''
INFO [10:13:55]: No expiration date found in WHOIS data for greengene.pro
INFO [10:13:55]: Entering die() with rc=3, msg='State: UNKNOWN ; No expiration date found for greengene.pro'
INFO [10:13:55]: Cleaning up temporary directory: /tmp/check_domain.GYMIFz and files: /tmp/check_domain.GYMIFz/whois_output.txt /tmp/check_domain.GYMIFz/rdap_bootstrap.json /tmp/check_domain.GYMIFz/error.txt
{"state":"UNKNOWN","days_left":0,"days_since_expired":0,"expire_date":"unknown","message":"State: UNKNOWN ; No expiration date found for greengene.pro"}
root@SRV-ZABBIX:~# curl -s 'https://rdap.identitydigital.services/rdap/domain/greengene.pro' | jq '.events'
null
Отлично, значит для .pro рабочая схема у вас уже найдена: для таких хостов задавайте {$RDAP_SERVER}=https://rdap.identitydigital.services/rdap/. Для зоны .pro именно этот RDAP-сервер указан IANA, а для gTLD с 28 января 2025 года RDAP считается основным источником регистрационных данных; Identity Digital также перевел свои затронутые зоны на RDAP вместо традиционного WHOIS. (IANA)
По greengene.pro вывод уже довольно однозначный: у вас RDAP-запрос падает с HTTP-ошибкой (curl exit code 22), затем fallback на WHOIS не находит дату окончания, поэтому check_domain.sh корректно отдает UNKNOWN. То есть тут сейчас ломается не Zabbix, а сам источник данных для этого конкретного домена. (ICANN)
Что делать дальше.
.pro, которые уже работают, оставьте:text{$RDAP_SERVER}=https://rdap.identitydigital.services/rdap/
greengene.pro сначала выясните, какой именно HTTP-код возвращает RDAP:bashcurl -sS -D - -o /dev/null -w 'HTTP:%{http_code}\n' \ 'https://rdap.identitydigital.services/rdap/domain/greengene.pro'
curl 22 сам по себе означает только HTTP error, но не говорит, что это именно: 404, 403, 429 и т.д. Это важно проверить отдельно.
Если увидите 429 или 403, смотрите на ограничения источника. Identity Digital пишет, что RDDS/WHOIS-запросы ограничиваются и при слишком большом числе запросов с одного IP сервис может начать отклонять обращения. (identity.digital)
Если увидите 404/410 или другой “нет записи”, а WHOIS по-прежнему не дает expire_date, тогда публично доступной даты окончания для greengene.pro у этого шаблона просто нет. В таком случае остаются три практичных варианта:
Domain Expiry или оставить для него отдельное правило без алертов по сроку.В сам item Zabbix не добавляйте -z. Этот флаг нужен только для ручной отладки, потому что его INFO-строки ломают JSON для dependent items.
Я бы сделал так: все рабочие .pro оставить на RDAP Identity Digital, а для greengene.pro либо завести отдельную ручную проверку через регистратора, либо исключить его из общего шаблона, если RDAP/WHOIS не отдают срок окончания.