Skip to content
MikroTik RouterOS Docs

WireGuard VPN

Create a basic WireGuard tunnel between two routers:

On Router A (initiator):

/interface wireguard add name=wg-tunnel listen-port=13231
/interface wireguard print
# Note the public-key value and share with Router B
/interface wireguard peers add interface=wg-tunnel \
public-key="<ROUTER_B_PUBLIC_KEY>" \
allowed-address=10.255.255.2/32,192.168.2.0/24 \
endpoint-address=198.51.100.20 endpoint-port=13231
/ip address add address=10.255.255.1/30 interface=wg-tunnel
/ip route add dst-address=192.168.2.0/24 gateway=wg-tunnel

On Router B (responder):

/interface wireguard add name=wg-tunnel listen-port=13231
/interface wireguard print
# Note the public-key value and share with Router A
/interface wireguard peers add interface=wg-tunnel \
public-key="<ROUTER_A_PUBLIC_KEY>" \
allowed-address=10.255.255.1/32,192.168.1.0/24
/ip address add address=10.255.255.2/30 interface=wg-tunnel
/ip route add dst-address=192.168.1.0/24 gateway=wg-tunnel

Add firewall rule on both:

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

WireGuard is a modern VPN protocol that provides secure, high-performance tunnels using state-of-the-art cryptography (Curve25519, ChaCha20, Poly1305, BLAKE2s). It operates on a peer-to-peer model with no inherent server/client distinction.

What this does:

  • Creates encrypted tunnels between RouterOS devices or third-party clients
  • Uses cryptographic key pairs for authentication (no passwords)
  • Routes traffic based on “allowed-address” lists (cryptokey routing)
  • Automatically handles NAT traversal with keepalive packets

When to use WireGuard:

  • Site-to-site tunnels between offices
  • Road warrior remote access for mobile devices
  • Hub-and-spoke VPN topologies
  • When you need simpler configuration than IPsec
  • When you want better performance than OpenVPN

When NOT to use it:

  • Compatibility with legacy devices that don’t support WireGuard
  • When you need certificate-based authentication
  • When TCP-based VPN is required (some corporate firewalls block UDP)
  • MikroTik router running RouterOS 7.1 or later
  • At least one side with a public IP or port forwarding configured
  • UDP port 13231 (default) accessible through firewalls
  • Access to exchange public keys between peers

Create a WireGuard interface on each router. The private key is auto-generated.

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

Display the interface to see the auto-generated public key:

/interface wireguard print

Example Output:

Flags: X - disabled; R - running
0 R name="wg-tunnel" mtu=1420 listen-port=13231
private-key="<hidden>"
public-key="A1B2C3D4E5F6G7H8I9J0K1L2M3N4O5P6Q7R8S9T0U1V="

Copy the public-key value and share it with the remote peer (via secure channel like email or chat).

Add the remote peer using their public key and define which networks are reachable through them:

/interface wireguard peers add interface=wg-tunnel \
public-key="<REMOTE_PUBLIC_KEY>" \
allowed-address=10.255.255.2/32,192.168.2.0/24 \
endpoint-address=198.51.100.20 \
endpoint-port=13231

Key properties:

  • public-key: The remote peer’s public key (required)
  • allowed-address: Networks reachable via this peer (acts as both ACL and routing)
  • endpoint-address: Remote peer’s public IP or hostname (required on initiator)
  • endpoint-port: Remote peer’s WireGuard port

Assign an IP address to the WireGuard interface for the tunnel network:

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

Use a dedicated /30 or /31 subnet for point-to-point tunnels.

Add static routes for the remote LAN:

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

Allow WireGuard handshake traffic and forwarding:

/ip firewall filter
add action=accept chain=input protocol=udp dst-port=13231 comment="WireGuard" place-before=0
add action=accept chain=forward in-interface=wg-tunnel comment="WireGuard forward in" place-before=0
add action=accept chain=forward out-interface=wg-tunnel comment="WireGuard forward out" place-before=0

Configure a server with multiple mobile clients (phones, laptops) connecting remotely:

Server Configuration:

# Create interface
/interface wireguard add name=wg-server listen-port=13231
# Assign server IP (use a dedicated subnet for VPN clients)
/ip address add address=192.168.100.1/24 interface=wg-server
# Add peers for each client (use /32 for individual clients)
/interface wireguard peers add interface=wg-server \
public-key="<CLIENT_1_PUBLIC_KEY>" \
allowed-address=192.168.100.2/32 \
name=laptop
/interface wireguard peers add interface=wg-server \
public-key="<CLIENT_2_PUBLIC_KEY>" \
allowed-address=192.168.100.3/32 \
name=phone
# Firewall rules - allow WireGuard and forwarding
/ip firewall filter
add action=accept chain=input protocol=udp dst-port=13231 place-before=0
add action=accept chain=forward in-interface=wg-server place-before=0
add action=accept chain=forward out-interface=wg-server place-before=0
# NAT masquerade - REQUIRED for clients to access internet through VPN
/ip firewall nat add action=masquerade chain=srcnat out-interface=ether1 \
src-address=192.168.100.0/24 comment="WireGuard road warrior NAT"

Common Issue

