Cisco has DMVPN for many-branch WANs. RouterOS doesn't — and pretending otherwise wastes an afternoon. This is the honest MikroTik answer: a WireGuard hub-and-spoke that scales to many sites, routes dynamically, and where each branch is a copy-paste — plus a clear-eyed look at what you give up versus DMVPN's on-demand spoke-to-spoke.
First, the honest part: RouterOS has no DMVPN. There's no mGRE, no NHRP, no dynamic spoke-to-spoke tunnel resolution. So when someone asks for "DMVPN on MikroTik," the real question is "how do I connect many branches without hand-meshing tunnels?" — and the best modern answer is a WireGuard hub-and-spoke: every spoke keeps a single tunnel to the hub, the hub knows all the LANs, and a routing protocol over the overlay does the rest. It's simple, fast, NAT-friendly, and each new site is one peer on the hub plus one hub-pointing config on the spoke.
What you trade away versus Cisco DMVPN: there's no automatic direct spoke-to-spoke path. Branch-to-branch traffic hairpins through the hub unless you deliberately add spoke peers (a partial or full mesh). For most estates that's a fine trade — the hub is central and well-connected anyway. This is the RouterOS entry in the pattern the translation guide maps.
01
A single WireGuard interface on the hub, an overlay subnet, and one peer entry per branch. The hub is the only device that grows as you add sites — one line each.
/interface wireguard add name=wg-hub listen-port=13231 /ip address add address=172.16.0.1/24 interface=wg-hub # overlay # One peer per spoke. allowed-address = spoke's overlay /32 + its LAN, # so the hub routes toward that spoke correctly. No endpoint needed on the # hub if spokes have dynamic IPs — they connect in. /interface wireguard peers add interface=wg-hub public-key="<spokeA-pub>" \ allowed-address=172.16.0.11/32,10.10.0.0/24 comment="Branch-A" add interface=wg-hub public-key="<spokeB-pub>" \ allowed-address=172.16.0.12/32,10.20.0.0/24 comment="Branch-B"
The single biggest WireGuard confusion, and it bites hardest in hub-and-spoke. allowed-address on a peer does two things: it decides which source IPs are accepted from that peer, and — crucially — it's the cryptokey routing table that decides which destinations get sent to that peer. On the hub, each spoke peer must list that spoke's LAN so the hub sends branch traffic down the right tunnel. Overlap two peers' allowed-addresses and traffic goes to whichever WireGuard picks — a silent black hole. Keep them disjoint and specific.
02
Each spoke has one peer: the hub. Its allowed-address covers the overlay and every other LAN it should reach — which, in pure hub-and-spoke, it reaches via the hub.
/interface wireguard add name=wg-spoke listen-port=13231 /ip address add address=172.16.0.11/24 interface=wg-spoke # One peer: the hub. allowed-address = overlay + all remote LANs reachable # through it. persistent-keepalive punches through the spoke's NAT. /interface wireguard peers add interface=wg-spoke public-key="<hub-pub>" \ endpoint-address=203.0.113.1 endpoint-port=13231 \ allowed-address=172.16.0.0/24,10.20.0.0/24,10.30.0.0/24 \ persistent-keepalive=25s # To reach Branch-B (10.20.0.0/24), traffic rides this tunnel to the hub, # which forwards it down Branch-B's tunnel. Hairpin — but simple and robust.
03
Listing every remote LAN in every spoke's allowed-address gets unwieldy fast. Run OSPF over the overlay and each site learns the others automatically — add a branch and its subnet propagates without editing the rest.
# Run OSPF on the wg interfaces so LANs are learned, not hand-listed. # NOTE: you still need allowed-address to permit the traffic — use a wide # overlay + summarised LAN block per spoke, and let OSPF pick paths within. /routing ospf instance add name=v7 router-id=172.16.0.11 /routing ospf area add name=backbone area-id=0.0.0.0 instance=v7 /routing ospf interface-template add interfaces=wg-spoke area=backbone network-type=ptmp cost=10 # ptmp (point-to-multipoint) suits a hub with many spokes on one subnet.
If two branches exchange heavy traffic and the hairpin hurts, WireGuard makes a direct path trivial — add each other as a peer on both spokes (their overlay IP + LAN, and an endpoint if both have public IPs). That's a manual mesh edge, not DMVPN's automatic on-demand tunnel, but it's a two-line fix for the specific pairs that need it. For sites behind NAT with no public IP, direct spoke-to-spoke isn't reliably possible without a relay — which is exactly why the hub model is the sane default. Right tool, honest limits.
04
Confirm handshakes on every peer, the overlay routes learned, and end-to-end reachability sourced from a LAN.
/interface wireguard peers print # last-handshake recent on every peer /routing ospf neighbor print # spokes adjacent to the hub /ip route print where ospf # remote LANs learned via the overlay /ping 10.20.0.1 src-address=10.10.0.1 # branch A LAN -> branch B LAN
| Symptom | Where to look |
|---|---|
| No handshake | Wrong public key / endpoint, or UDP 13231 blocked. Check both peers' keys. |
| Handshake up, no traffic | allowed-address doesn't cover the destination LAN (cryptokey routing). |
| Branch-to-branch fails | Hub not forwarding — missing spoke LAN in the hub peer, or no route. |
| Spoke behind NAT drops | Add persistent-keepalive so the NAT mapping stays open. |
Takeaways
allowed-address is cryptokey routing, not a filter — on the hub it must list each spoke's LAN, kept disjoint, or traffic black-holes.NOCTIS builds scalable hub-and-spoke WANs on MikroTik and Cisco across Crete — WireGuard overlays that route dynamically, add a branch in two lines, and fail over cleanly.
Book a Discovery Call →