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

SD-WAN на MikroTik — WireGuard и OSPF

RouterOS 7.xVPN13 мин130 мар. 2026 г.
TelegramVK

SD-WAN на MikroTik — реализация через WireGuard и OSPF

SD-WAN (Software-Defined Wide Area Network) — подход к управлению корпоративной WAN-сетью, при котором логика маршрутизации отделена от транспорта. Коммерческие SD-WAN решения (Cisco Viptela, VMware VeloCloud, Fortinet SD-WAN) предлагают централизованный контроллер, автоматический failover, QoS и мониторинг из коробки. MikroTik не имеет готового продукта "SD-WAN", но RouterOS предоставляет все необходимые компоненты для построения аналогичного решения: WireGuard для шифрованного транспорта, OSPF для динамической маршрутизации, Queue Tree для QoS и Netwatch для мониторинга каналов. В этом руководстве построим полноценную SD-WAN сеть из компонентов RouterOS.

Описание

Что такое SD-WAN

Традиционная WAN-сеть строится на MPLS-каналах от провайдера или статических VPN-туннелях с ручным failover. SD-WAN добавляет:

  1. Транспортную независимость — использование любых каналов (MPLS, интернет, LTE) одновременно
  2. Интеллектуальную маршрутизацию — выбор пути на основе качества канала (latency, jitter, packet loss)
  3. Централизованное управление — единая точка конфигурации для всех площадок
  4. Автоматический failover — переключение на резервный канал за секунды
  5. QoS — приоритизация критичного трафика (VoIP, видео) на уровне приложений

Архитектура SD-WAN на MikroTik

Строим SD-WAN из следующих компонентов RouterOS:

Компонент SD-WANРеализация в RouterOSНазначение
Шифрованный транспортWireGuardТуннели между площадками
Динамическая маршрутизацияOSPF v2/v3Автоматическое обнаружение путей
FailoverOSPF cost + NetwatchПереключение по качеству канала
QoSQueue Tree + MangleПриоритизация VoIP/видео
МониторингNetwatch + ScriptingОценка качества каналов
УправлениеREST API + AnsibleЦентрализованная конфигурация

Топологии

Hub-and-Spoke — центральный офис (Hub) + филиалы (Spokes):

code
                    ┌──────────┐
         ┌──────────┤   Hub    ├──────────┐
         │          │ (HQ)     │          │
         │          └────┬─────┘          │
         │               │               │
    ┌────┴────┐    ┌────┴────┐    ┌────┴────┐
    │ Spoke 1 │    │ Spoke 2 │    │ Spoke 3 │
    │ (Branch)│    │ (Branch)│    │ (Branch)│
    └─────────┘    └─────────┘    └─────────┘
  • Количество туннелей: N (по одному от каждого spoke к hub)
  • Трафик между spoke идёт через hub
  • Просто масштабируется (новый филиал = один туннель к hub)
  • Hub — single point of failure

Full-Mesh — каждый с каждым:

code
    ┌─────────┐     ┌─────────┐
    │ Site A  │─────│ Site B  │
    └────┬────┘     └────┬────┘
         │    ╲      ╱   │
         │     ╲    ╱    │
         │      ╲  ╱     │
         │       ╲╱      │
         │       ╱╲      │
         │      ╱  ╲     │
         │     ╱    ╲    │
    ┌────┴────┐     ┌────┴────┐
    │ Site C  │─────│ Site D  │
    └─────────┘     └─────────┘
  • Количество туннелей: N*(N-1)/2 (для 5 сайтов = 10 туннелей)
  • Прямая связность без промежуточных узлов
  • Оптимальная задержка (direct path)
  • Сложно масштабируется (экспоненциальный рост туннелей)

Рекомендация: hub-and-spoke для 5+ площадок, full-mesh для 2-4 площадок.

Сравнение с коммерческим SD-WAN

КритерийMikroTik SD-WANCisco ViptelaVMware VeloCloud
СтоимостьБесплатно (лицензия RouterOS)$$$$
GUI-контроллерНет (CLI + API)vManageVeloCloud Orchestrator
Zero-touch provisioningНет (ручная настройка)ДаДа
Application-aware routingЧастично (Mangle + L7)Да (DPI)Да (DPI)
Автоматический failoverДа (OSPF + Netwatch)ДаДа
SLA monitoringСкрипты + NetwatchВстроенныйВстроенный
МасштабированиеДо ~50 площадокТысячиТысячи
ПоддержкаCommunityTAC 24/7TAC 24/7

MikroTik SD-WAN — бюджетное решение для малого и среднего бизнеса (до 20-50 площадок), где стоимость коммерческого SD-WAN неоправданна.

Настройка

Сценарий: Hub + 2 Spoke с dual-WAN

Архитектура:

code
Hub (HQ):
  WAN1: 203.0.113.1 (основной)
  WAN2: 203.0.113.2 (резервный)
  LAN: 10.0.0.0/24
  Loopback: 10.255.255.1/32

Spoke 1 (Branch 1):
  WAN1: 198.51.100.1
  WAN2: 198.51.100.2
  LAN: 10.1.0.0/24
  Loopback: 10.255.255.11/32

Spoke 2 (Branch 2):
  WAN1: 192.0.2.1
  WAN2: 192.0.2.2
  LAN: 10.2.0.0/24
  Loopback: 10.255.255.12/32

Каждый spoke имеет два WireGuard-туннеля к hub: через WAN1 и WAN2. OSPF определяет лучший путь. Netwatch мониторит качество каналов и корректирует OSPF cost.

Шаг 1: WireGuard mesh (Hub)

На Hub создаём WireGuard-интерфейсы для каждого канала:

[admin@MikroTik] >
# Loopback для OSPF Router ID
/interface/bridge add name=lo0
/ip/address add address=10.255.255.1/32 interface=lo0

# WireGuard через WAN1 (основной)
/interface/wireguard add name=wg-wan1 listen-port=13231 mtu=1420

# WireGuard через WAN2 (резервный)
/interface/wireguard add name=wg-wan2 listen-port=13232 mtu=1420

# IP-адреса на WireGuard-туннелях
# Hub-Spoke1 через WAN1
/ip/address add address=10.10.1.1/30 interface=wg-wan1
# Hub-Spoke1 через WAN2
/ip/address add address=10.10.2.1/30 interface=wg-wan2

# Peers: Spoke 1 через WAN1
/interface/wireguard/peers add interface=wg-wan1 \
  public-key="<SPOKE1_WG_WAN1_PUBKEY>" \
  allowed-address=10.10.1.2/32,10.1.0.0/24,10.255.255.11/32 \
  endpoint-address=198.51.100.1 endpoint-port=13231

# Peers: Spoke 1 через WAN2
/interface/wireguard/peers add interface=wg-wan2 \
  public-key="<SPOKE1_WG_WAN2_PUBKEY>" \
  allowed-address=10.10.2.2/32,10.1.0.0/24,10.255.255.11/32 \
  endpoint-address=198.51.100.2 endpoint-port=13232

# Peers: Spoke 2 через WAN1
/interface/wireguard/peers add interface=wg-wan1 \
  public-key="<SPOKE2_WG_WAN1_PUBKEY>" \
  allowed-address=10.10.3.2/32,10.2.0.0/24,10.255.255.12/32 \
  endpoint-address=192.0.2.1 endpoint-port=13231

# Peers: Spoke 2 через WAN2
/interface/wireguard/peers add interface=wg-wan2 \
  public-key="<SPOKE2_WG_WAN2_PUBKEY>" \
  allowed-address=10.10.4.2/32,10.2.0.0/24,10.255.255.12/32 \
  endpoint-address=192.0.2.2 endpoint-port=13232

# Дополнительные IP для Spoke 2 туннелей
/ip/address add address=10.10.3.1/30 interface=wg-wan1
/ip/address add address=10.10.4.1/30 interface=wg-wan2

# Firewall
/ip/firewall/filter add chain=input protocol=udp dst-port=13231-13232 \
  action=accept comment="Allow WireGuard SD-WAN" place-before=0

Шаг 1b: WireGuard (Spoke 1)

[admin@MikroTik] >
# Loopback
/interface/bridge add name=lo0
/ip/address add address=10.255.255.11/32 interface=lo0

# WireGuard через WAN1
/interface/wireguard add name=wg-wan1 listen-port=13231 mtu=1420
/ip/address add address=10.10.1.2/30 interface=wg-wan1

# WireGuard через WAN2
/interface/wireguard add name=wg-wan2 listen-port=13232 mtu=1420
/ip/address add address=10.10.2.2/30 interface=wg-wan2

# Peer: Hub через WAN1
/interface/wireguard/peers add interface=wg-wan1 \
  public-key="<HUB_WG_WAN1_PUBKEY>" \
  allowed-address=10.10.1.1/32,10.0.0.0/24,10.255.255.1/32,10.10.3.0/30,10.10.4.0/30,10.2.0.0/24,10.255.255.12/32 \
  endpoint-address=203.0.113.1 endpoint-port=13231

# Peer: Hub через WAN2
/interface/wireguard/peers add interface=wg-wan2 \
  public-key="<HUB_WG_WAN2_PUBKEY>" \
  allowed-address=10.10.2.1/32,10.0.0.0/24,10.255.255.1/32,10.10.3.0/30,10.10.4.0/30,10.2.0.0/24,10.255.255.12/32 \
  endpoint-address=203.0.113.2 endpoint-port=13232

# Firewall
/ip/firewall/filter add chain=input protocol=udp dst-port=13231-13232 \
  action=accept comment="Allow WireGuard SD-WAN" place-before=0
/ip/firewall/filter add chain=forward in-interface=wg-wan1 action=accept place-before=0
/ip/firewall/filter add chain=forward in-interface=wg-wan2 action=accept place-before=0

Шаг 2: OSPF поверх WireGuard

OSPF динамически обнаруживает маршруты и переключает трафик при отказе канала. Настраиваем OSPF на всех WireGuard-интерфейсах.

Hub:

[admin@MikroTik] >
# OSPF Instance
/routing/ospf/instance add name=sd-wan-ospf router-id=10.255.255.1 \
  version=2

# OSPF Area
/routing/ospf/area add name=backbone instance=sd-wan-ospf area-id=0.0.0.0

# OSPF интерфейсы
# WAN1 туннели — cost 10 (основной)
/routing/ospf/interface-template add area=backbone \
  interfaces=wg-wan1 cost=10 type=ptp \
  hello-interval=10s dead-interval=40s

