Skip to content

$ cat ./posts/network/wireguard-as-a-routed-mesh.conf

-rw-r--r-- 1.6K #network #security

WireGuard as a routed mesh

by chris · 2 min read · /network


WireGuard has no concept of a connection. It has peers, public keys and allowed IPs, and that last field does double duty as both an access control list and a routing table. Understanding that one detail is most of what it takes to design a working mesh.

1. One interface, many peers

# /etc/wireguard/wg0.conf
[Interface]
Address = 10.10.0.1/24
ListenPort = 51820
PrivateKey = <server key>

[Peer]
# laptop
PublicKey = <laptop pubkey>
AllowedIPs = 10.10.0.2/32

[Peer]
# branch office router
PublicKey = <router pubkey>
AllowedIPs = 10.10.0.3/32, 192.168.50.0/24

The second peer advertises a whole subnet behind it. Traffic for 192.168.50.0/24 is encrypted to that peer and decrypted only if it arrives signed by that key — routing and authorisation in one line.

2. Turn on forwarding, then stop

sysctl -w net.ipv4.ip_forward=1
sysctl -w net.ipv6.conf.all.forwarding=1

No NAT is needed between sites that both have real subnets. Adding masquerade because a tutorial said so is what turns a debuggable network into one where every packet capture shows the wrong source address.

3. Keepalives are for NAT, not for health

PersistentKeepalive = 25

Set it on peers behind NAT so the mapping stays open. Setting it everywhere just adds traffic. To check a tunnel, read the handshake age:

sudo wg show wg0 latest-handshakes

Anything older than three minutes on an active peer means the path is broken, whatever the interface state claims.

← cd .. fris@linux:~/blog$ man network