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

Мониторинг портов (ожидаемое состояние)

Монитор портов периодически проверяет список TCP-портов на хосте и сравнивает фактическое состояние с ожидаемым. Алерт уходит не тогда, когда порт «недоступен», а тогда, когда состояние расходится с тем, что вы задали:

  • ожидаемо-открытый порт вдруг закрылся (упал сервис, отвалился firewall-rule);
  • порт, который должен быть закрыт, вдруг открылся (поднялся лишний сервис, кто-то выставил БД наружу, проброс остался после деплоя).

Это инструмент про постоянство конфигурации, а не про «жив ли сервис». Вы фиксируете эталон («22 и 443 открыты» или «5432 снаружи закрыт») — Notifly сигналит при любом отклонении от него.

ИнструментВопрос, на который отвечаетКогда брать
Монитор портов«Эти конкретные порты в нужном состоянии?»следить за эталоном open/closed по списку портов
Монитор kind: "tcp"«Этот один порт открыт / отвечает?»проверить доступность одного сервиса (handshake)
Сканирование портов«А что вообще открыто на хосте?»разовое или периодическое обнаружение открытых портов

Грубо: kind: "tcp" — проверка одного порта на жизнь, port-scan — разведка («покажи всё открытое»), а port-monitor — контроль того, что заранее известный набор портов держит заранее известное состояние.

  1. Раз в intervalSec Notifly открывает TCP-соединение (handshake) с каждым портом из expectedPorts на host — до 16 портов параллельно, с таймаутом timeoutSec на порт.
  2. Порт считается открытым, если соединение установилось, и закрытым, если пришёл отказ или истёк таймаут.
  3. Результат сравнивается с режимом alertMode:
    • alertMode: "closed" — порты из expectedPorts должны быть открыты; алерт, когда ожидаемо-открытый порт закрылся;
    • alertMode: "open" — порты из expectedPorts должны быть закрыты; алерт, когда такой порт открылся.
  4. Когда все порты возвращаются в ожидаемое состояние, монитор снова up и (если задан recoveryMessage) уходит сообщение о восстановлении.

Текущий снимок открытых портов хранится в поле lastSeenPorts (CSV вида "22,443") и обновляется на каждой проверке — по нему видно, что монитор «видит» сейчас.

  • Алерт уходит в канал appid с заголовком alertTitle и приоритетом alertPriority. К тексту alertMessage сервер дописывает, что именно случилось — «Закрылись ожидаемые порты: 443» или «Обнаружены открытые порты: 5432», — и строку «Хост: …».
  • Один алерт на падение. Пока монитор в down и алерт уже отправлен (поле alertedAt), повторных алертов нет. Если вы измените через PUT параметры проверки (host, expectedPorts, alertMode, intervalSec, timeoutSec), монитор проверится сразу, а отметка alertedAt снимется — если проблема не ушла, придёт свежий алерт.
  • Восстановление отправляется, только если задан recoveryMessage и о падении действительно был отправлен алерт. Заголовок — recoveryTitle, а если он пуст — Порты восстановлены: <host>; приоритет тот же, что у алерта.

Алерты — обычные сообщения канала, поэтому на них действуют правила канала: в тихие часы их эскалация во внешние методы доставки подавляется, если alertPriority ниже порога прорыва (по умолчанию 8). В активном окне обслуживания проверки идут и пишутся в историю, но алерт о падении не отправляется — если после окна порты всё ещё не в том состоянии, алерт придёт первой же проверкой.

Монитор портов — источник с историей проверок, поэтому он появляется на статус-странице своего канала, а переходы up ↔ down открывают и закрывают там авто-инциденты.

  • Веб-сервер должен слушать 80 и 443. expectedPorts: "80,443", alertMode: "closed" — алерт, если упал nginx или закрылся порт.
  • БД не должна торчать наружу. expectedPorts: "5432,6379,27017", alertMode: "open" — алерт, если Postgres/Redis/Mongo внезапно доступны с публичного адреса.
  • На проде не должно быть отладочных портов. expectedPorts: "9229,5005,8000", alertMode: "open" — ловим забытый debug-порт после релиза.
  • Только публичные адреса. Хост, который резолвится в приватный, loopback- или link-local-адрес (10.x, 192.168.x, 127.0.0.1, 169.254.x и т. п.), при создании и обновлении отклоняется с 400. Та же проверка повторяется при каждом подключении: если DNS-имя позже начнёт указывать на приватный адрес, соединение будет заблокировано.
  • Квота. Каждая проверка монитора — одно событие дневной квоты dailyEvents (независимо от числа портов в списке). Когда квота исчерпана, проверки откладываются до следующих суток — подробнее в Квотах и тарифах.
ПолеТипОбязательноеОписание
appidnumberдаID канала, куда слать алерты (свой или расшаренный с правом отправки)
namestringданазвание монитора, 1–200 символов
hoststringдахост или IP (без / и пробелов), например db.example.com или 203.0.113.10
expectedPortsstringдасписок портов через запятую: "22,80,443"; каждый порт 1–65535
alertModestringда"closed" (ждём открытые порты, алерт при закрытии) или "open" (ждём закрытые порты, алерт при открытии)
intervalSecnumberдапериод проверки в секундах, 60–86400
timeoutSecnumberнеттаймаут на порт в секундах, по умолчанию 5, максимум 10
alertTitlestringнетзаголовок алерта
alertMessagestringдатекст алерта, 1–2000 символов
alertMessageMarkdownboolнеттрактовать текст алерта и восстановления как Markdown
alertPrioritynumberнетприоритет алерта и восстановления, 0–10 (по умолчанию 0)
recoveryTitlestringнетзаголовок сообщения о восстановлении
recoveryMessagestringнеттекст восстановления; пусто = не отправлять