# WAN2 туннели — cost 100 (резервный)
/routing/ospf/interface-template add area=backbone \
  interfaces=wg-wan2 cost=100 type=ptp \
  hello-interval=10s dead-interval=40s

# Loopback (анонсируем Router ID)
/routing/ospf/interface-template add area=backbone \
  interfaces=lo0 type=ptp passive

# LAN сеть (анонсируем в OSPF)
/routing/ospf/interface-template add area=backbone \
  interfaces=bridge1 passive

Spoke 1:

[admin@MikroTik] >
/routing/ospf/instance add name=sd-wan-ospf router-id=10.255.255.11 \
  version=2

/routing/ospf/area add name=backbone instance=sd-wan-ospf area-id=0.0.0.0

# WAN1 — cost 10 (основной)
/routing/ospf/interface-template add area=backbone \
  interfaces=wg-wan1 cost=10 type=ptp \
  hello-interval=10s dead-interval=40s

# WAN2 — cost 100 (резервный)
/routing/ospf/interface-template add area=backbone \
  interfaces=wg-wan2 cost=100 type=ptp \
  hello-interval=10s dead-interval=40s

/routing/ospf/interface-template add area=backbone \
  interfaces=lo0 type=ptp passive

/routing/ospf/interface-template add area=backbone \
  interfaces=bridge1 passive

Spoke 2 — аналогично Spoke 1 с router-id=10.255.255.12.

При нормальной работе OSPF выберет путь через WAN1 (cost=10). При падении WAN1 трафик автоматически перейдёт на WAN2 (cost=100) в течение dead-interval (40 секунд).

Шаг 3: Мониторинг каналов (Netwatch)

Netwatch мониторит доступность удалённого хоста и выполняет скрипт при отказе. Используем его для динамического изменения OSPF cost:

Hub:

[admin@MikroTik] >
# Мониторинг WAN1 до Spoke 1
/tool/netwatch add host=10.10.1.2 interval=5s timeout=2s \
  type=icmp \
  up-script="/routing/ospf/interface-template set [find interfaces=wg-wan1] cost=10" \
  down-script="/routing/ospf/interface-template set [find interfaces=wg-wan1] cost=1000"

# Мониторинг WAN2 до Spoke 1
/tool/netwatch add host=10.10.2.2 interval=5s timeout=2s \
  type=icmp \
  up-script="/routing/ospf/interface-template set [find interfaces=wg-wan2] cost=100" \
  down-script="/routing/ospf/interface-template set [find interfaces=wg-wan2] cost=5000"

Логика:

  • Канал работает нормально: WAN1 cost=10, WAN2 cost=100 → трафик через WAN1
  • WAN1 упал: WAN1 cost=1000, WAN2 cost=100 → трафик через WAN2
  • Оба канала деградировали: OSPF выберет наименьший cost

Продвинутый мониторинг: оценка jitter и packet loss

Для более интеллектуального failover используйте скрипт, оценивающий не только доступность, но и качество канала:

[admin@MikroTik] >
# Скрипт оценки качества канала
/system/script add name=check-wan1-quality source={
  :local pingResult [/ping 10.10.1.2 count=10 interval=100ms as-value]
  :local loss ($pingResult->"packet-loss")
  :local avgRtt ($pingResult->"avg-rtt")

  :if ($loss > 20) do={
    # Потери > 20% — канал плохой
    /routing/ospf/interface-template set [find interfaces=wg-wan1] cost=500
    /log warning "WAN1 quality degraded: loss=$loss%"
  } else={
    :if ($avgRtt > 100ms) do={
      # Задержка > 100ms — канал средний
      /routing/ospf/interface-template set [find interfaces=wg-wan1] cost=50
      /log info "WAN1 latency high: rtt=$avgRtt"
    } else={
      # Канал хороший
      /routing/ospf/interface-template set [find interfaces=wg-wan1] cost=10
    }
  }
}

# Запуск скрипта каждые 30 секунд
/system/scheduler add name=wan1-quality-check interval=30s \
  on-event="/system/script/run check-wan1-quality"

Шаг 4: QoS (Queue Tree)

Приоритизация трафика критична для SD-WAN. Настроим Queue Tree для VoIP, видеоконференций и остального трафика.

Маркировка трафика (Mangle):

[admin@MikroTik] >
# Маркировка VoIP (SIP + RTP)
/ip/firewall/mangle add chain=forward protocol=udp \
  dst-port=5060-5061 action=mark-packet \
  new-packet-mark=voip passthrough=no \
  comment="Mark VoIP SIP"

/ip/firewall/mangle add chain=forward protocol=udp \
  dst-port=10000-20000 dscp=46 action=mark-packet \
  new-packet-mark=voip passthrough=no \
  comment="Mark VoIP RTP (EF)"

# Маркировка видеоконференций (Zoom, Teams)
/ip/firewall/mangle add chain=forward protocol=udp \
  dst-port=8801-8810 action=mark-packet \
  new-packet-mark=video passthrough=no \
  comment="Mark Zoom UDP"

/ip/firewall/mangle add chain=forward protocol=udp \
  dst-port=3478-3481 action=mark-packet \
  new-packet-mark=video passthrough=no \
  comment="Mark Teams/STUN"

# Весь остальной трафик
/ip/firewall/mangle add chain=forward action=mark-packet \
  new-packet-mark=bulk passthrough=no \
  comment="Mark bulk traffic"

