SD-WAN на MikroTik — WireGuard и OSPF
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 добавляет:
- Транспортную независимость — использование любых каналов (MPLS, интернет, LTE) одновременно
- Интеллектуальную маршрутизацию — выбор пути на основе качества канала (latency, jitter, packet loss)
- Централизованное управление — единая точка конфигурации для всех площадок
- Автоматический failover — переключение на резервный канал за секунды
- QoS — приоритизация критичного трафика (VoIP, видео) на уровне приложений
Архитектура SD-WAN на MikroTik
Строим SD-WAN из следующих компонентов RouterOS:
| Компонент SD-WAN | Реализация в RouterOS | Назначение |
|---|---|---|
| Шифрованный транспорт | WireGuard | Туннели между площадками |
| Динамическая маршрутизация | OSPF v2/v3 | Автоматическое обнаружение путей |
| Failover | OSPF cost + Netwatch | Переключение по качеству канала |
| QoS | Queue 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-WAN | Cisco Viptela | VMware VeloCloud |
|---|---|---|---|
| Стоимость | Бесплатно (лицензия RouterOS) | $$ | $$ |
| GUI-контроллер | Нет (CLI + API) | vManage | VeloCloud Orchestrator |
| Zero-touch provisioning | Нет (ручная настройка) | Да | Да |
| Application-aware routing | Частично (Mangle + L7) | Да (DPI) | Да (DPI) |
| Автоматический failover | Да (OSPF + Netwatch) | Да | Да |
| SLA monitoring | Скрипты + Netwatch | Встроенный | Встроенный |
| Масштабирование | До ~50 площадок | Тысячи | Тысячи |
| Поддержка | Community | TAC 24/7 | TAC 24/7 |
MikroTik SD-WAN — бюджетное решение для малого и среднего бизнеса (до 20-50 площадок), где стоимость коммерческого SD-WAN неоправданна.
Настройка
Сценарий: Hub + 2 Spoke с dual-WAN
Архитектура:
codeHub (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):
bashcurl -k -u sdwan-api:ApiP@ssw0rd! \ https://203.0.113.1/rest/routing/ospf/neighbor/print
Пример изменения OSPF cost через API:
bashcurl -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 нужно:
- Создать WireGuard peer (2 штуки для dual-WAN)
- Назначить IP-адреса на туннели
- 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 | Обычно 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.
Решение:
[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 решениям.
┌──────────┐
┌──────────┤ 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.
**Решение**: