🚀 Launching your own ISP? Create a free account and get 1 router slot for life!
Back to all articles
Tutorial By MikroRadius Team

WireGuard Hub-and-Spoke VPN on MikroTik: Central Office with Multiple Branches

Need to connect three or more branch offices to a central headquarters? This tutorial shows how to build a scalable hub‑and‑spoke WireGuard VPN on MikroTik – central router as hub, branches as spokes, with routing, NAT bypass, and traffic isolation.

Once you have more than two sites, point‑to‑point WireGuard tunnels become messy. A hub‑and‑spoke topology simplifies management: all branch offices (spokes) connect to a central headquarters (hub). The hub routes traffic between spokes and provides access to central servers. This guide walks you through setting up a scalable multi‑site WireGuard VPN on MikroTik RouterOS v7.

Why Hub‑and‑Spoke WireGuard?

  • Central management – Add or remove branches from the hub without touching other spokes.
  • Efficient routing – Spokes only need one tunnel (to the hub), not N‑1 tunnels.
  • Centralised security – Apply firewall policies at the hub for inter‑branch traffic.
  • Lower complexity – Fewer peer entries overall compared to full mesh.

Topology Example

  • Hub (Headquarters): LAN 192.168.1.0/24, public IP 203.0.113.10 (static).
  • Spoke A (Branch A): LAN 192.168.2.0/24, public IP 198.51.100.20 (static).
  • Spoke B (Branch B): LAN 192.168.3.0/24, public IP 198.51.100.30 (dynamic – uses DDNS).
  • All branches communicate with the hub. Optionally, the hub can route traffic between spokes (e.g., Branch A to Branch B).

Prerequisites

  • Hub router: MikroTik with RouterOS v7.1+, static public IP recommended.
  • Spoke routers: MikroTik with RouterOS v7.1+, public IP or DDNS.
  • Unique LAN subnets for each site (no overlaps).
  • Basic understanding of IP routing and firewall.

Step 1: Hub Configuration – WireGuard Interface

On the central router, create a WireGuard interface that will accept connections from all spokes.

/interface wireguard add name=wg-hub listen-port=51820

Note the generated public key:

/interface wireguard print

Save the hub's public key – you'll need it for each spoke.

Step 2: Hub – Assign Tunnel IPs and Address Pool

Assign a /24 subnet for the tunnel interfaces. Each spoke will get a unique /30 from this range, but a simpler approach is to give each spoke a separate tunnel IP (e.g., 10.10.10.2 for Spoke A, 10.10.10.3 for Spoke B) and the hub gets 10.10.10.1.

/ip address add address=10.10.10.1/24 interface=wg-hub

Step 3: Hub – Add Peer Entries for Each Spoke

For each spoke, create a separate peer entry. Use the spoke's public key and allowed addresses (tunnel IP + spoke's LAN).

Spoke A peer (LAN 192.168.2.0/24, tunnel IP 10.10.10.2):

/interface wireguard peers add interface=wg-hub public-key="<SpokeA-public-key>" allowed-address=10.10.10.2/32,192.168.2.0/24

Spoke B peer (LAN 192.168.3.0/24, tunnel IP 10.10.10.3):

/interface wireguard peers add interface=wg-hub public-key="<SpokeB-public-key>" allowed-address=10.10.10.3/32,192.168.3.0/24

The hub does not specify endpoint-address for spokes if the spokes will initiate the connection (recommended).

Step 4: Hub – Firewall and NAT Bypass

Allow incoming WireGuard traffic on the hub:

/ip firewall filter add chain=input protocol=udp dst-port=51820 action=accept comment="Allow WireGuard hub"

Allow forwarding between hub LAN and spoke LANs, and optionally between spokes:

/ip firewall filter add chain=forward connection-state=established,related action=accept
/ip firewall filter add chain=forward src-address=192.168.1.0/24 dst-address=192.168.2.0/24 action=accept
/ip firewall filter add chain=forward src-address=192.168.2.0/24 dst-address=192.168.1.0/24 action=accept
/ip firewall filter add chain=forward src-address=192.168.1.0/24 dst-address=192.168.3.0/24 action=accept
/ip firewall filter add chain=forward src-address=192.168.3.0/24 dst-address=192.168.1.0/24 action=accept
# Optional: allow spoke-to-spoke via hub
/ip firewall filter add chain=forward src-address=192.168.2.0/24 dst-address=192.168.3.0/24 action=accept
/ip firewall filter add chain=forward src-address=192.168.3.0/24 dst-address=192.168.2.0/24 action=accept

Prevent NAT of VPN traffic (add above your masquerade rule):

/ip firewall nat add chain=srcnat src-address=192.168.1.0/24 dst-address=192.168.2.0/24 action=accept
/ip firewall nat add chain=srcnat src-address=192.168.1.0/24 dst-address=192.168.3.0/24 action=accept
/ip firewall nat add chain=srcnat src-address=192.168.2.0/24 dst-address=192.168.1.0/24 action=accept
/ip firewall nat add chain=srcnat src-address=192.168.3.0/24 dst-address=192.168.1.0/24 action=accept

Step 5: Spoke A Configuration

On Spoke A router (192.168.2.0/24 LAN, public IP 198.51.100.20).

Create WireGuard interface:

/interface wireguard add name=wg-spoke listen-port=51820