Queue Tree (пример для WAN1 100 Mbps):

[admin@MikroTik] >
# Корневая очередь на WireGuard-интерфейсе
/queue/tree add name=sd-wan-out parent=wg-wan1 \
  max-limit=100M

# VoIP — строгий приоритет, гарантия 10M
/queue/tree add name=voip-out parent=sd-wan-out \
  packet-mark=voip priority=1 \
  limit-at=10M max-limit=20M

# Видео — высокий приоритет, гарантия 30M
/queue/tree add name=video-out parent=sd-wan-out \
  packet-mark=video priority=3 \
  limit-at=30M max-limit=50M

# Bulk — остальное
/queue/tree add name=bulk-out parent=sd-wan-out \
  packet-mark=bulk priority=8 \
  limit-at=20M max-limit=100M

Приоритеты: VoIP (priority=1) всегда получает полосу первым, затем видео (priority=3), затем остальной трафик (priority=8).

Шаг 5: Централизованное управление (REST API)

RouterOS 7 поддерживает REST API для удалённого управления. Используйте его для централизованной конфигурации:

[admin@MikroTik] >
# Включение REST API
/ip/service set api-ssl disabled=no port=8729
/ip/service set www-ssl disabled=no port=443

# Создание пользователя для API
/user add name=sdwan-api password="ApiP@ssw0rd!" group=full

Пример запроса через curl (получение маршрутов OSPF):

bash
curl -k -u sdwan-api:ApiP@ssw0rd! \
  https://203.0.113.1/rest/routing/ospf/neighbor/print

Пример изменения OSPF cost через API:

bash
curl -k -u sdwan-api:ApiP@ssw0rd! \
  -X PATCH https://203.0.113.1/rest/routing/ospf/interface-template/0 \
  -H "Content-Type: application/json" \
  -d '{"cost": 500}'

Автоматизация через Ansible

Для управления десятками площадок используйте Ansible с модулем community.routeros:

yaml
# ansible playbook: update-ospf-cost.yml
- name: Update OSPF cost on all spokes
  hosts: mikrotik_spokes
  gather_facts: no
  tasks:
    - name: Set WAN1 OSPF cost
      community.routeros.command:
        commands:
          - /routing/ospf/interface-template set [find interfaces=wg-wan1] cost={{ wan1_cost }}

Проверка

Проверка WireGuard-туннелей

[admin@MikroTik] >
# Все WireGuard peers
/interface/wireguard/peers print detail

# Статус handshake (должен быть < 2 минут)
/interface/wireguard/peers print proplist=interface,endpoint,last-handshake,rx,tx

Проверка OSPF

[admin@MikroTik] >
# OSPF neighbors (должны быть Full)
/routing/ospf/neighbor print

# OSPF маршруты
/ip/route print where routing-table=main ospf

# OSPF LSA database
/routing/ospf/lsa print where area=backbone

Ожидаемый вывод neighbors:

[admin@MikroTik] >
#   INSTANCE     ROUTER-ID      STATE     INTERFACE
0   sd-wan-ospf  10.255.255.11  Full      wg-wan1
1   sd-wan-ospf  10.255.255.11  Full      wg-wan2
2   sd-wan-ospf  10.255.255.12  Full      wg-wan1
3   sd-wan-ospf  10.255.255.12  Full      wg-wan2

Все neighbours в состоянии Full — OSPF работает корректно.

Проверка failover

Для тестирования отключите WAN1 на одном из spoke и убедитесь, что трафик переключился:

[admin@MikroTik] >
# На Spoke 1: отключаем WAN1 интерфейс
/interface disable ether1

# На Hub: проверяем маршруты (должны измениться)
/ip/route print where dst-address~"10.1.0.0"

# Трассировка до Spoke 1 LAN (должна идти через wg-wan2)
/tool/traceroute 10.1.0.1

# Включаем обратно
/interface enable ether1

# Ждём ~40 секунд (OSPF dead-interval) — маршруты вернутся на WAN1

Проверка QoS

[admin@MikroTik] >
# Статистика Queue Tree
/queue/tree print stats

# Мониторинг пакетных марок
/ip/firewall/mangle print stats where chain=forward

Проверка Netwatch

[admin@MikroTik] >
# Статус мониторинга
/tool/netwatch print

# Логи переключений
/log print where topics~"script"

Масштабирование

Hub-and-Spoke: добавление нового филиала

Для каждого нового spoke на Hub нужно:

  1. Создать WireGuard peer (2 штуки для dual-WAN)
  2. Назначить IP-адреса на туннели
  3. OSPF обнаружит новые маршруты автоматически
[admin@MikroTik] >
# Hub: добавление Spoke 3
/interface/wireguard/peers add interface=wg-wan1 \
  public-key="<SPOKE3_KEY>" \
  allowed-address=10.10.5.2/32,10.3.0.0/24,10.255.255.13/32 \
  endpoint-address=<SPOKE3_WAN1_IP> endpoint-port=13231

/ip/address add address=10.10.5.1/30 interface=wg-wan1

# OSPF обнаружит Spoke 3 автоматически через interface-template

Пределы масштабирования

ПараметрРекомендация
Количество WireGuard peers на одном устройствеДо 50 на CCR, до 20 на hAP ax3
Количество OSPF neighboursДо 50 (зависит от CPU)
Количество площадок (hub-and-spoke)До 20-50
Количество площадок (full-mesh)До 5-8 (иначе слишком много туннелей)
Пропускная способность (суммарная)Зависит от модели (CCR: 1-5 Gbps, hAP: 200-500 Mbps)

