← Writing

WireGuard vs the VPN you already have

Remote access is a decision you make once and live with for years. Right now you probably have one of four things: a port forwarded straight at RDP, a client VPN from whoever made your firewall, an OpenVPN server somebody set up and left, or a monthly subscription to a zero-trust product.

If you're weighing a change, it's worth knowing what WireGuard actually does differently — and what it flatly refuses to do.

It is small on purpose

OpenVPN and IPsec are frameworks. They negotiate: which cipher, which hash, which key exchange, which mode, which phase-2 proposal. That flexibility is why they interoperate with everything, and it is also why the config files are long and the failure messages are unreadable.

WireGuard picks one of each and ships no negotiation at all. The implementation is a few thousand lines — small enough to have been audited line by line, which is not a claim the alternatives can make. There is no cipher list to get wrong because there is no cipher list.

The practical consequence is a configuration you can hold in your head:

/interface/wireguard
add name=wg-remote listen-port=51820 mtu=1420

/interface/wireguard/peers
add interface=wg-remote public-key="..." allowed-address=10.10.10.5/32 \
    persistent-keepalive=25s comment="office laptop"

Three behaviors you notice daily

It has no concept of connecting. There is no session to establish or drop; the interface is simply up, and packets either match a peer and get encrypted or they don't and get discarded. People stop asking whether they're connected, because there's nothing to connect.

It roams. A peer's endpoint address is learned from the most recent correctly authenticated packet, so carrying a laptop from office Wi-Fi to LTE moves the tunnel with it, mid-transfer, with no reconnect. IPsec and OpenVPN generally renegotiate.

It is silent. WireGuard never replies to a packet it cannot authenticate. Scan the public address and UDP 51820 gives you nothing — not a rejection, not a closed port, nothing. Compare that to an IKE or OpenVPN daemon that announces itself to anyone who asks.

allowed-address is doing two jobs

This is the field people misconfigure. On the router's peer entry it is a cryptographic access list: a packet arriving through the tunnel from that peer is dropped unless its source address falls inside the listed range. On the client, the same field is the route table — the destinations that get sent into the tunnel.

So allowed-address=10.10.10.5/32 on the router means "this key may only ever be 10.10.10.5." Set it to 0.0.0.0/0 on the server side, as some tutorials do by symmetry with the client config, and you have told the router that this one peer may claim to be any address on the internet. One field, two meanings, and only one of them is obvious from the name.

What it doesn't do, and you have to care

WireGuard authenticates keys, not people. There is no user database, no MFA, no directory integration, no per-user policy and no expiry. A key is valid until you delete the peer. When someone leaves, you remove their peer entry — and if you can't tell which entry is theirs, that's a problem you created months earlier by not filling in the comment field.

That is a real disadvantage against an SSO-backed VPN product, and it's the honest reason not to reach for WireGuard everywhere. For a small business with a handful of people who need in, one key per device with the owner's name on it is completely manageable. For fifty users with turnover, you want a directory behind it, or a management layer on top of it.

It also pushes no settings. There is no mechanism in the protocol to hand a client a DNS server or a search domain; the DNS = line in config files is something the client tooling applies locally, not something the server sends.

The gotcha: it works, then large transfers hang

Here is the failure almost everyone misdiagnoses. The tunnel comes up. Ping works. SSH works. Small pages load fine. Then somebody copies a file or opens a remote desktop session and it freezes solid, forever, with no error.

That's MTU. WireGuard adds 60 bytes of overhead over IPv4 and 80 over IPv6, which is why 1420 is the usual interface MTU — it's the conservative figure that survives both. But if the path underneath is smaller than you assumed, and anything along it is filtering the ICMP "fragmentation needed" messages that would say so, large packets simply disappear while small ones don't. Everything interactive feels healthy; everything bulk stalls.

Set the interface MTU explicitly, then clamp TCP's idea of segment size to whatever the path really is:

/ip firewall mangle
add chain=forward action=change-mss new-mss=clamp-to-pmtu protocol=tcp \
    tcp-flags=syn out-interface=wg-remote

That single rule closes more "the VPN is slow" tickets than anything else I do.

What to do

  1. One key and one tunnel address per device, with the person's name in the comment.
  2. Set allowed-address to a single /32 for each road-warrior peer, and never 0.0.0.0/0 on the router side.
  3. Add persistent-keepalive=25s to peers behind NAT so their mapping stays open.
  4. Clamp MSS on the tunnel before you tell anyone it's ready.
  5. Write down how you revoke a key, and revoke one once to prove the process works.

If remote access currently means a forwarded port and a shared password, that is the thing to fix first.


Need this kind of thinking applied to your own setup? Get in touch →