Skip to content
MikroTik RouterOS Docs

WireGuard Site-to-Site VPN: Complete Configuration Guide

WireGuard Site-to-Site VPN: Complete Configuration Guide

Section titled “WireGuard Site-to-Site VPN: Complete Configuration Guide”

RouterOS Version: 7.x+ Difficulty: Intermediate Estimated Time: 30 minutes

For the impatient: here’s the 30-second version.

# On both routers: create interface and get public key
/interface wireguard add name=wg-tunnel listen-port=13231
/interface wireguard print
# On initiator (Office A): configure peer with remote endpoint
/interface wireguard peers add interface=wg-tunnel public-key="OFFICE_B_KEY" allowed-address=10.2.0.0/24,10.255.255.2/32 endpoint-address=198.51.100.20 endpoint-port=13231
/ip address add address=10.255.255.1/30 interface=wg-tunnel
# On responder (Office B): configure peer without endpoint
/interface wireguard peers add interface=wg-tunnel public-key="OFFICE_A_KEY" allowed-address=10.1.0.0/24,10.255.255.1/32
/ip address add address=10.255.255.2/30 interface=wg-tunnel

WireGuard is a modern VPN protocol that provides secure, high-performance tunnels between sites with minimal configuration overhead. Unlike traditional IPsec, WireGuard uses state-of-the-art cryptography and a simple peer-to-peer model that makes site-to-site connections both easier to configure and more reliable to maintain.

This guide explains how to establish secure tunnels between remote offices, covering the essential concepts, common pitfalls, and troubleshooting techniques that separate working configurations from broken ones.

WireGuard operates on a peer-to-peer basis - there’s no inherent “server” or “client” distinction. Each endpoint is a peer that can initiate connections to other peers. This simplicity is both WireGuard’s strength and the source of most configuration errors.

WireGuard Site-to-Site Tunnel

Public/Private Key Pairs: Each WireGuard interface has a unique key pair. The private key never leaves the device; public keys are exchanged between peers for authentication.

Allowed Addresses: This is the most critical and misunderstood setting. It serves two purposes:

  1. Ingress filtering: Traffic FROM these addresses is accepted from this peer
  2. Routing table: Traffic TO these addresses is sent to this peer

Endpoint: The public IP address and port where a peer can be reached. Only one peer needs to know the other’s endpoint - WireGuard learns return paths automatically.

The most common error is configuring overlapping allowed-addresses on the same interface:

# WRONG - This will cause routing conflicts
/interface wireguard peers
add allowed-address=10.1.0.0/24 interface=wg1 public-key="peer1-key"
add allowed-address=10.1.0.0/24 interface=wg1 public-key="peer2-key" # Overlap!

Each subnet can only be allowed from one peer per interface. If multiple peers need access to the same subnet, they must share a single peer configuration or use different WireGuard interfaces.

For this guide, we’ll configure a tunnel between two offices:

WireGuard Site-to-Site Architecture

Tunnel addressing: We use 10.255.255.0/30 for the tunnel itself - a point-to-point link between the routers.

Routing logic:

  • Traffic to 10.2.0.0/24 from Office A → goes via wg-tunnel to Office B
  • Traffic to 10.1.0.0/24 from Office B → goes via wg-tunnel to Office A
  • Both routers have public IP addresses or port forwarding configured
  • RouterOS 7.x+ installed on both devices
  • UDP port 13231 (or chosen port) accessible from the internet
  • Basic understanding of IP routing and subnetting

This minimal example establishes a working tunnel between two sites. We’ll configure Office A as the initiator (knows Office B’s endpoint) and Office B as the responder.

On both routers, create the WireGuard interface. This automatically generates the cryptographic key pairs:

/interface wireguard add name=wg-tunnel listen-port=13231

Display the generated public key on each router:

/interface wireguard print

Note the public-key value from each router - you’ll need to configure these on the opposite peer.

Office A (Initiator):

