MikroTik Guide
Isometric white router with two antennas, a glowing pink padlock and a keyhole badge on top, pink cables branching to glowing nodes on a dark dotted surface
Networking

MikroTik WireGuard VPN Configuration on RouterOS 7: Interface, Peers, Allowed-Address and the Firewall Rule

A MikroTik WireGuard VPN configuration in packet order: interface and keys, peer and allowed-address, address and route, the input rule that must sit above the defconf drop, then the road-warrior and site-to-site variants and the tests that prove the tunnel.

By MikroTik Guide Editorial · · 6 min read

A working mikrotik wireguard vpn configuration is four commands and one firewall rule, and most of the broken ones on the forum got the four commands right. What breaks is allowed-address, an input-chain accept that landed under the defconf drop, or a peer that keeps firing handshakes at an endpoint it should be waiting for. This post walks the RouterOS 7 pieces in the order a packet meets them, then the road-warrior and site-to-site variants and the checks that prove the tunnel carries traffic, not just handshakes.

What a peer entry actually is

WireGuard has no server, no client and no session to log into. An interface owns one private key; each peer entry pairs a remote public key with an allowed-address list. WireGuard calls this cryptokey routing and defines it in one sentence: “When sending packets, the list of allowed IPs behaves as a sort of routing table, and when receiving packets, the list of allowed IPs behaves as a sort of access control list.” Every mistake below is a failure to take that sentence literally.

Underneath sits the Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s handshake: one round trip over UDP, Curve25519 for the key agreement, ChaCha20-Poly1305 for the data. A peer sends to “the most recent IP endpoint for which they authentically decrypted data”, so a phone moving from LTE to Wi-Fi keeps the tunnel without reconnecting, and RouterOS exposes that learned address as the read-only current-endpoint-address. The WireGuard keys and AllowedIPs explainer on wireguardlab.com goes deeper on the protocol.

Step 1: the interface and its keys

/interface/wireguard
add listen-port=13231 name=wireguard1
/interface/wireguard/print

Per the MikroTik WireGuard documentation, private-key is generated on creation when you do not supply one, listen-port defaults to 13231 and mtu to 1420. print shows both keys. The public key is what the other end needs; the private key never leaves the router, and the documentation is blunt that it is never needed on the remote side.

Step 2: peers, and the allowed-address trap

/interface/wireguard/peers
add interface=wireguard1 public-key="<remote public key>" \
    allowed-address=10.255.255.2/32,10.1.101.0/24 \
    endpoint-address=203.0.113.10 endpoint-port=13231 persistent-keepalive=25s

Three documented rules. The tunnel address in allowed-address has to be in the same subnet as the address you put on the WireGuard interface. Ranges cannot overlap between peers on one interface, so every road-warrior peer gets its own /32. And for site-to-site, the remote LAN prefix goes in the same list, or the far side’s replies are discarded on arrival.

Two things allowed-address does not do. It does not install a route on RouterOS; /ip/route is still your job. And it does not log what it drops. A packet whose source is outside the list is silently discarded, because WireGuard is designed to say nothing to traffic it does not trust. The symptom is last-handshake refreshing while ping across the tunnel dies, and that is nearly always a missing prefix in allowed-address.

preshared-key is optional. The documentation describes it as an extra symmetric-key layer mixed into the public-key exchange “for post-quantum resistance”. Generate it once, paste the same value on both peers.

Step 3: address, route, firewall

/ip/address
add address=10.255.255.1/30 interface=wireguard1
/ip/route
add dst-address=10.1.101.0/24 gateway=wireguard1
/ip/firewall/filter
add chain=input action=accept protocol=udp dst-port=13231 \
    comment="allow WireGuard" place-before=1

The place-before=1 is not decoration. The default firewall ends the input chain with drop all not coming from LAN, and new rules append at the bottom. An accept written without place-before sits under the drop and never sees a WAN packet. Nothing logs it; the only evidence is a last-handshake field that stays empty. The RouterOS firewall post covers the shadowing rule in general; this is its most common instance.

To let tunnel peers reach services on the router itself (DNS on UDP 53, WinBox on TCP 8291), the documentation offers an input accept for the tunnel subnet or adding wireguard1 to the LAN interface list. The list is the better answer, because forward and NAT key on lists too: forward drops only new connections arriving on the WAN list without a dst-nat, so a tunnel interface outside that list forwards to the LAN by default, and the masquerade rule matches out-interface-list=WAN, so tunnel clients reach the internet with no new NAT rule. Treating the tunnel as untrusted takes explicit forward rules.

Road warrior: RouterOS as the responder

