Netwatch — продвинутые сценарии мониторинга
Netwatch на MikroTik — продвинутые сценарии мониторинга
Базовая статья по Netwatch рассматривает ICMP-проверки и простой failover. На практике этого часто недостаточно: хост может отвечать на ping, но HTTP-сервис на нём не работает, DNS резолвер зависает, VPN-туннель теряет связность, а LTE-модем требует физической перезагрузки. В RouterOS 7.20+ Netwatch поддерживает проверки TCP-connect и HTTP-GET, а в сочетании со скриптами и переменными окружения позволяет строить сложные сценарии мониторинга с комбинированной логикой, уведомлениями в Telegram и автоматическим восстановлением. В этой статье разберём пять продвинутых сценариев, каждый из которых решает реальную задачу на production-сети.
Все команды приведены для RouterOS 7.20+.
Описание
HTTP-мониторинг (проверка кода 200)
Стандартная ICMP-проверка подтверждает только доступность хоста на сетевом уровне. Сервер может отвечать на ping, но веб-приложение возвращает 502 Bad Gateway или 500 Internal Server Error. HTTP-мониторинг в Netwatch решает эту проблему — он выполняет реальный HTTP GET-запрос и проверяет код ответа.
Параметры HTTP-проверки:
- type=http-get — тип проверки
- http-code-min и http-code-max — диапазон допустимых кодов ответа (по умолчанию 100–399)
- host — URL или IP-адрес для проверки
- port — порт (по умолчанию 80)
[admin@MikroTik] ># HTTP-мониторинг веб-сервера — проверка кода 200 /tool/netwatch add host=192.168.88.100 type=http-get port=80 \ http-code-min=200 http-code-max=200 \ interval=30s timeout=5s \ up-script=":log info \"Web server is UP (HTTP 200)\"" \ down-script=":log error \"Web server is DOWN or not returning 200\"" \ comment="HTTP monitor - web server"
Если нужно проверять HTTPS (порт 443), укажите tls=yes:
[admin@MikroTik] >/tool/netwatch add host=my-site.example.com type=http-get port=443 tls=yes \ http-code-min=200 http-code-max=299 \ interval=60s timeout=10s \ up-script=":log info \"HTTPS site is UP\"" \ down-script=":log error \"HTTPS site is DOWN\"" \ comment="HTTPS monitor"
TCP-мониторинг (проверка порта)
TCP-connect проверяет, что определённый порт открыт и принимает соединения. Это полезно для мониторинга сервисов, которые не имеют HTTP-интерфейса: SSH (22), SMTP (25), DNS (53), база данных (3306/5432), VPN-сервис.
[admin@MikroTik] ># TCP-мониторинг SSH-сервера /tool/netwatch add host=10.0.0.5 type=tcp-connect port=22 \ interval=30s timeout=5s \ up-script=":log info \"SSH on 10.0.0.5 is UP\"" \ down-script=":log error \"SSH on 10.0.0.5 is DOWN\"" \ comment="TCP monitor - SSH" # TCP-мониторинг DNS (порт 53) /tool/netwatch add host=10.0.0.1 type=tcp-connect port=53 \ interval=20s timeout=3s \ up-script=":log info \"DNS TCP port is open\"" \ down-script=":log error \"DNS TCP port is closed\"" \ comment="TCP monitor - DNS"
Переменные скриптов и окружение
Netwatch-скрипты выполняются в контексте системного скриптера. Для обмена данными между скриптами используются глобальные переменные:
[admin@MikroTik] ># Установка глобальной переменной в скрипте :global failoverActive false # Чтение переменной в другом скрипте :global failoverActive :if ($failoverActive = true) do={ :log info "Failover is currently active" }
Просмотр всех переменных окружения (полезно для отладки):
[admin@MikroTik] >/system/script/environment/print # Показывает все глобальные переменные, их значения и владельца (кто создал)
Логирование для отладки
При разработке сложных скриптов критически важно видеть, что происходит. Используйте разные уровни логирования:
routeros:log info "Netwatch: нормальное событие" :log warning "Netwatch: предупреждение, требует внимания" :log error "Netwatch: критическая ошибка"
Настройте отдельный topic для Netwatch-скриптов через logging:
[admin@MikroTik] ># Создать действие — запись в отдельный файл /system/logging/action add name=netwatch-log target=disk disk-file-name=netwatch \ disk-lines-per-file=1000 disk-file-count=2 # Создать правило логирования для скриптов /system/logging add topics=script action=netwatch-log
Настройка
Сценарий 1: Auto Failover с восстановлением и Telegram-уведомлениями
Самый востребованный сценарий. При падении WAN1 трафик переключается на WAN2, администратор получает уведомление в Telegram. Когда WAN1 восстанавливается — трафик возвращается обратно, снова приходит уведомление.
Подготовка маршрутов:
[admin@MikroTik] ># Основной провайдер — ether1 (WAN1), gateway 10.0.1.1 /ip/route add dst-address=0.0.0.0/0 gateway=10.0.1.1 distance=1 \ comment="ISP1-primary" # Резервный провайдер — ether2 (WAN2), gateway 10.0.2.1 /ip/route add dst-address=0.0.0.0/0 gateway=10.0.2.1 distance=2 \ comment="ISP2-backup" # Маршрут для проверки через конкретный gateway /ip/route add dst-address=8.8.8.8/32 gateway=10.0.1.1 distance=1 \ comment="Check host via ISP1"
Скрипт отправки в Telegram (создаём отдельный скрипт для переиспользования):
[admin@MikroTik] >/system/script add name=telegram-send dont-require-permissions=no source={ :global telegramBotToken "123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11" :global telegramChatId "-1001234567890" :local message [:tostr $1] :local identity [/system/identity/get name] :local sendMsg ("[".$identity."] ".$message) /tool/fetch url=("https://api.telegram.org/bot".$telegramBotToken.\ "/sendMessage\?chat_id=".$telegramChatId.\ "&text=".$sendMsg.\ "&parse_mode=HTML") \ mode=https keep-result=no }
Netwatch с failover и уведомлениями:
[admin@MikroTik] >/tool/netwatch add host=8.8.8.8 type=icmp interval=10s timeout=3s \ down-script={ :global failoverActive :if ($failoverActive != true) do={ :global failoverActive true :local ts [/system/clock/get time] :log error ("WAN1 DOWN at ".$ts." - activating failover to WAN2") # Снижаем приоритет основного маршрута /ip/route/set [find comment="ISP1-primary"] distance=10 # Уведомление в Telegram :delay 5s :local msg ("<b>WAN1 DOWN</b>\nFailover to WAN2 activated\nTime: ".$ts) /system/script/run [find name=telegram-send] \ ;:global 1 $msg; /system/script/run telegram-send } } \ up-script={ :global failoverActive :if ($failoverActive = true) do={ :global failoverActive false :local ts [/system/clock/get time] :log info ("WAN1 UP at ".$ts." - restoring primary route") # Восстанавливаем приоритет основного маршрута /ip/route/set [find comment="ISP1-primary"] distance=1 # Уведомление в Telegram :delay 5s :local msg ("<b>WAN1 UP</b>\nPrimary route restored\nTime: ".$ts) /system/script/run [find name=telegram-send] \ ;:global 1 $msg; /system/script/run telegram-send } } \ comment="WAN1 failover monitor"
Более надёжный вариант отправки Telegram из down/up-script напрямую:
[admin@MikroTik] >/tool/netwatch add host=8.8.8.8 type=icmp interval=10s timeout=3s \ down-script={ :global failoverActive :if ($failoverActive != true) do={ :global failoverActive true :local ts [/system/clock/get time] :log error ("WAN1 DOWN at ".$ts) /ip/route/set [find comment="ISP1-primary"] distance=10 :delay 3s :global telegramBotToken :global telegramChatId :local identity [/system/identity/get name] :local sendMsg ("[".$identity."] WAN1 DOWN - failover activated at ".$ts) /tool/fetch url=("https://api.telegram.org/bot".$telegramBotToken.\ "/sendMessage\?chat_id=".$telegramChatId."&text=".$sendMsg) \ mode=https keep-result=no } } \ up-script={ :global failoverActive :if ($failoverActive = true) do={ :global failoverActive false :local ts [/system/clock/get time] :log info ("WAN1 UP at ".$ts) /ip/route/set [find comment="ISP1-primary"] distance=1 :delay 3s :global telegramBotToken :global telegramChatId :local identity [/system/identity/get name] :local sendMsg ("[".$identity."] WAN1 UP - primary route restored at ".$ts) /tool/fetch url=("https://api.telegram.org/bot".$telegramBotToken.\ "/sendMessage\?chat_id=".$telegramChatId."&text=".$sendMsg) \ mode=https keep-result=no } } \ comment="WAN1 failover + Telegram"
Не забудьте инициализировать глобальные переменные Telegram при старте:
[admin@MikroTik] >/system/scheduler add name=init-telegram-vars start-time=startup on-event={ :global telegramBotToken "123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11" :global telegramChatId "-1001234567890" :global failoverActive false }
Сценарий 2: DNS-монитор — переключение на резервный DNS
Если ваш основной DNS-сервер перестаёт отвечать, клиенты в сети не могут резолвить доменные имена. Netwatch может автоматически переключать DNS на резервный.
[admin@MikroTik] ># Мониторинг основного DNS (TCP-порт 53) /tool/netwatch add host=10.0.0.53 type=tcp-connect port=53 \ interval=15s timeout=3s \ down-script={ :log warning "Primary DNS 10.0.0.53 is DOWN - switching to backup" /ip/dns/set servers=8.8.8.8,1.1.1.1 # Очистка DNS-кэша для быстрого переключения /ip/dns/cache/flush :log info "DNS switched to 8.8.8.8, 1.1.1.1" } \ up-script={ :log info "Primary DNS 10.0.0.53 is UP - restoring" /ip/dns/set servers=10.0.0.53,8.8.8.8 /ip/dns/cache/flush :log info "DNS restored to primary 10.0.0.53" } \ comment="DNS failover monitor"
Для более надёжной проверки используйте HTTP-GET к DNS-over-HTTPS серверу или комбинируйте с ICMP:
[admin@MikroTik] ># Дополнительная проверка — ping DNS-сервера /tool/netwatch add host=10.0.0.53 type=icmp interval=10s timeout=3s \ down-script={ :log error "DNS server 10.0.0.53 unreachable by ICMP" } \ up-script={ :log info "DNS server 10.0.0.53 reachable again" } \ comment="DNS ping monitor"
Автоматическая проверка DNS-резолвинга через скрипт:
[admin@MikroTik] >/system/scheduler add name=dns-resolve-check interval=1m on-event={ :do { :local result [:resolve "mikrotik.com"] :if ([:len $result] > 0) do={ :log info ("DNS resolve OK: mikrotik.com = ".$result) } } on-error={ :log error "DNS resolve FAILED for mikrotik.com" # Переключение на резервный DNS /ip/dns/set servers=8.8.8.8,1.1.1.1 /ip/dns/cache/flush } }
Сценарий 3: Перезагрузка LTE-модема при потере связи
LTE-модемы (USB или miniPCIe) иногда зависают и требуют физической перезагрузки. Если модем подключён через USB, MikroTik может отключить и включить питание USB-порта, что эквивалентно физическому переподключению.
[admin@MikroTik] ># Мониторинг LTE-соединения через ping до провайдерского gateway /tool/netwatch add host=8.8.4.4 type=icmp interval=30s timeout=10s \ down-script={ :global lteRebootCount :if ([:typeof $lteRebootCount] = "nothing") do={ :global lteRebootCount 0 } # Ограничение: не более 3 перезагрузок подряд :if ($lteRebootCount < 3) do={ :global lteRebootCount ($lteRebootCount + 1) :local ts [/system/clock/get time] :log warning ("LTE DOWN - rebooting USB modem (attempt ".\ $lteRebootCount."/3) at ".$ts) # Способ 1: Отключение питания USB /system/routerboard/usb/power-reset duration=5s :delay 15s # Способ 2: Альтернатива — через AT-команду # /interface/lte/at-chat lte1 input="AT+CFUN=1,1" # Способ 3: Перезапуск LTE-интерфейса /interface/lte/disable [find name=lte1] :delay 5s /interface/lte/enable [find name=lte1] :log info "LTE interface restarted" } else={ :log error ("LTE modem failed after 3 reboot attempts - manual intervention required") } } \ up-script={ :global lteRebootCount 0 :log info "LTE connection restored" } \ comment="LTE modem watchdog"
Важные замечания:
- Команда
/system/routerboard/usb/power-resetдоступна не на всех моделях — зависит от аппаратной платформы. - На моделях с miniPCIe LTE (например, LtAP, SXT LTE) используйте AT-команды:
/interface/lte/at-chat lte1 input="AT+CFUN=1,1"— это программная перезагрузка модема. - Обязательно ограничивайте количество перезагрузок (переменная
lteRebootCount), чтобы не попасть в бесконечный цикл.
Инициализация счётчика при старте:
[admin@MikroTik] >/system/scheduler add name=init-lte-vars start-time=startup on-event={ :global lteRebootCount 0 }
Сценарий 4: Мониторинг VPN-туннеля — перезапуск WireGuard
WireGuard-туннели не имеют встроенного keepalive-механизма определения «мёртвого» пира (в отличие от IPsec DPD). Netwatch может мониторить удалённый адрес WireGuard-пира и перезапускать интерфейс при потере связности.
[admin@MikroTik] ># Предположим: # wireguard1 — WireGuard-интерфейс # 10.10.10.2 — адрес удалённого пира внутри туннеля # Удалённый endpoint: vpn.example.com:13231 /tool/netwatch add host=10.10.10.2 type=icmp interval=20s timeout=5s \ down-script={ :local ts [/system/clock/get time] :log warning ("WireGuard peer 10.10.10.2 DOWN at ".$ts." - restarting tunnel") # Перезапуск WireGuard-интерфейса /interface/wireguard/disable [find name=wireguard1] :delay 3s /interface/wireguard/enable [find name=wireguard1] :delay 5s # Проверяем, поднялся ли интерфейс :local ifStatus [/interface/get wireguard1 running] :if ($ifStatus = true) do={ :log info "WireGuard interface wireguard1 restarted successfully" } else={ :log error "WireGuard interface wireguard1 failed to restart" } } \ up-script={ :log info "WireGuard peer 10.10.10.2 is UP" } \ comment="WireGuard tunnel monitor"
Расширенный вариант — пересоздание пира при смене IP (dynamic DNS):
Если удалённая сторона имеет динамический IP и использует DDNS, может потребоваться обновить endpoint-адрес пира:
[admin@MikroTik] >/tool/netwatch add host=10.10.10.2 type=icmp interval=30s timeout=5s \ down-script={ :local ts [/system/clock/get time] :log warning ("WG peer DOWN at ".$ts." - resolving endpoint and restarting") # Резолвим актуальный IP удалённой стороны :do { :local newIp [:resolve "vpn.example.com"] :local currentEndpoint [/interface/wireguard/peers/get \ [find interface=wireguard1] endpoint-address] :if ($newIp != $currentEndpoint) do={ :log info ("WG endpoint changed: ".$currentEndpoint." -> ".$newIp) /interface/wireguard/peers/set [find interface=wireguard1] \ endpoint-address=$newIp } } on-error={ :log error "Failed to resolve vpn.example.com" } # Перезапуск интерфейса /interface/wireguard/disable wireguard1 :delay 3s /interface/wireguard/enable wireguard1 } \ up-script={ :log info "WireGuard tunnel to 10.10.10.2 is UP" } \ comment="WireGuard DDNS monitor"
Сценарий 5: Комбинированный мониторинг (2 из 3 проверок)
Наиболее сложный, но и наиболее надёжный сценарий. Failover срабатывает только если 2 из 3 проверок (ping, HTTP, DNS) одновременно показывают failure. Это защищает от ложных срабатываний: временный потерянный ping не вызовет переключение, если HTTP и DNS работают.
Концепция: каждый Netwatch-монитор обновляет глобальную переменную-счётчик. Отдельный скрипт по scheduler каждые 30 секунд проверяет, сколько мониторов показывают DOWN, и принимает решение.
Инициализация переменных при старте:
[admin@MikroTik] >/system/scheduler add name=init-combined-monitor start-time=startup on-event={ :global monPingOk true :global monHttpOk true :global monDnsOk true :global combinedFailover false }
Три независимых монитора:
[admin@MikroTik] ># Монитор 1: ICMP (ping) /tool/netwatch add host=8.8.8.8 type=icmp interval=10s timeout=3s \ down-script={ :global monPingOk false :log warning "Combined monitor: PING check FAILED" } \ up-script={ :global monPingOk true :log info "Combined monitor: PING check OK" } \ comment="Combined - ping check" # Монитор 2: HTTP (проверка веб-сервера провайдера или публичного сайта) /tool/netwatch add host=captive.apple.com type=http-get port=80 \ http-code-min=200 http-code-max=200 \ interval=15s timeout=5s \ down-script={ :global monHttpOk false :log warning "Combined monitor: HTTP check FAILED" } \ up-script={ :global monHttpOk true :log info "Combined monitor: HTTP check OK" } \ comment="Combined - HTTP check" # Монитор 3: TCP к DNS (порт 53) /tool/netwatch add host=1.1.1.1 type=tcp-connect port=53 \ interval=10s timeout=3s \ down-script={ :global monDnsOk false :log warning "Combined monitor: DNS check FAILED" } \ up-script={ :global monDnsOk true :log info "Combined monitor: DNS check OK" } \ comment="Combined - DNS check"
Скрипт принятия решения (выполняется по scheduler):
[admin@MikroTik] >/system/script add name=combined-failover-check dont-require-permissions=no source={ :global monPingOk :global monHttpOk :global monDnsOk :global combinedFailover # Подсчёт количества «живых» проверок :local okCount 0 :if ($monPingOk = true) do={ :set okCount ($okCount + 1) } :if ($monHttpOk = true) do={ :set okCount ($okCount + 1) } :if ($monDnsOk = true) do={ :set okCount ($okCount + 1) } :local failCount (3 - $okCount) # Если 2 или более проверок failed — включаем failover :if ($failCount >= 2 && $combinedFailover != true) do={ :global combinedFailover true :local ts [/system/clock/get time] :log error ("COMBINED FAILOVER ACTIVATED at ".$ts.\ " (fails: ".$failCount."/3)") /ip/route/set [find comment="ISP1-primary"] distance=10 # Telegram notification :global telegramBotToken :global telegramChatId :local identity [/system/identity/get name] /tool/fetch url=("https://api.telegram.org/bot".$telegramBotToken.\ "/sendMessage\?chat_id=".$telegramChatId.\ "&text=[".$identity."] FAILOVER: ".$failCount."/3 checks failed") \ mode=https keep-result=no } # Если менее 2 проверок failed — восстанавливаем :if ($failCount < 2 && $combinedFailover = true) do={ :global combinedFailover false :local ts [/system/clock/get time] :log info ("COMBINED FAILOVER DEACTIVATED at ".$ts.\ " (ok: ".$okCount."/3)") /ip/route/set [find comment="ISP1-primary"] distance=1 :global telegramBotToken :global telegramChatId :local identity [/system/identity/get name] /tool/fetch url=("https://api.telegram.org/bot".$telegramBotToken.\ "/sendMessage\?chat_id=".$telegramChatId.\ "&text=[".$identity."] RESTORED: ".$okCount."/3 checks OK") \ mode=https keep-result=no } } # Запуск скрипта каждые 30 секунд /system/scheduler add name=combined-failover-scheduler interval=30s \ on-event="/system/script/run combined-failover-check"
Такой подход значительно снижает количество ложных срабатываний. Единичный пакет, потерянный на ICMP, не вызовет переключение, если HTTP и DNS отвечают.
Проверка
Просмотр статуса всех мониторов
[admin@MikroTik] ># Все Netwatch-записи с текущим статусом /tool/netwatch/print # Columns: HOST, TYPE, INTERVAL, STATUS, SINCE # Подробная информация по конкретному монитору /tool/netwatch/print detail where comment~"WAN1"
Проверка глобальных переменных
[admin@MikroTik] ># Все переменные окружения скриптов /system/script/environment/print # NAME VALUE # failoverActive false # monPingOk true # monHttpOk true # monDnsOk true # combinedFailover false # lteRebootCount 0 # telegramBotToken 123456:ABC... # telegramChatId -100123...
Проверка логов
[admin@MikroTik] ># Все записи, связанные со скриптами /log/print where topics~"script" # Фильтр по ключевому слову /log/print where message~"failover" /log/print where message~"WAN1" /log/print where message~"LTE"
Ручное тестирование скриптов
Перед привязкой скрипта к Netwatch рекомендуется протестировать его вручную:
[admin@MikroTik] ># Запустить скрипт из CLI /system/script/run combined-failover-check # Проверить, что переменные обновились /system/script/environment/print where name~"mon" # Симулировать DOWN — вручную задать переменную :global monPingOk false :global monHttpOk false /system/script/run combined-failover-check # Должен сработать failover # Восстановить :global monPingOk true :global monHttpOk true /system/script/run combined-failover-check # Должен восстановиться
Проверка маршрутов после failover
[admin@MikroTik] ># Текущая таблица маршрутов /ip/route/print where dst-address=0.0.0.0/0 # Проверьте distance — после failover ISP1 должен иметь distance=10 # Трассировка для подтверждения /tool/traceroute 8.8.8.8 count=1 # Первый хоп покажет, через какой gateway идёт трафик
Мониторинг LTE
[admin@MikroTik] ># Статус LTE-интерфейса /interface/lte/print /interface/lte/monitor lte1 once # Информация о сигнале /interface/lte/info lte1 once
Типичные ошибки
1. Скрипт выполняется при каждой проверке, а не при смене статуса
Ошибка: использование /system/scheduler вместо Netwatch для мониторинга. Scheduler выполняет скрипт каждый интервал, а Netwatch — только при смене состояния (UP→DOWN или DOWN→UP).
Решение: используйте Netwatch для событийного мониторинга. Если всё же нужен scheduler — добавьте проверку глобальной переменной, чтобы избежать повторных срабатываний:
[admin@MikroTik] ># Неправильно (scheduler) — отправляет Telegram каждую минуту при DOWN /system/scheduler add interval=1m on-event={ :if ([/ping 8.8.8.8 count=3] = 0) do={ # Это будет выполняться КАЖДУЮ минуту, пока хост DOWN /tool/fetch url="https://api.telegram.org/..." } } # Правильно — Netwatch выполнит скрипт только при СМЕНЕ статуса /tool/netwatch add host=8.8.8.8 type=icmp interval=10s \ down-script={ # Выполнится ОДИН раз при переходе UP → DOWN /tool/fetch url="https://api.telegram.org/..." }
2. Netwatch проверяет хост через не тот интерфейс
Проблема: вы мониторите доступность через WAN1, но ICMP-пакеты уходят через WAN2 (из-за ECMP или failover). Хост доступен через WAN2 → Netwatch показывает UP, хотя WAN1 не работает.
Решение: создайте статический маршрут для проверяемого хоста через конкретный gateway:
[admin@MikroTik] ># Принудительно направляем проверку через WAN1 /ip/route add dst-address=8.8.8.8/32 gateway=10.0.1.1 distance=1 \ comment="Netwatch check via ISP1 only"
3. Ошибки в скриптах не видны
Проблема: скрипт содержит синтаксическую ошибку, Netwatch молча не выполняет его.
Решение: всегда тестируйте скрипт вручную перед привязкой:
[admin@MikroTik] ># Создайте скрипт с тем же содержимым /system/script add name=test-netwatch-script source={ :log info "Test script executed" # Ваш код здесь } /system/script/run test-netwatch-script # Проверьте логи на наличие ошибок /log/print where topics~"script"
4. Бесконечный цикл перезагрузки LTE
Проблема: модем зависает, Netwatch перезагружает его, модем не поднимается, Netwatch снова перезагружает — бесконечный цикл.
Решение: используйте счётчик попыток (переменная lteRebootCount) и ограничьте количество перезагрузок. После превышения лимита — только логирование и уведомление администратору.
5. Telegram-уведомления не отправляются
Проблема: DNS не работает (именно DNS-проблема вызвала failover), и роутер не может разрезолвить api.telegram.org.
Решение: добавьте статический DNS-запись или используйте IP-адрес:
[admin@MikroTik] ># Статическая DNS-запись для Telegram API /ip/dns/static add name=api.telegram.org address=149.154.167.220
Или укажите альтернативный DNS-сервер, доступный через резервный канал:
[admin@MikroTik] ># Убедитесь, что DNS доступен через оба WAN /ip/dns/set servers=8.8.8.8,1.1.1.1
6. HTTP-check показывает DOWN на HTTPS-сайте
Проблема: указан type=http-get с портом 443, но забыли tls=yes.
Решение:
[admin@MikroTik] ># Неправильно /tool/netwatch add host=example.com type=http-get port=443 # Правильно /tool/netwatch add host=example.com type=http-get port=443 tls=yes
7. Переменные теряются после перезагрузки
Проблема: глобальные переменные (failoverActive, lteRebootCount) обнуляются после перезагрузки роутера.
Решение: инициализируйте переменные через scheduler с start-time=startup:
[admin@MikroTik] >/system/scheduler add name=init-global-vars start-time=startup on-event={ :global failoverActive false :global lteRebootCount 0 :global monPingOk true :global monHttpOk true :global monDnsOk true :global combinedFailover false :global telegramBotToken "YOUR_BOT_TOKEN" :global telegramChatId "YOUR_CHAT_ID" :log info "Global variables initialized" }
8. Слишком агрессивный interval и timeout
Проблема: interval=5s, timeout=1s — роутер генерирует много трафика и ложных срабатываний.
Рекомендации:
- Для критических сервисов: interval=10s, timeout=3s
- Для обычного мониторинга: interval=30s, timeout=5s
- Для некритических проверок: interval=60s, timeout=10s
[admin@MikroTik] ># Оптимальные параметры для WAN failover /tool/netwatch/set [find comment~"WAN1"] interval=10s timeout=3s # Оптимальные параметры для HTTP-мониторинга /tool/netwatch/set [find comment~"HTTP"] interval=30s timeout=5s
Отладка: /system/script/environment/print
Команда /system/script/environment/print — ваш главный инструмент отладки сложных скриптов Netwatch. Она показывает все глобальные переменные, их текущие значения и скрипт-владельца:
[admin@MikroTik] >/system/script/environment/print # NAME VALUE OWNER # failoverActive false init-global-vars # monPingOk true Combined - ping check # monHttpOk true Combined - HTTP check # monDnsOk false Combined - DNS check # combinedFailover false combined-failover-check # lteRebootCount 0 init-global-vars # telegramBotToken 123456:ABC... init-global-vars # telegramChatId -100123... init-global-vars
Полезные фильтры:
[admin@MikroTik] ># Только переменные мониторинга /system/script/environment/print where name~"mon" # Удалить «застрявшую» переменную /system/script/environment/remove [find name=failoverActive] # Переопределить значение из CLI :global failoverActive false
При работе с продвинутыми сценариями Netwatch помните: сначала тестируйте каждый скрипт отдельно, потом собирайте в комплексную систему. Используйте глобальные переменные для обмена данными между мониторами. Всегда ограничивайте агрессивные действия (перезагрузки, перезапуски) счётчиками. И обязательно настройте уведомления — автоматика хороша, но администратор должен знать, что происходит в сети.
# HTTP-мониторинг веб-сервера — проверка кода 200
/tool/netwatch
add host=192.168.88.100 type=http-get port=80 \
http-code-min=200 http-code-max=200 \
interval=30s timeout=5s \
up-script=":log info \"Web server is UP (HTTP 200)\"" \
down-script=":log error \"Web server is DOWN or not returning 200\"" \
comment="HTTP monitor - web server"
/tool/netwatch
add host=my-site.example.com type=http-get port=443 tls=yes \
http-code-min=200 http-code-max=299 \
interval=60s timeout=10s \
up-script=":log info \"HTTPS site is UP\"" \
down-script=":log error \"HTTPS site is DOWN\"" \
comment="HTTPS monitor"
# TCP-мониторинг SSH-сервера
/tool/netwatch
add host=10.0.0.5 type=tcp-connect port=22 \
interval=30s timeout=5s \
up-script=":log info \"SSH on 10.0.0.5 is UP\"" \
down-script=":log error \"SSH on 10.0.0.5 is DOWN\"" \
comment="TCP monitor - SSH"
# TCP-мониторинг DNS (порт 53)
/tool/netwatch
add host=10.0.0.1 type=tcp-connect port=53 \
interval=20s timeout=3s \
up-script=":log info \"DNS TCP port is open\"" \
down-script=":log error \"DNS TCP port is closed\"" \
comment="TCP monitor - DNS"
# Установка глобальной переменной в скрипте
:global failoverActive false
# Чтение переменной в другом скрипте
:global failoverActive
:if ($failoverActive = true) do={
:log info "Failover is currently active"
}
/system/script/environment/print
# Показывает все глобальные переменные, их значения и владельца (кто создал)
:log info "Netwatch: нормальное событие"
:log warning "Netwatch: предупреждение, требует внимания"
:log error "Netwatch: критическая ошибка"
# Создать действие — запись в отдельный файл
/system/logging/action
add name=netwatch-log target=disk disk-file-name=netwatch \
disk-lines-per-file=1000 disk-file-count=2
# Создать правило логирования для скриптов
/system/logging
add topics=script action=netwatch-log
# Основной провайдер — ether1 (WAN1), gateway 10.0.1.1
/ip/route
add dst-address=0.0.0.0/0 gateway=10.0.1.1 distance=1 \
comment="ISP1-primary"
# Резервный провайдер — ether2 (WAN2), gateway 10.0.2.1
/ip/route
add dst-address=0.0.0.0/0 gateway=10.0.2.1 distance=2 \
comment="ISP2-backup"
# Маршрут для проверки через конкретный gateway
/ip/route
add dst-address=8.8.8.8/32 gateway=10.0.1.1 distance=1 \
comment="Check host via ISP1"
/system/script
add name=telegram-send dont-require-permissions=no source={
:global telegramBotToken "123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11"
:global telegramChatId "-1001234567890"
:local message [:tostr $1]
:local identity [/system/identity/get name]
:local sendMsg ("[".$identity."] ".$message)
/tool/fetch url=("https://api.telegram.org/bot".$telegramBotToken.\
"/sendMessage\?chat_id=".$telegramChatId.\
"&text=".$sendMsg.\
"&parse_mode=HTML") \
mode=https keep-result=no
}
/tool/netwatch
add host=8.8.8.8 type=icmp interval=10s timeout=3s \
down-script={
:global failoverActive
:if ($failoverActive != true) do={
:global failoverActive true
:local ts [/system/clock/get time]
:log error ("WAN1 DOWN at ".$ts." - activating failover to WAN2")
# Снижаем приоритет основного маршрута
/ip/route/set [find comment="ISP1-primary"] distance=10
# Уведомление в Telegram
:delay 5s
:local msg ("<b>WAN1 DOWN</b>\nFailover to WAN2 activated\nTime: ".$ts)
/system/script/run [find name=telegram-send] \
;:global 1 $msg; /system/script/run telegram-send
}
} \
up-script={
:global failoverActive
:if ($failoverActive = true) do={
:global failoverActive false
:local ts [/system/clock/get time]
:log info ("WAN1 UP at ".$ts." - restoring primary route")
# Восстанавливаем приоритет основного маршрута
/ip/route/set [find comment="ISP1-primary"] distance=1
# Уведомление в Telegram
:delay 5s
:local msg ("<b>WAN1 UP</b>\nPrimary route restored\nTime: ".$ts)
/system/script/run [find name=telegram-send] \
;:global 1 $msg; /system/script/run telegram-send
}
} \
comment="WAN1 failover monitor"
/tool/netwatch
add host=8.8.8.8 type=icmp interval=10s timeout=3s \
down-script={
:global failoverActive
:if ($failoverActive != true) do={
:global failoverActive true
:local ts [/system/clock/get time]
:log error ("WAN1 DOWN at ".$ts)
/ip/route/set [find comment="ISP1-primary"] distance=10
:delay 3s
:global telegramBotToken
:global telegramChatId
:local identity [/system/identity/get name]
:local sendMsg ("[".$identity."] WAN1 DOWN - failover activated at ".$ts)
/tool/fetch url=("https://api.telegram.org/bot".$telegramBotToken.\
"/sendMessage\?chat_id=".$telegramChatId."&text=".$sendMsg) \
mode=https keep-result=no
}
} \
up-script={
:global failoverActive
:if ($failoverActive = true) do={
:global failoverActive false
:local ts [/system/clock/get time]
:log info ("WAN1 UP at ".$ts)
/ip/route/set [find comment="ISP1-primary"] distance=1
:delay 3s
:global telegramBotToken
:global telegramChatId
:local identity [/system/identity/get name]
:local sendMsg ("[".$identity."] WAN1 UP - primary route restored at ".$ts)
/tool/fetch url=("https://api.telegram.org/bot".$telegramBotToken.\
"/sendMessage\?chat_id=".$telegramChatId."&text=".$sendMsg) \
mode=https keep-result=no
}
} \
comment="WAN1 failover + Telegram"
/system/scheduler
add name=init-telegram-vars start-time=startup on-event={
:global telegramBotToken "123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11"
:global telegramChatId "-1001234567890"
:global failoverActive false
}
# Мониторинг основного DNS (TCP-порт 53)
/tool/netwatch
add host=10.0.0.53 type=tcp-connect port=53 \
interval=15s timeout=3s \
down-script={
:log warning "Primary DNS 10.0.0.53 is DOWN - switching to backup"
/ip/dns/set servers=8.8.8.8,1.1.1.1
# Очистка DNS-кэша для быстрого переключения
/ip/dns/cache/flush
:log info "DNS switched to 8.8.8.8, 1.1.1.1"
} \
up-script={
:log info "Primary DNS 10.0.0.53 is UP - restoring"
/ip/dns/set servers=10.0.0.53,8.8.8.8
/ip/dns/cache/flush
:log info "DNS restored to primary 10.0.0.53"
} \
comment="DNS failover monitor"
# Дополнительная проверка — ping DNS-сервера
/tool/netwatch
add host=10.0.0.53 type=icmp interval=10s timeout=3s \
down-script={
:log error "DNS server 10.0.0.53 unreachable by ICMP"
} \
up-script={
:log info "DNS server 10.0.0.53 reachable again"
} \
comment="DNS ping monitor"
/system/scheduler
add name=dns-resolve-check interval=1m on-event={
:do {
:local result [:resolve "mikrotik.com"]
:if ([:len $result] > 0) do={
:log info ("DNS resolve OK: mikrotik.com = ".$result)
}
} on-error={
:log error "DNS resolve FAILED for mikrotik.com"
# Переключение на резервный DNS
/ip/dns/set servers=8.8.8.8,1.1.1.1
/ip/dns/cache/flush
}
}
# Мониторинг LTE-соединения через ping до провайдерского gateway
/tool/netwatch
add host=8.8.4.4 type=icmp interval=30s timeout=10s \
down-script={
:global lteRebootCount
:if ([:typeof $lteRebootCount] = "nothing") do={
:global lteRebootCount 0
}
# Ограничение: не более 3 перезагрузок подряд
:if ($lteRebootCount < 3) do={
:global lteRebootCount ($lteRebootCount + 1)
:local ts [/system/clock/get time]
:log warning ("LTE DOWN - rebooting USB modem (attempt ".\
$lteRebootCount."/3) at ".$ts)
# Способ 1: Отключение питания USB
/system/routerboard/usb/power-reset duration=5s
:delay 15s
# Способ 2: Альтернатива — через AT-команду
# /interface/lte/at-chat lte1 input="AT+CFUN=1,1"
# Способ 3: Перезапуск LTE-интерфейса
/interface/lte/disable [find name=lte1]
:delay 5s
/interface/lte/enable [find name=lte1]
:log info "LTE interface restarted"
} else={
:log error ("LTE modem failed after 3 reboot attempts - manual intervention required")
}
} \
up-script={
:global lteRebootCount 0
:log info "LTE connection restored"
} \
comment="LTE modem watchdog"
/system/scheduler
add name=init-lte-vars start-time=startup on-event={
:global lteRebootCount 0
}
# Предположим:
# wireguard1 — WireGuard-интерфейс
# 10.10.10.2 — адрес удалённого пира внутри туннеля
# Удалённый endpoint: vpn.example.com:13231
/tool/netwatch
add host=10.10.10.2 type=icmp interval=20s timeout=5s \
down-script={
:local ts [/system/clock/get time]
:log warning ("WireGuard peer 10.10.10.2 DOWN at ".$ts." - restarting tunnel")
# Перезапуск WireGuard-интерфейса
/interface/wireguard/disable [find name=wireguard1]
:delay 3s
/interface/wireguard/enable [find name=wireguard1]
:delay 5s
# Проверяем, поднялся ли интерфейс
:local ifStatus [/interface/get wireguard1 running]
:if ($ifStatus = true) do={
:log info "WireGuard interface wireguard1 restarted successfully"
} else={
:log error "WireGuard interface wireguard1 failed to restart"
}
} \
up-script={
:log info "WireGuard peer 10.10.10.2 is UP"
} \
comment="WireGuard tunnel monitor"
/tool/netwatch
add host=10.10.10.2 type=icmp interval=30s timeout=5s \
down-script={
:local ts [/system/clock/get time]
:log warning ("WG peer DOWN at ".$ts." - resolving endpoint and restarting")
# Резолвим актуальный IP удалённой стороны
:do {
:local newIp [:resolve "vpn.example.com"]
:local currentEndpoint [/interface/wireguard/peers/get \
[find interface=wireguard1] endpoint-address]
:if ($newIp != $currentEndpoint) do={
:log info ("WG endpoint changed: ".$currentEndpoint." -> ".$newIp)
/interface/wireguard/peers/set [find interface=wireguard1] \
endpoint-address=$newIp
}
} on-error={
:log error "Failed to resolve vpn.example.com"
}
# Перезапуск интерфейса
/interface/wireguard/disable wireguard1
:delay 3s
/interface/wireguard/enable wireguard1
} \
up-script={
:log info "WireGuard tunnel to 10.10.10.2 is UP"
} \
comment="WireGuard DDNS monitor"
/system/scheduler
add name=init-combined-monitor start-time=startup on-event={
:global monPingOk true
:global monHttpOk true
:global monDnsOk true
:global combinedFailover false
}
# Монитор 1: ICMP (ping)
/tool/netwatch
add host=8.8.8.8 type=icmp interval=10s timeout=3s \
down-script={
:global monPingOk false
:log warning "Combined monitor: PING check FAILED"
} \
up-script={
:global monPingOk true
:log info "Combined monitor: PING check OK"
} \
comment="Combined - ping check"
# Монитор 2: HTTP (проверка веб-сервера провайдера или публичного сайта)
/tool/netwatch
add host=captive.apple.com type=http-get port=80 \
http-code-min=200 http-code-max=200 \
interval=15s timeout=5s \
down-script={
:global monHttpOk false
:log warning "Combined monitor: HTTP check FAILED"
} \
up-script={
:global monHttpOk true
:log info "Combined monitor: HTTP check OK"
} \
comment="Combined - HTTP check"
# Монитор 3: TCP к DNS (порт 53)
/tool/netwatch
add host=1.1.1.1 type=tcp-connect port=53 \
interval=10s timeout=3s \
down-script={
:global monDnsOk false
:log warning "Combined monitor: DNS check FAILED"
} \
up-script={
:global monDnsOk true
:log info "Combined monitor: DNS check OK"
} \
comment="Combined - DNS check"
/system/script
add name=combined-failover-check dont-require-permissions=no source={
:global monPingOk
:global monHttpOk
:global monDnsOk
:global combinedFailover
# Подсчёт количества «живых» проверок
:local okCount 0
:if ($monPingOk = true) do={ :set okCount ($okCount + 1) }
:if ($monHttpOk = true) do={ :set okCount ($okCount + 1) }
:if ($monDnsOk = true) do={ :set okCount ($okCount + 1) }
:local failCount (3 - $okCount)
# Если 2 или более проверок failed — включаем failover
:if ($failCount >= 2 && $combinedFailover != true) do={
:global combinedFailover true
:local ts [/system/clock/get time]
:log error ("COMBINED FAILOVER ACTIVATED at ".$ts.\
" (fails: ".$failCount."/3)")
/ip/route/set [find comment="ISP1-primary"] distance=10
# Telegram notification
:global telegramBotToken
:global telegramChatId
:local identity [/system/identity/get name]
/tool/fetch url=("https://api.telegram.org/bot".$telegramBotToken.\
"/sendMessage\?chat_id=".$telegramChatId.\
"&text=[".$identity."] FAILOVER: ".$failCount."/3 checks failed") \
mode=https keep-result=no
}
# Если менее 2 проверок failed — восстанавливаем
:if ($failCount < 2 && $combinedFailover = true) do={
:global combinedFailover false
:local ts [/system/clock/get time]
:log info ("COMBINED FAILOVER DEACTIVATED at ".$ts.\
" (ok: ".$okCount."/3)")
/ip/route/set [find comment="ISP1-primary"] distance=1
:global telegramBotToken
:global telegramChatId
:local identity [/system/identity/get name]
/tool/fetch url=("https://api.telegram.org/bot".$telegramBotToken.\
"/sendMessage\?chat_id=".$telegramChatId.\
"&text=[".$identity."] RESTORED: ".$okCount."/3 checks OK") \
mode=https keep-result=no
}
}
# Запуск скрипта каждые 30 секунд
/system/scheduler
add name=combined-failover-scheduler interval=30s \
on-event="/system/script/run combined-failover-check"
# Все Netwatch-записи с текущим статусом
/tool/netwatch/print
# Columns: HOST, TYPE, INTERVAL, STATUS, SINCE
# Подробная информация по конкретному монитору
/tool/netwatch/print detail where comment~"WAN1"
# Все переменные окружения скриптов
/system/script/environment/print
# NAME VALUE
# failoverActive false
# monPingOk true
# monHttpOk true
# monDnsOk true
# combinedFailover false
# lteRebootCount 0
# telegramBotToken 123456:ABC...
# telegramChatId -100123...
# Все записи, связанные со скриптами
/log/print where topics~"script"
# Фильтр по ключевому слову
/log/print where message~"failover"
/log/print where message~"WAN1"
/log/print where message~"LTE"
# Запустить скрипт из CLI
/system/script/run combined-failover-check
# Проверить, что переменные обновились
/system/script/environment/print where name~"mon"
# Симулировать DOWN — вручную задать переменную
:global monPingOk false
:global monHttpOk false
/system/script/run combined-failover-check
# Должен сработать failover
# Восстановить
:global monPingOk true
:global monHttpOk true
/system/script/run combined-failover-check
# Должен восстановиться
# Текущая таблица маршрутов
/ip/route/print where dst-address=0.0.0.0/0
# Проверьте distance — после failover ISP1 должен иметь distance=10
# Трассировка для подтверждения
/tool/traceroute 8.8.8.8 count=1
# Первый хоп покажет, через какой gateway идёт трафик
# Статус LTE-интерфейса
/interface/lte/print
/interface/lte/monitor lte1 once
# Информация о сигнале
/interface/lte/info lte1 once
# Неправильно (scheduler) — отправляет Telegram каждую минуту при DOWN
/system/scheduler add interval=1m on-event={
:if ([/ping 8.8.8.8 count=3] = 0) do={
# Это будет выполняться КАЖДУЮ минуту, пока хост DOWN
/tool/fetch url="https://api.telegram.org/..."
}
}
# Правильно — Netwatch выполнит скрипт только при СМЕНЕ статуса
/tool/netwatch add host=8.8.8.8 type=icmp interval=10s \
down-script={
# Выполнится ОДИН раз при переходе UP → DOWN
/tool/fetch url="https://api.telegram.org/..."
}
# Принудительно направляем проверку через WAN1
/ip/route
add dst-address=8.8.8.8/32 gateway=10.0.1.1 distance=1 \
comment="Netwatch check via ISP1 only"
# Создайте скрипт с тем же содержимым
/system/script
add name=test-netwatch-script source={
:log info "Test script executed"
# Ваш код здесь
}
/system/script/run test-netwatch-script
# Проверьте логи на наличие ошибок
/log/print where topics~"script"
# Статическая DNS-запись для Telegram API
/ip/dns/static
add name=api.telegram.org address=149.154.167.220
# Убедитесь, что DNS доступен через оба WAN
/ip/dns/set servers=8.8.8.8,1.1.1.1
# Неправильно
/tool/netwatch add host=example.com type=http-get port=443
# Правильно
/tool/netwatch add host=example.com type=http-get port=443 tls=yes
/system/scheduler
add name=init-global-vars start-time=startup on-event={
:global failoverActive false
:global lteRebootCount 0
:global monPingOk true
:global monHttpOk true
:global monDnsOk true
:global combinedFailover false
:global telegramBotToken "YOUR_BOT_TOKEN"
:global telegramChatId "YOUR_CHAT_ID"
:log info "Global variables initialized"
}
# Оптимальные параметры для WAN failover
/tool/netwatch/set [find comment~"WAN1"] interval=10s timeout=3s
# Оптимальные параметры для HTTP-мониторинга
/tool/netwatch/set [find comment~"HTTP"] interval=30s timeout=5s
/system/script/environment/print
# NAME VALUE OWNER
# failoverActive false init-global-vars
# monPingOk true Combined - ping check
# monHttpOk true Combined - HTTP check
# monDnsOk false Combined - DNS check
# combinedFailover false combined-failover-check
# lteRebootCount 0 init-global-vars
# telegramBotToken 123456:ABC... init-global-vars
# telegramChatId -100123... init-global-vars
# Только переменные мониторинга
/system/script/environment/print where name~"mon"
# Удалить «застрявшую» переменную
/system/script/environment/remove [find name=failoverActive]
# Переопределить значение из CLI
:global failoverActive false