Without the NAT masquerade rule, road warrior clients can connect but won’t have internet access through the VPN. This is the most common “connected but no internet” problem.

Client Configuration (for WireGuard app on iOS/Android/Windows/macOS):

Split tunnel - only VPN traffic goes through tunnel (recommended):

[Interface]
Address = 192.168.100.2/24
PrivateKey = <client_private_key>
DNS = 192.168.100.1
[Peer]
PublicKey = <server_public_key>
Endpoint = server.example.com:13231
AllowedIPs = 192.168.100.0/24, 192.168.1.0/24
PersistentKeepalive = 25

Full tunnel - ALL traffic goes through VPN (for privacy/security):

[Interface]
Address = 192.168.100.2/24
PrivateKey = <client_private_key>
DNS = 192.168.100.1
[Peer]
PublicKey = <server_public_key>
Endpoint = server.example.com:13231
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25

Generating client keys: Use the WireGuard app to generate keys, or on a MikroTik:

# Generate a key pair for the client
/interface wireguard
add name=temp-keygen
print
# Copy the private-key and public-key, then remove
remove temp-keygen

When your MikroTik is behind a NAT router (double NAT scenario):

# Create interface
/interface wireguard add name=wg-client listen-port=13231
# Assign tunnel IP
/ip address add address=10.255.255.2/30 interface=wg-client
# Configure peer with persistent-keepalive to maintain NAT mapping
/interface wireguard peers add interface=wg-client \
public-key="<SERVER_PUBLIC_KEY>" \
allowed-address=10.255.255.1/32,192.168.0.0/24 \
endpoint-address=server.example.com \
endpoint-port=13231 \
persistent-keepalive=25s
# Add route to remote network
/ip route add dst-address=192.168.0.0/24 gateway=wg-client

The persistent-keepalive=25s sends a packet every 25 seconds to keep the NAT mapping alive.

When the server has a static IP and should only respond to connections (never initiate):

/interface wireguard peers add interface=wg-server \
public-key="<CLIENT_PUBLIC_KEY>" \
allowed-address=192.168.100.2/32 \
responder=yes

The responder=yes setting prevents the server from attempting to initiate handshakes to clients with dynamic IPs.

Import an existing WireGuard configuration:

/interface wireguard wg-import file=client.conf

Or import from a string:

/interface wireguard wg-import config-string="[Interface]
Address=192.168.88.3/24
ListenPort=13533
PrivateKey=<key>
[Peer]
PublicKey=<key>
Endpoint=199.168.100.10:51820
AllowedIPs=0.0.0.0/0
PersistentKeepalive=25"
/interface wireguard print

Expected Output:

Flags: X - disabled; R - running
0 R name="wg-tunnel" mtu=1420 listen-port=13231
private-key="..." public-key="..."

The “R” flag indicates the interface is running.

/interface wireguard peers print

Expected Output:

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

The last-handshake should show a recent time (under 3 minutes). If it shows “never”, the handshake hasn’t completed.

/ping 10.255.255.2 count=3

Expected: Successful replies with 0% packet loss.

/interface wireguard peers print stats

Expected: rx and tx bytes should increment when traffic flows.

Problem: Handshake never completes (last-handshake shows “never”)

Section titled “Problem: Handshake never completes (last-handshake shows “never”)”

Cause: Firewall blocking UDP traffic on port 13231.

Solution: Add firewall rule to accept WireGuard traffic:

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

Problem: Handshake works but no traffic passes between LANs

Section titled “Problem: Handshake works but no traffic passes between LANs”

Cause: Missing forward firewall rules or incorrect allowed-address.

Solution:

  1. Add forward rules:
/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
  1. Verify allowed-address includes the remote LAN subnet.

Cause: Overlapping subnets in allowed-address across multiple peers.

Solution: Each subnet can only appear in ONE peer’s allowed-address. Use /32 for individual clients:

# Wrong - overlapping
add allowed-address=10.0.0.0/24 public-key="peer1"
add allowed-address=10.0.0.0/24 public-key="peer2"
# Correct - unique addresses
add allowed-address=10.0.0.1/32 public-key="peer1"
add allowed-address=10.0.0.2/32 public-key="peer2"

Problem: Tunnel works initially then drops after inactivity

Section titled “Problem: Tunnel works initially then drops after inactivity”

Cause: NAT state timeout on upstream device.

Solution: Enable persistent-keepalive on the peer behind NAT:

/interface wireguard peers set [find name=my-peer] persistent-keepalive=25s

Cause: First peer has allowed-address=0.0.0.0/0 which captures all routing.

Solution: Only use 0.0.0.0/0 for single-peer “route all traffic” scenarios. Otherwise use specific subnets.

Problem: Configuration correct but handshake never completes (ISP issue)

Section titled “Problem: Configuration correct but handshake never completes (ISP issue)”

Cause: Some ISPs/carriers filter UDP traffic on non-standard ports.

Solution:

  1. Try a different port number (e.g., 51820)
  2. Test from a different network to isolate the issue

Cause: Default MTU of 1420 too large for some networks (especially with double NAT).

Solution: Reduce MTU on the WireGuard interface:

/interface wireguard set wg-tunnel mtu=1380
  • IP Cloud - DDNS for dynamic IP endpoints
  • VRRP - high availability for VPN gateways