При приближении к лимитам рассмотрите:

  • Иерархическую топологию (региональные хабы)
  • Разделение на несколько OSPF area
  • Переход на коммерческое SD-WAN решение

SD-WAN vs простой VPN

КритерийПростой VPN (WireGuard)SD-WAN на MikroTik
FailoverРучной или static routingАвтоматический (OSPF)
Выбор путиСтатическийДинамический (по качеству)
QoSНетQueue Tree
МониторингРучная проверкаNetwatch + скрипты
СложностьНизкаяВысокая
Количество WANОбычно 12+ (dual-WAN)
Время переключенияМинуты (ручное)Секунды (OSPF)

Простой VPN достаточен для 2-3 площадок с одним WAN-каналом. SD-WAN оправдан при dual-WAN и требованиях к автоматическому failover и QoS.

Типичные ошибки

1. OSPF neighbours застряли в состоянии Init/2-Way

Причина: тип интерфейса OSPF настроен неправильно. Для point-to-point WireGuard-туннелей нужен type=ptp.

Решение:

[admin@MikroTik] >
# Проверьте тип
/routing/ospf/interface-template print

# Должно быть type=ptp для WireGuard
/routing/ospf/interface-template set [find interfaces=wg-wan1] type=ptp

При type=broadcast OSPF ожидает выборы DR/BDR, что не работает на point-to-point линках.

2. Трафик не переключается при падении канала

Причина: OSPF dead-interval слишком велик (по умолчанию 40 секунд) или Netwatch не обновляет OSPF cost.

Решение: уменьшите таймеры OSPF для быстрого failover:

[admin@MikroTik] >
# Быстрые таймеры (failover за ~3 секунды)
/routing/ospf/interface-template set [find interfaces=wg-wan1] \
  hello-interval=1s dead-interval=3s

/routing/ospf/interface-template set [find interfaces=wg-wan2] \
  hello-interval=1s dead-interval=3s

Внимание: агрессивные таймеры увеличивают нагрузку на CPU и могут вызывать ложные срабатывания при кратковременных потерях.

3. WireGuard allowed-address конфликтует с OSPF

Причина: OSPF анонсирует маршруты, но WireGuard отбрасывает пакеты, если dst-address не входит в allowed-address соответствующего peer.

Решение: добавьте все необходимые подсети в allowed-address:

[admin@MikroTik] >
# Должны быть все подсети, доступные через этого peer
/interface/wireguard/peers set [find endpoint-address=198.51.100.1] \
  allowed-address=10.10.1.2/32,10.1.0.0/24,10.255.255.11/32

# Или используйте 0.0.0.0/0 (менее безопасно, но проще)

4. QoS не работает — весь трафик попадает в bulk

Причина: правила Mangle не срабатывают или расположены в неправильном порядке.

Решение:

[admin@MikroTik] >
# Проверьте счётчики Mangle
/ip/firewall/mangle print stats where chain=forward

# Если счётчики VoIP/video = 0:
# 1. Убедитесь что порты и DSCP правильные
# 2. Проверьте passthrough=no на каждом правиле
# 3. Специфичные правила (VoIP) должны быть ВЫШЕ общих (bulk)

5. OSPF создаёт петли маршрутизации при full-mesh

Причина: в full-mesh с несколькими путями OSPF может создать sub-optimal routing при неправильных cost.

Решение: тщательно планируйте OSPF cost для каждого линка:

[admin@MikroTik] >
# Основные линки: cost 10
# Резервные линки: cost 100
# Деградировавшие линки (Netwatch): cost 500-1000
# Отключённые линки: cost 65535

Используйте type=ptp и убедитесь, что loopback-адреса анонсируются корректно.

6. REST API недоступен извне

Причина: firewall блокирует порт 443 или API-сервис не включён.

Решение:

[admin@MikroTik] >
# Проверьте сервисы
/ip/service print

# Включите www-ssl
/ip/service set www-ssl disabled=no

# Разрешите доступ только с management-сети
/ip/service set www-ssl address=10.0.0.0/24

# Firewall: разрешите порт 443
/ip/firewall/filter add chain=input protocol=tcp dst-port=443 \
  src-address=10.0.0.0/24 action=accept \
  comment="Allow REST API" place-before=0

7. Высокая нагрузка CPU при большом количестве туннелей

Причина: WireGuard шифрование + OSPF + QoS создают значительную нагрузку на CPU.

Решение:

[admin@MikroTik] >
# Проверьте нагрузку CPU
/system/resource print

# Если CPU > 80%:
# 1. Увеличьте OSPF таймеры (hello=10s, dead=40s)
# 2. Уменьшите частоту Netwatch (interval=30s)
# 3. Упростите Queue Tree
# 4. Рассмотрите более мощное оборудование (CCR2004, CCR2216)

Итоги

SD-WAN на MikroTik — это не коробочное решение, а конструктор из компонентов RouterOS. WireGuard обеспечивает шифрованный транспорт, OSPF — динамическую маршрутизацию и failover, Queue Tree — QoS, Netwatch — мониторинг каналов. Всё вместе это даёт функционал, сравнимый с базовым коммерческим SD-WAN, но бесплатно.

