Второй интернет-канал в офисе давно перестал быть роскошью: когда падает основной провайдер, встают и телефония, и кассы, и удалённые рабочие столы. MikroTik умеет переключаться на резервный канал автоматически — и в базовом варианте это настраивается за пять минут. Проблема в том, что базовый вариант не срабатывает в самом частом сценарии аварии. Разберём, почему, и соберём схему, которая переключается по фактической доступности интернета, а не по состоянию шлюза.

Исходные данные

  • ISP1 (основной) — на ether1, шлюз 100.64.1.1
  • ISP2 (резервный) — на ether2, шлюз 172.31.2.1
  • RouterOS 7.x (для 6.x синтаксис отличается минимально)

Базовый вариант: два маршрута с разным distance

/ip route add dst-address=0.0.0.0/0 gateway=100.64.1.1 distance=1 check-gateway=ping comment="ISP1 main"
/ip route add dst-address=0.0.0.0/0 gateway=172.31.2.1 distance=2 comment="ISP2 backup"

Логика: активен маршрут с меньшим distance. Если check-gateway=ping перестаёт видеть шлюз ISP1, маршрут помечается недоступным, и трафик уходит через ISP2. NAT — по правилу на каждый интерфейс:

/ip firewall nat add chain=srcnat out-interface=ether1 action=masquerade
/ip firewall nat add chain=srcnat out-interface=ether2 action=masquerade

Схема рабочая, но у неё есть дыра: check-gateway проверяет только шлюз провайдера — железку в соседнем доме. А самая частая авария выглядит иначе: шлюз жив и бодро отвечает на пинги, но дальше него трафик не уходит (обрыв магистрали, проблемы у аплинка). Роутер считает канал исправным и продолжает лить трафик в чёрную дыру.

Правильный вариант: Netwatch по внешнему хосту

Идея: проверять не шлюз, а реальную точку в интернете (например, 1.1.1.1), причём строго через основной канал. Если она недоступна — скриптом выключать основной маршрут.

Шаг 1. Прибиваем маршрут до тестового хоста к ISP1, чтобы проверочный пинг никогда не убегал через резерв:

/ip route add dst-address=1.1.1.1/32 gateway=100.64.1.1 comment="probe via ISP1"

Важно: с этого момента 1.1.1.1 доступен только через ISP1 — не используйте его как DNS на этом роутере, для DNS возьмите другие адреса.

Шаг 2. Netwatch, который дёргает маршруты:

/tool netwatch add host=1.1.1.1 interval=10s timeout=3s \
    down-script="/ip route set [find comment=\"ISP1 main\"] disabled=yes; :log warning \"FAILOVER: ISP1 down, switching to ISP2\"" \
    up-script="/ip route set [find comment=\"ISP1 main\"] disabled=no; :log warning \"FAILOVER: ISP1 restored\""

Теперь при недоступности 1.1.1.1 через основной канал маршрут ISP1 выключается, дефолт переезжает на ISP2 — а Netwatch продолжает проверять 1.1.1.1 через ISP1 (маршрут /32 мы не трогали) и вернёт всё назад, как только канал оживёт. Переключение происходит за 10–15 секунд.

Доводим до продакшена

Защита от ложных срабатываний. Один потерянный хост — ещё не авария: у 1.1.1.1 тоже бывают плохие дни. Надёжнее два Netwatch на разные хосты (1.1.1.1 и 8.8.8.8, оба через маршруты /32 к ISP1), а в down-script добавить проверку соседа — переключаемся, только если недоступны оба:

/tool netwatch add host=8.8.8.8 interval=10s timeout=3s \
    down-script=":if ([/tool netwatch get [find host=1.1.1.1] status] = \"down\") do={/ip route set [find comment=\"ISP1 main\"] disabled=yes; :log warning \"FAILOVER: both probes down, switching to ISP2\"}" \
    up-script="/ip route set [find comment=\"ISP1 main\"] disabled=no; :log warning \"FAILOVER: ISP1 restored\""

И зеркально ту же проверку — в down-script первого Netwatch.

Зависшие соединения. При переключении канала установленные TCP-сессии остаются в connection tracking со старым внешним IP и умирают по таймауту. Телефония и банк-клиенты оживут быстрее, если подчистить трекинг при failover — добавьте в down-script:

/ip firewall connection remove [find]

(на нагруженных роутерах — аккуратнее: сбросятся все сессии, включая живые через ISP2).

Уведомления. Переключение — событие, о котором админ должен узнать раньше клиента. В down/up-script легко добавляется отправка в Telegram через fetch — этой теме посвятим отдельную статью.

Проверка

Не ждите настоящей аварии — устройте учебную. Заблокируйте проверочные хосты на основном канале и посмотрите на поведение:

/ip firewall filter add chain=output dst-address=1.1.1.1 out-interface=ether1 action=drop comment="TEST failover"
/ip firewall filter add chain=output dst-address=8.8.8.8 out-interface=ether1 action=drop comment="TEST failover"
# смотрим лог и активный маршрут:
/log print where message~"FAILOVER"
/ip route print where dst-address=0.0.0.0/0
# после проверки убираем:
/ip firewall filter remove [find comment="TEST failover"]

Схема обкатана в продакшене на офисных RB-сериях и CHR. Если нужна помощь с настройкой резервирования каналов, MikroTik или сетевой инфраструктуры — оставьте заявку, поможем.