Кроме этих полей, ответ содержит состояние монитора:

  • status — pending (создан или возобновлён, проверок ещё не было), up (всё в ожидаемом состоянии), down (есть отклонение или ошибка проверки) или paused (проверки отключены);
  • lastSeenPorts — открытые порты на последней проверке (CSV);
  • lastError — описание проблемы на последней проверке (пусто, если всё в порядке);
  • lastCheckAt, nextCheckAt — время последней и следующей проверки;
  • alertedAt — когда отправлен алерт о текущем падении (null, если алерта не было);
  • id, created.
  1. Откройте app.notifly.ru → Мониторы → вкладка Порты → подвкладка Мониторы.
  2. Нажмите «Добавить монитор портов» (или «Создать» на странице мониторов → карточка «Открытые порты хоста»).
  3. Укажите название и хост, добавьте порты по одному (ввод + Enter), выберите «Уведомлять когда»: «Порт закрыт» (closed) или «Порт открыт» (open), таймаут на порт, интервал, канал и текст уведомления; при желании включите сообщение о восстановлении.
  4. Кнопкой «Тест» можно прямо в диалоге увидеть, какие порты сейчас открыты/закрыты (вызов POST /port-monitor/test).

Монитор из админки создаётся с приоритетом 5; другой alertPriority задаётся через API. В строке монитора есть кнопка «Просканировать все порты хоста (Discovery)» — она открывает сканирование портов с уже подставленным хостом. Эталон удобно получать и в обратную сторону: завершённый скан превращается в монитор одним запросом POST /port-scan/:id/to-monitor.

Веб-сервер должен слушать 80 и 443 — алерт, если порт закрылся:

Окно терминала
curl -X POST "$NOTIFLY_URL/port-monitor" \
-H "Content-Type: application/json" \
-H "X-Notifly-Key: <api-token>" \
-d '{
"appid": 12345,
"name": "web-1 — 80/443 должны слушать",
"host": "web-1.example.com",
"expectedPorts": "80,443",
"alertMode": "closed",
"intervalSec": 300,
"timeoutSec": 5,
"alertTitle": "Порт закрылся на web-1",
"alertMessage": "Один из ожидаемо-открытых портов (80/443) недоступен.",
"alertPriority": 8,
"recoveryMessage": "Порты web-1 снова открыты."
}'

БД не должна быть доступна снаружи — алерт, если порт открылся:

Окно терминала
curl -X POST "$NOTIFLY_URL/port-monitor" \
-H "Content-Type: application/json" \
-H "X-Notifly-Key: <api-token>" \
-d '{
"appid": 12345,
"name": "Публичный IP — БД не должна торчать",
"host": "203.0.113.10",
"expectedPorts": "5432,6379,27017",
"alertMode": "open",
"intervalSec": 600,
"alertTitle": "База доступна из интернета!",
"alertMessage": "Один из портов БД (5432/6379/27017) открыт на публичном IP.",
"alertPriority": 10
}'

В ответе придёт сохранённый объект монитора (id, status: "pending", nextCheckAt и т. д.); первая проверка запланирована «на сейчас».

PUT /port-monitor/:id принимает тот же полный набор полей, что и создание (включая appid), но канал монитора при обновлении не меняется.

POST /port-monitor/test проверяет порты хоста прямо сейчас и возвращает фактическое состояние — без создания монитора. Удобно, чтобы свериться с эталоном перед созданием:

Окно терминала
curl -X POST "$NOTIFLY_URL/port-monitor/test" \
-H "Content-Type: application/json" \
-H "X-Notifly-Key: <api-token>" \
-d '{ "host": "web-1.example.com", "expectedPorts": "22,80,443,5432", "timeoutSec": 5 }'

Ответ:

{"open": [22, 80, 443], "closed": [5432]}

Здесь таймаут и отказ одинаково попадают в closed, а timeoutSec вне диапазона 1–10 заменяется на 5. Если в expectedPorts нет ни одного корректного порта, вернётся {"open": [], "closed": [], "error": "no ports to scan"}.

Каждая проверка пишется в историю: успех, длительность, текст ошибки и метаданные — openPorts, expectedPorts, alertMode, а при отклонении ещё missing (закрывшиеся ожидаемые порты, режим closed) или opened (открывшиеся порты, режим open). В админке история видна в диалоге редактирования монитора: график проверок и сетка «порт × время», где каждая клетка показывает, был ли порт в нужном состоянии.

Через API: GET /monitor-history/port_monitor/:id — агрегированная история, GET /monitor-history/port_monitor/:id/log?limit=50 — последние записи (до 200) с полем metadata.

  • POST /port-monitor/:id/pause — отключает проверки (статус paused).
  • POST /port-monitor/:id/resume — возвращает монитор в работу (статус pending, проверка планируется «на сейчас»).
Метод и путьНазначение
GET /port-monitorсписок мониторов портов
POST /port-monitorсоздание
POST /port-monitor/testразовая проверка без сохранения
PUT /port-monitor/:idобновление
DELETE /port-monitor/:idудаление
POST /port-monitor/:id/pauseпоставить на паузу
POST /port-monitor/:id/resumeвозобновить

Авторизация — заголовок X-Notifly-Key с API-токеном. Для создания, изменения, удаления и паузы нужен токен с уровнем write (токен read получит 403); токен со скоупом по каналам видит и меняет только мониторы своих каналов. Токены каналов и share-токены на этих ручках не принимаются (403).