Главные ограничения: отсутствие GUI-контроллера (управление через CLI/API/Ansible), нет application-aware routing на уровне DPI, масштабирование ограничено ~50 площадками. Для малого и среднего бизнеса с 5-20 филиалами это отличный вариант. При росте до десятков площадок и требованиях к DPI и zero-touch provisioning — присмотритесь к коммерческим SD-WAN решениям.

[admin@MikroTik] >
┌──────────┐
         ┌──────────┤   Hub    ├──────────┐
         │          │ (HQ)     │          │
         │          └────┬─────┘          │
         │               │               │
    ┌────┴────┐    ┌────┴────┐    ┌────┴────┐
    │ Spoke 1 │    │ Spoke 2 │    │ Spoke 3 │
    │ (Branch)│    │ (Branch)│    │ (Branch)│
    └─────────┘    └─────────┘    └─────────┘
┌─────────┐     ┌─────────┐
    │ Site A  │─────│ Site B  │
    └────┬────┘     └────┬────┘
         │    ╲      ╱   │
         │     ╲    ╱    │
         │      ╲  ╱     │
         │       ╲╱      │
         │       ╱╲      │
         │      ╱  ╲     │
         │     ╱    ╲    │
    ┌────┴────┐     ┌────┴────┐
    │ Site C  │─────│ Site D  │
    └─────────┘     └─────────┘
Hub (HQ):
  WAN1: 203.0.113.1 (основной)
  WAN2: 203.0.113.2 (резервный)
  LAN: 10.0.0.0/24
  Loopback: 10.255.255.1/32

Spoke 1 (Branch 1):
  WAN1: 198.51.100.1
  WAN2: 198.51.100.2
  LAN: 10.1.0.0/24
  Loopback: 10.255.255.11/32

Spoke 2 (Branch 2):
  WAN1: 192.0.2.1
  WAN2: 192.0.2.2
  LAN: 10.2.0.0/24
  Loopback: 10.255.255.12/32
# Loopback для OSPF Router ID
/interface/bridge add name=lo0
/ip/address add address=10.255.255.1/32 interface=lo0

# WireGuard через WAN1 (основной)
/interface/wireguard add name=wg-wan1 listen-port=13231 mtu=1420

# WireGuard через WAN2 (резервный)
/interface/wireguard add name=wg-wan2 listen-port=13232 mtu=1420

# IP-адреса на WireGuard-туннелях
# Hub-Spoke1 через WAN1
/ip/address add address=10.10.1.1/30 interface=wg-wan1
# Hub-Spoke1 через WAN2
/ip/address add address=10.10.2.1/30 interface=wg-wan2

# Peers: Spoke 1 через WAN1
/interface/wireguard/peers add interface=wg-wan1 \
  public-key="<SPOKE1_WG_WAN1_PUBKEY>" \
  allowed-address=10.10.1.2/32,10.1.0.0/24,10.255.255.11/32 \
  endpoint-address=198.51.100.1 endpoint-port=13231

# Peers: Spoke 1 через WAN2
/interface/wireguard/peers add interface=wg-wan2 \
  public-key="<SPOKE1_WG_WAN2_PUBKEY>" \
  allowed-address=10.10.2.2/32,10.1.0.0/24,10.255.255.11/32 \
  endpoint-address=198.51.100.2 endpoint-port=13232

# Peers: Spoke 2 через WAN1
/interface/wireguard/peers add interface=wg-wan1 \
  public-key="<SPOKE2_WG_WAN1_PUBKEY>" \
  allowed-address=10.10.3.2/32,10.2.0.0/24,10.255.255.12/32 \
  endpoint-address=192.0.2.1 endpoint-port=13231

# Peers: Spoke 2 через WAN2
/interface/wireguard/peers add interface=wg-wan2 \
  public-key="<SPOKE2_WG_WAN2_PUBKEY>" \
  allowed-address=10.10.4.2/32,10.2.0.0/24,10.255.255.12/32 \
  endpoint-address=192.0.2.2 endpoint-port=13232

# Дополнительные IP для Spoke 2 туннелей
/ip/address add address=10.10.3.1/30 interface=wg-wan1
/ip/address add address=10.10.4.1/30 interface=wg-wan2

# Firewall
/ip/firewall/filter add chain=input protocol=udp dst-port=13231-13232 \
  action=accept comment="Allow WireGuard SD-WAN" place-before=0
# Loopback
/interface/bridge add name=lo0
/ip/address add address=10.255.255.11/32 interface=lo0

# WireGuard через WAN1
/interface/wireguard add name=wg-wan1 listen-port=13231 mtu=1420
/ip/address add address=10.10.1.2/30 interface=wg-wan1

# WireGuard через WAN2
/interface/wireguard add name=wg-wan2 listen-port=13232 mtu=1420
/ip/address add address=10.10.2.2/30 interface=wg-wan2

# Peer: Hub через WAN1
/interface/wireguard/peers add interface=wg-wan1 \
  public-key="<HUB_WG_WAN1_PUBKEY>" \
  allowed-address=10.10.1.1/32,10.0.0.0/24,10.255.255.1/32,10.10.3.0/30,10.10.4.0/30,10.2.0.0/24,10.255.255.12/32 \
  endpoint-address=203.0.113.1 endpoint-port=13231