/interface wireguard peers add interface=wg-tunnel public-key="OFFICE_B_PUBLIC_KEY" allowed-address=10.2.0.0/24,10.255.255.2/32 endpoint-address=198.51.100.20 endpoint-port=13231

Office B (Responder):

/interface wireguard peers add interface=wg-tunnel public-key="OFFICE_A_PUBLIC_KEY" allowed-address=10.1.0.0/24,10.255.255.1/32 responder=yes

Key differences:

  • Office A specifies the endpoint-address (Office B’s public IP)
  • Office B uses responder=yes (only responds, doesn’t initiate)
  • Each peer’s allowed-address includes the remote LAN and tunnel IP

Office A:

/ip address add address=10.255.255.1/30 interface=wg-tunnel

Office B:

/ip address add address=10.255.255.2/30 interface=wg-tunnel

Verify the WireGuard interface is running:

/interface wireguard print

Expected Output:

Flags: R - RUNNING
0 R name="wg-tunnel" mtu=1420 listen-port=13231 private-key="..." public-key="..."

Confirm the tunnel has established successfully:

/interface wireguard peers print

Expected Output:

0 interface=wg-tunnel public-key="..." allowed-address=10.2.0.0/24,10.255.255.2/32
current-endpoint-address=198.51.100.20 current-endpoint-port=13231 last-handshake=5s

The last-handshake should show a recent time (under 3 minutes).

Test basic tunnel connectivity:

/ping 10.255.255.2 count=3

Expected Output:

SEQ HOST SIZE TTL TIME STATUS
0 10.255.255.2 56 64 25ms
1 10.255.255.2 56 64 24ms
2 10.255.255.2 56 64 26ms
sent=3 received=3 packet-loss=0% min-rtt=24ms avg-rtt=25ms max-rtt=26ms

For automatic routing between LANs, add static routes on both routers:

Office A:

/ip route add dst-address=10.2.0.0/24 gateway=wg-tunnel

Office B:

/ip route add dst-address=10.1.0.0/24 gateway=wg-tunnel

If you have restrictive firewall rules, allow WireGuard traffic:

Allow WireGuard UDP traffic:

/ip firewall filter add action=accept chain=input protocol=udp dst-port=13231 place-before=0

Allow tunnel traffic forwarding:

/ip firewall filter add action=accept chain=forward in-interface=wg-tunnel place-before=0
/ip firewall filter add action=accept chain=forward out-interface=wg-tunnel place-before=0

If devices behind the tunnel need internet access via the remote site, configure source NAT:

/ip firewall nat add action=masquerade chain=srcnat out-interface=ether1 src-address=10.1.0.0/24

Symptoms: last-handshake shows “never” or very old timestamp

Common Causes and Solutions:

  1. Firewall blocking UDP: Ensure UDP port 13231 is allowed on both routers

    /ip firewall filter add chain=input protocol=udp dst-port=13231 action=accept place-before=0
  2. Wrong or unreachable endpoint: Confirm the endpoint-address is correct and reachable

    /tool traceroute 198.51.100.20
    /ping 198.51.100.20
  3. Public key mismatch: Each peer must have the OTHER router’s public key

    # On Router A, peer entry should have Router B's public key (not Router A's)
    /interface wireguard peers print
  4. NAT without port forwarding: If the endpoint router is behind NAT, configure port forwarding for UDP 13231

  5. Time synchronization: WireGuard requires accurate clocks on both endpoints

    /system ntp client print
    /system clock print

WebFig Bug: Empty endpoint-address

Critical: WebFig has a known bug where saving a peer without an endpoint-address sets it to "" (empty string) instead of leaving it unset. This causes handshakes to fail.

Symptoms: Tunnel worked, then stopped after editing peer in WebFig. Config appears correct.

Check for the bug:

/interface wireguard peers print detail
# Look for: endpoint-address=""

Solution: Use CLI to properly remove the endpoint-address:

# This is WRONG (WebFig does this):
/interface wireguard peers set 0 endpoint-address=""
# This is CORRECT - use CLI to unset:
/interface wireguard peers unset 0 endpoint-address

Always use CLI (not WebFig) when configuring WireGuard peers without endpoints.

Debug commands:

/log print where topics~"wireguard"
/interface wireguard peers print detail

Symptoms: Tunnel IPs ping, but LAN-to-LAN traffic fails

Solutions:

  1. Check allowed-address: Must include both tunnel IPs AND remote LANs
  2. Verify routing: Add explicit routes to remote networks
  3. Firewall rules: Ensure forward chain allows tunnel traffic
  4. Asymmetric routing: Check that return traffic uses the same path

Debug commands:

/ip route print where gateway=wg-tunnel
/tool traceroute 10.2.0.1 src-address=10.1.0.1

Symptoms: Tunnel works intermittently, handshake times vary wildly, last-handshake shows >2 minutes

Solutions:

  1. Add keepalive for NAT traversal: The peer BEHIND NAT must send keepalives to maintain the NAT mapping

    # On the peer that is behind NAT (the initiator/client side)
    /interface wireguard peers set 0 persistent-keepalive=25s
  2. MTU issues: Reduce MTU to avoid fragmentation

    /interface wireguard set wg-tunnel mtu=1380
  3. ISP blocking: Some ISPs block or throttle VPN traffic - try different ports

    /interface wireguard set wg-tunnel listen-port=51820
  4. Dynamic IP without DDNS: If the endpoint’s public IP changes, implement DDNS and use hostname for endpoint-address

Symptoms: Routing table conflicts, traffic goes to wrong peer

Solution: Each subnet can only appear in one peer’s allowed-address per interface:

# WRONG - 10.1.0.0/24 appears twice
add allowed-address=10.1.0.0/24,10.2.0.0/24 interface=wg-tunnel public-key="peer1"
add allowed-address=10.1.0.0/24,10.3.0.0/24 interface=wg-tunnel public-key="peer2"
# CORRECT - Non-overlapping subnets
add allowed-address=10.2.0.0/24 interface=wg-tunnel public-key="peer1"
add allowed-address=10.3.0.0/24 interface=wg-tunnel public-key="peer2"
# Check WireGuard interface statistics
/interface wireguard print stats
# Monitor peer connection status
/interface wireguard peers print detail
# View WireGuard-specific logs
/log print where topics~"wireguard"
# Test tunnel with specific source
/ping 10.2.0.1 src-address=10.1.0.1
# Check routing table for tunnel routes
/ip route print where gateway~"wg"
  • Never share private keys - each device generates its own
  • Rotate keys periodically - especially if devices are compromised
  • Use strong entropy - RouterOS generates cryptographically secure keys automatically
# Restrict tunnel traffic to specific services
/ip firewall filter add action=accept chain=forward in-interface=wg-tunnel dst-port=22,80,443 protocol=tcp
/ip firewall filter add action=drop chain=forward in-interface=wg-tunnel
# Log all tunnel connections
/system logging add topics=wireguard action=memory
# Monitor data usage per peer
/interface wireguard peers print stats

For connecting multiple branch offices through a central hub:

Hub-and-Spoke Topology

Hub configuration: Each branch gets its own peer with non-overlapping allowed-addresses.

Branch configuration: Each branch only needs one peer pointing to the hub.

For direct branch-to-branch communication without going through a hub:

Full Mesh Topology

Configuration: Each router needs peers for every other router. With N sites, each router needs N-1 peer configurations.

WireGuard benefits from AES-NI acceleration on x86 devices:

/system resource print
# Look for "cpu-features" containing "aes"

Optimize MTU to avoid fragmentation:

# Test optimal MTU size
/ping 8.8.8.8 size=1472 do-not-fragment
# Adjust WireGuard MTU accordingly
/interface wireguard set wg-tunnel mtu=1420

Monitor connection tracking on high-traffic tunnels:

/ip firewall connection print count-only
/ip settings print