Assign tunnel IP (must match hub's allowed-address for this spoke):

/ip address add address=10.10.10.2/24 interface=wg-spoke

Add peer pointing to hub:

/interface wireguard peers add interface=wg-spoke public-key="<Hub-public-key>" endpoint-address=203.0.113.10 endpoint-port=51820 allowed-address=10.10.10.1/32,192.168.1.0/24

Firewall – allow WireGuard input and forward:

/ip firewall filter add chain=input protocol=udp dst-port=51820 action=accept
/ip firewall filter add chain=forward src-address=192.168.2.0/24 dst-address=192.168.1.0/24 action=accept
/ip firewall filter add chain=forward src-address=192.168.1.0/24 dst-address=192.168.2.0/24 action=accept

NAT bypass on Spoke A (above masquerade):

/ip firewall nat add chain=srcnat src-address=192.168.2.0/24 dst-address=192.168.1.0/24 action=accept

Step 6: Spoke B Configuration (Dynamic IP, Using DDNS)

Spoke B has a dynamic public IP. Enable MikroTik Cloud DDNS:

/ip cloud set ddns-enabled=yes
/ip cloud print

Note the hostname, e.g., spokeb.sn.mynetname.net. On the hub, we cannot use a dynamic endpoint because the hub needs to know where to send traffic. Instead, Spoke B will initiate and send keepalives.

On Spoke B:

/interface wireguard add name=wg-spoke listen-port=51820
/ip address add address=10.10.10.3/24 interface=wg-spoke
/interface wireguard peers add interface=wg-spoke public-key="<Hub-public-key>" endpoint-address=203.0.113.10 endpoint-port=51820 allowed-address=10.10.10.1/32,192.168.1.0/24 persistent-keepalive=25

On the hub, add Spoke B peer as before (without endpoint address, or with the DDNS hostname if you want two‑way initiation, but keepalive from spoke is simpler).

Step 7: Adding Static Routes for Remote LANs

WireGuard automatically adds routes based on allowed-address. Verify on hub:

/ip route print where dst-address~"192.168.2"

If missing, add manually. On hub, for routes to spoke LANs via the tunnel:

/ip route add dst-address=192.168.2.0/24 gateway=10.10.10.2
/ip route add dst-address=192.168.3.0/24 gateway=10.10.10.3

On each spoke, route to hub LAN:

/ip route add dst-address=192.168.1.0/24 gateway=10.10.10.1

If you want spokes to reach each other (via hub), add routes on spokes for the other spoke's LAN, with gateway = hub's tunnel IP (10.10.10.1).

Step 8: Testing the Hub‑and‑Spoke VPN

  1. On Spoke A, ping the hub's tunnel IP: ping 10.10.10.1 – should succeed.
  2. On Spoke A, ping a device on hub LAN: ping 192.168.1.1.
  3. On hub, ping Spoke A's LAN IP: ping 192.168.2.1.
  4. If inter‑spoke routing is enabled, from Spoke A ping Spoke B's LAN IP: ping 192.168.3.1 – this traffic goes through the hub.
  5. Check WireGuard peers on hub:
/interface wireguard peers print

You should see both spokes with recent handshakes.

Step 9: Enabling Spoke‑to‑Spoke Routing on the Hub (Optional)

By default, the hub will route between spokes if firewall rules permit and routes exist. Ensure the hub's forward chain allows traffic between 192.168.2.0/24 and 192.168.3.0/24 (we added those earlier). Also, the hub must have routes to both spoke LANs (automatic from allowed-address). Spokes need routes to each other's LANs via the hub.

On Spoke A, add:

/ip route add dst-address=192.168.3.0/24 gateway=10.10.10.1

On Spoke B, add:

/ip route add dst-address=192.168.2.0/24 gateway=10.10.10.1

Now traffic from Branch A to Branch B will go: Spoke A → hub → Spoke B.

Step 10: Adding a New Spoke (Scalability)

To add a third branch (Spoke C):

  1. On Spoke C, configure WireGuard interface, tunnel IP (e.g., 10.10.10.4/24), peer to hub.
  2. On hub, add a new peer for Spoke C with its public key, allowed-address=10.10.10.4/32,192.168.4.0/24.
  3. Add firewall forward and NAT bypass rules on hub for the new subnet.
  4. On existing spokes, optionally add route to 192.168.4.0/24 via hub if inter‑spoke access needed.

No changes needed on other spokes – they only know about the hub, not each new spoke.

Troubleshooting Hub‑and‑Spoke WireGuard

  • Spoke cannot handshake with hub: Verify hub's firewall allows UDP 51820. Check that the spoke's endpoint-address is correct and reachable. If spoke is behind CGNAT, you may need a VPS relay (advanced).
  • Handshake works but cannot ping remote LAN: Confirm that NAT bypass rules are in place (no masquerade between VPN subnets). Also ensure the hub has a route back to the spoke's LAN (allowed-address adds it automatically).
  • Spoke can ping hub tunnel IP but not hub LAN devices: Check the hub's forward chain – it must allow traffic from the spoke's tunnel IP or spoke LAN to the hub LAN.
  • Spoke‑to‑spoke ping fails: Ensure both spokes have routes to each other's LANs via the hub's tunnel IP. Also verify the hub's forward chain allows the traffic (both directions).
  • Dynamic IP spoke disconnects: Set persistent-keepalive=25 on the spoke's peer configuration so it sends keepalives through NAT.

Performance Considerations

  • The hub router's CPU handles encryption for all spokes. For many branches, use a powerful MikroTik (e.g., CCR series) or dedicate a CHR on a VM.
  • Inter‑spoke traffic traverses the hub twice (encrypt→decrypt→re‑encrypt), increasing latency. For heavy spoke‑to‑spoke traffic, consider a full mesh or a more advanced dynamic routing solution.
  • MTU issues can occur – set MTU to 1420 on all WireGuard interfaces if you experience packet fragmentation.

Comparing Hub‑and‑Spoke vs. Full Mesh vs. Point‑to‑Point

TopologyNumber of Tunnels (n sites)Best forDrawback
Point‑to‑point1Two sites onlyNot scalable
Hub‑and‑spoken-1Many branches, central servicesHub bottleneck, higher latency between spokes
Full meshn(n-1)/2Low latency between all sitesComplex configuration, many peers

Conclusion

A hub‑and‑spoke WireGuard VPN on MikroTik is the most practical way to interconnect multiple branch offices with a central headquarters. It balances simplicity, security, and scalability. Start with a single spoke, verify routing, then expand to additional branches. For dynamic routing across many sites, consider adding OSPF over the WireGuard tunnels to automatically exchange routes.

Once your hub‑and‑spoke network is stable, explore WireGuard over VLANs to segment different departments, or integrate with MikroRadius for per‑user VPN policies.

Was this article helpful?