mikrotik-wiki.ru
Главная
Загрузка...

Netwatch — продвинутые сценарии мониторинга

RouterOS 7.xМониторинг15 мин130 мар. 2026 г.
TelegramVK

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 помните: сначала тестируйте каждый скрипт отдельно, потом собирайте в комплексную систему. Используйте глобальные переменные для обмена данными между мониторами. Всегда ограничивайте агрессивные действия (перезагрузки, перезапуски) счётчиками. И обязательно настройте уведомления — автоматика хороша, но администратор должен знать, что происходит в сети.

[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"
/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
Мониторинг / Netwatch — продвинутые сценарии мониторинга