# Peer: Hub через WAN2
/interface/wireguard/peers add interface=wg-wan2 \
  public-key="<HUB_WG_WAN2_PUBKEY>" \
  allowed-address=10.10.2.1/32,10.0.0.0/24,10.255.255.1/32,10.10.3.0/30,10.10.4.0/30,10.2.0.0/24,10.255.255.12/32 \
  endpoint-address=203.0.113.2 endpoint-port=13232

# Firewall
/ip/firewall/filter add chain=input protocol=udp dst-port=13231-13232 \
  action=accept comment="Allow WireGuard SD-WAN" place-before=0
/ip/firewall/filter add chain=forward in-interface=wg-wan1 action=accept place-before=0
/ip/firewall/filter add chain=forward in-interface=wg-wan2 action=accept place-before=0
# OSPF Instance
/routing/ospf/instance add name=sd-wan-ospf router-id=10.255.255.1 \
  version=2

# OSPF Area
/routing/ospf/area add name=backbone instance=sd-wan-ospf area-id=0.0.0.0

# OSPF интерфейсы
# WAN1 туннели — cost 10 (основной)
/routing/ospf/interface-template add area=backbone \
  interfaces=wg-wan1 cost=10 type=ptp \
  hello-interval=10s dead-interval=40s

# WAN2 туннели — cost 100 (резервный)
/routing/ospf/interface-template add area=backbone \
  interfaces=wg-wan2 cost=100 type=ptp \
  hello-interval=10s dead-interval=40s

# Loopback (анонсируем Router ID)
/routing/ospf/interface-template add area=backbone \
  interfaces=lo0 type=ptp passive

# LAN сеть (анонсируем в OSPF)
/routing/ospf/interface-template add area=backbone \
  interfaces=bridge1 passive
/routing/ospf/instance add name=sd-wan-ospf router-id=10.255.255.11 \
  version=2

/routing/ospf/area add name=backbone instance=sd-wan-ospf area-id=0.0.0.0

# WAN1 — cost 10 (основной)
/routing/ospf/interface-template add area=backbone \
  interfaces=wg-wan1 cost=10 type=ptp \
  hello-interval=10s dead-interval=40s

# WAN2 — cost 100 (резервный)
/routing/ospf/interface-template add area=backbone \
  interfaces=wg-wan2 cost=100 type=ptp \
  hello-interval=10s dead-interval=40s

/routing/ospf/interface-template add area=backbone \
  interfaces=lo0 type=ptp passive

/routing/ospf/interface-template add area=backbone \
  interfaces=bridge1 passive
# Мониторинг WAN1 до Spoke 1
/tool/netwatch add host=10.10.1.2 interval=5s timeout=2s \
  type=icmp \
  up-script="/routing/ospf/interface-template set [find interfaces=wg-wan1] cost=10" \
  down-script="/routing/ospf/interface-template set [find interfaces=wg-wan1] cost=1000"

# Мониторинг WAN2 до Spoke 1
/tool/netwatch add host=10.10.2.2 interval=5s timeout=2s \
  type=icmp \
  up-script="/routing/ospf/interface-template set [find interfaces=wg-wan2] cost=100" \
  down-script="/routing/ospf/interface-template set [find interfaces=wg-wan2] cost=5000"
# Скрипт оценки качества канала
/system/script add name=check-wan1-quality source={
  :local pingResult [/ping 10.10.1.2 count=10 interval=100ms as-value]
  :local loss ($pingResult->"packet-loss")
  :local avgRtt ($pingResult->"avg-rtt")

  :if ($loss > 20) do={
    # Потери > 20% — канал плохой
    /routing/ospf/interface-template set [find interfaces=wg-wan1] cost=500
    /log warning "WAN1 quality degraded: loss=$loss%"
  } else={
    :if ($avgRtt > 100ms) do={
      # Задержка > 100ms — канал средний
      /routing/ospf/interface-template set [find interfaces=wg-wan1] cost=50
      /log info "WAN1 latency high: rtt=$avgRtt"
    } else={
      # Канал хороший
      /routing/ospf/interface-template set [find interfaces=wg-wan1] cost=10
    }
  }
}

# Запуск скрипта каждые 30 секунд
/system/scheduler add name=wan1-quality-check interval=30s \
  on-event="/system/script/run check-wan1-quality"
# Маркировка VoIP (SIP + RTP)
/ip/firewall/mangle add chain=forward protocol=udp \
  dst-port=5060-5061 action=mark-packet \
  new-packet-mark=voip passthrough=no \
  comment="Mark VoIP SIP"

/ip/firewall/mangle add chain=forward protocol=udp \
  dst-port=10000-20000 dscp=46 action=mark-packet \
  new-packet-mark=voip passthrough=no \
  comment="Mark VoIP RTP (EF)"

# Маркировка видеоконференций (Zoom, Teams)
/ip/firewall/mangle add chain=forward protocol=udp \
  dst-port=8801-8810 action=mark-packet \
  new-packet-mark=video passthrough=no \
  comment="Mark Zoom UDP"

/ip/firewall/mangle add chain=forward protocol=udp \
  dst-port=3478-3481 action=mark-packet \
  new-packet-mark=video passthrough=no \
  comment="Mark Teams/STUN"

# Весь остальной трафик
/ip/firewall/mangle add chain=forward action=mark-packet \
  new-packet-mark=bulk passthrough=no \
  comment="Mark bulk traffic"