/interface/wireguard
add listen-port=13231 name=wg-rw
/ip/address
add address=192.168.100.1/24 interface=wg-rw
/interface/wireguard/peers
add interface=wg-rw name=phone private-key=auto responder=yes \
    allowed-address=192.168.100.2/32 client-address=192.168.100.2/32 \
    client-dns=192.168.100.1 client-endpoint=vpn.example.net:13231 client-keepalive=25s

private-key=auto makes RouterOS generate the phone’s keypair, and the client-* fields populate the config that show-client-config renders as a QR code for the WireGuard app. Version gates, all from the documentation: the name field arrived in 7.15, client-allowed-address in 7.21 (before that the exported AllowedIPs is fixed at 0.0.0.0/0, ::/0), and viewing the QR code needs the show-sensitive permission from 7.21_ab548. Leave client-address empty and the export defaults to 192.168.177.2/24. To let the phone generate its own keys, drop private-key=auto and paste its public key into public-key.

The documentation states that without it the router will “repeatedly try to connect” to endpoint-address or the last learned endpoint. A server peer with no endpoint has nothing to connect to, and on a multi-WAN box the documentation requires responder so replies leave via the interface the handshake arrived on rather than whichever WAN the routing table prefers.

For client-dns to work, /ip/dns set allow-remote-requests=yes and the input accept for 192.168.100.0/24 (or the LAN list membership) both have to be in place. A phone with AllowedIPs 0.0.0.0/0 and no DNS answer looks exactly like a dead tunnel.

Site to site, both ends RouterOS

The documentation’s worked example puts Office1 on LAN 10.1.202.0/24 with tunnel address 10.255.255.1/30 and Office2 on 10.1.101.0/24 with 10.255.255.2/30. Each side’s peer entry lists the other’s tunnel /32 plus its LAN /24 in allowed-address, sets endpoint-address to the other’s public IP, and each side adds one /ip/route for the remote LAN via its WireGuard interface. Both ends initiate, so neither needs responder.

If one office sits behind CGNAT in 100.64.0.0/10, it cannot be the target. Give it the endpoint and the keepalive, set responder=yes on the public side and omit its endpoint-address; the public side learns where the CGNAT office is from the first authenticated packet.

Keepalive and MTU

RFC 4787 requires that a NAT’s UDP mapping “MUST NOT expire in less than two minutes” and recommends five, but WireGuard only sends when it has data, so an idle tunnel behind NAT loses its mapping and the next inbound packet has nowhere to go. The WireGuard quick start recommends 25 seconds as the interval that “works with a wide variety of firewalls”, and MikroTik’s documentation repeats the figure. Set it on the NATted side only.

The 1420 default is 1500 minus the tunnel overhead: an outer IPv4 header of 20 bytes or IPv6 of 40, 8 of UDP, and 32 of WireGuard framing (4-byte type, 4-byte receiver index, 8-byte counter, 16-byte Poly1305 tag). Over a PPPoE WAN at 1492, IPv4 transport still fits at 1420 but an IPv6 outer header does not, so set mtu=1412 in that case, and clamp TCP MSS on the tunnel the same way the PPPoE post does for the WAN. The WireGuard MTU calculator on wireguardlab.com does the arithmetic for other paths.

Things to test before you call it done

/interface/wireguard/peers/print detail

Read three fields. last-handshake empty means the firewall, the port or the keys; nothing else can stop the handshake. last-handshake ticking with rx frozen means allowed-address or a missing route. current-endpoint-address tells you which WAN the far side actually reached you on.

Then prove the path one hop at a time:

/ping 10.255.255.2 src-address=10.255.255.1
/ping 10.1.101.1 src-address=10.1.202.1
/tool/torch interface=wireguard1

From a workstation on the LAN: mtr -n 10.1.101.10 to confirm the route enters the tunnel rather than the WAN, ping -M do -s 1392 10.1.101.10 to prove a 1420-byte packet crosses unfragmented (1392 plus 28 bytes of ICMP and IP headers), iperf3 -c 10.1.101.10 and then iperf3 -c 10.1.101.10 -R because upload and download cross different NATs, and from the phone dig @192.168.100.1 example.com to confirm allow-remote-requests and the input rule agree. A tunnel that passes all five is configured. One that passes only the handshake is not.

Sources

  1. WireGuard - MikroTik Documentation
  2. Building Your First Firewall - MikroTik Documentation
  3. WireGuard: fast, modern, secure VPN tunnel
  4. Protocol & Cryptography - WireGuard
  5. Quick Start - WireGuard
  6. RFC 4787: Network Address Translation (NAT) Behavioral Requirements for Unicast UDP

Related