# Корневая очередь на WireGuard-интерфейсе
/queue/tree add name=sd-wan-out parent=wg-wan1 \
  max-limit=100M

# VoIP — строгий приоритет, гарантия 10M
/queue/tree add name=voip-out parent=sd-wan-out \
  packet-mark=voip priority=1 \
  limit-at=10M max-limit=20M

# Видео — высокий приоритет, гарантия 30M
/queue/tree add name=video-out parent=sd-wan-out \
  packet-mark=video priority=3 \
  limit-at=30M max-limit=50M

# Bulk — остальное
/queue/tree add name=bulk-out parent=sd-wan-out \
  packet-mark=bulk priority=8 \
  limit-at=20M max-limit=100M
# Включение REST API
/ip/service set api-ssl disabled=no port=8729
/ip/service set www-ssl disabled=no port=443

# Создание пользователя для API
/user add name=sdwan-api password="ApiP@ssw0rd!" group=full
curl -k -u sdwan-api:ApiP@ssw0rd! \
  https://203.0.113.1/rest/routing/ospf/neighbor/print
curl -k -u sdwan-api:ApiP@ssw0rd! \
  -X PATCH https://203.0.113.1/rest/routing/ospf/interface-template/0 \
  -H "Content-Type: application/json" \
  -d '{"cost": 500}'
### Проверка

#### Проверка WireGuard-туннелей
#### Проверка OSPF
Ожидаемый вывод neighbors:
Все neighbours в состоянии `Full` — OSPF работает корректно.

#### Проверка failover

Для тестирования отключите WAN1 на одном из spoke и убедитесь, что трафик переключился:
#### Проверка QoS
#### Проверка Netwatch
### Масштабирование

#### Hub-and-Spoke: добавление нового филиала

Для каждого нового spoke на Hub нужно:

1. Создать WireGuard peer (2 штуки для dual-WAN)
2. Назначить IP-адреса на туннели
3. OSPF обнаружит новые маршруты автоматически
#### Пределы масштабирования

| Параметр | Рекомендация |
|---|---|
| Количество WireGuard peers на одном устройстве | До 50 на CCR, до 20 на hAP ax3 |
| Количество OSPF neighbours | До 50 (зависит от CPU) |
| Количество площадок (hub-and-spoke) | До 20-50 |
| Количество площадок (full-mesh) | До 5-8 (иначе слишком много туннелей) |
| Пропускная способность (суммарная) | Зависит от модели (CCR: 1-5 Gbps, hAP: 200-500 Mbps) |

При приближении к лимитам рассмотрите:

- Иерархическую топологию (региональные хабы)
- Разделение на несколько OSPF area
- Переход на коммерческое SD-WAN решение

### SD-WAN vs простой VPN

| Критерий | Простой VPN (WireGuard) | SD-WAN на MikroTik |
|---|---|---|
| Failover | Ручной или static routing | Автоматический (OSPF) |
| Выбор пути | Статический | Динамический (по качеству) |
| QoS | Нет | Queue Tree |
| Мониторинг | Ручная проверка | Netwatch + скрипты |
| Сложность | Низкая | Высокая |
| Количество WAN | Обычно 1 | 2+ (dual-WAN) |
| Время переключения | Минуты (ручное) | Секунды (OSPF) |

Простой VPN достаточен для 2-3 площадок с одним WAN-каналом. SD-WAN оправдан при dual-WAN и требованиях к автоматическому failover и QoS.

### Типичные ошибки

#### 1. OSPF neighbours застряли в состоянии Init/2-Way

**Причина**: тип интерфейса OSPF настроен неправильно. Для point-to-point WireGuard-туннелей нужен `type=ptp`.

**Решение**:
При `type=broadcast` OSPF ожидает выборы DR/BDR, что не работает на point-to-point линках.

#### 2. Трафик не переключается при падении канала

**Причина**: OSPF dead-interval слишком велик (по умолчанию 40 секунд) или Netwatch не обновляет OSPF cost.

**Решение**: уменьшите таймеры OSPF для быстрого failover:
**Внимание**: агрессивные таймеры увеличивают нагрузку на CPU и могут вызывать ложные срабатывания при кратковременных потерях.

#### 3. WireGuard allowed-address конфликтует с OSPF

**Причина**: OSPF анонсирует маршруты, но WireGuard отбрасывает пакеты, если dst-address не входит в `allowed-address` соответствующего peer.

**Решение**: добавьте все необходимые подсети в allowed-address:
#### 4. QoS не работает — весь трафик попадает в bulk

**Причина**: правила Mangle не срабатывают или расположены в неправильном порядке.

**Решение**:
#### 5. OSPF создаёт петли маршрутизации при full-mesh

**Причина**: в full-mesh с несколькими путями OSPF может создать sub-optimal routing при неправильных cost.

**Решение**: тщательно планируйте OSPF cost для каждого линка:
Используйте `type=ptp` и убедитесь, что loopback-адреса анонсируются корректно.

#### 6. REST API недоступен извне

**Причина**: firewall блокирует порт 443 или API-сервис не включён.

**Решение**:
#### 7. Высокая нагрузка CPU при большом количестве туннелей

**Причина**: WireGuard шифрование + OSPF + QoS создают значительную нагрузку на CPU.

**Решение**:
VPN / SD-WAN на MikroTik — WireGuard и OSPF