← Archief / Tutorials

Wireguard site-to-site in 10 minuten

Twee homelabs verbinden via een €5 VPS. Configs, keys, en de firewall-regels die vaak vergeten worden.

Wireguard site-to-site in 10 minuten

WireGuard site-to-site in 10 minuten

Twee homelabs verbinden via een €5 VPS. Configs, keys, en de firewall-regels die vaak vergeten worden.

Je hebt twee locaties: thuis in Gent, en een serverruimte in Brussel. Beide netwerken zitten achter een NAT-router. Direct verbinden kan niet — beide kanten zitten achter een dynamisch IP of dubbele NAT van de provider. De klassieke oplossing is een VPS als centraal knooppunt: een goedkope Hetzner CX22 (vroeger CX11, intussen hernoemd) voor een paar euro per maand fungeert als relay. Beide homelabs dialen in naar de VPS, en via de VPS kunnen ze met elkaar praten.

WireGuard is voor deze topologie ideaal: minimale overhead, simpele configuratiebestanden en een kernel-implementatie die beduidend sneller is dan OpenVPN of IPSec. Het enige wat je nodig hebt zijn keypairs, een publiek IP (de VPS), en een paar iptables-regels die verrassend vaak vergeten worden.

Topologie en keypairs genereren

De opstelling bestaat uit drie nodes:

  • VPS — Hetzner CX22, Debian 12, publiek IP 95.217.x.x, WireGuard-tunnel-IP 10.10.0.1/24
  • Site A — homelab Gent, LAN 192.168.1.0/24, tunnel-IP 10.10.0.2/32
  • Site B — homelab Brussel, LAN 192.168.2.0/24, tunnel-IP 10.10.0.3/32

Genereer voor elke node een keypair. Doe dit op de betreffende node zelf — de private key verlaat de machine nooit.

Elke node apart uitvoeren
# Installeer WireGuard (Debian/Ubuntu)
apt install wireguard -y

# Genereer keypair
wg genkey | tee /etc/wireguard/private.key | wg pubkey > /etc/wireguard/public.key
chmod 600 /etc/wireguard/private.key

# Toon de public key (deel deze met de andere nodes)
cat /etc/wireguard/public.key

Na deze stap heb je drie public keys — één per node. Noteer ze; je hebt ze nodig in de [Peer]-secties van de configs.

VPS-configuratie: de hub

De VPS is de enige node met een publiek IP en speelt de rol van hub. Beide site-peers verbinden naar de VPS; de VPS forwardet verkeer tussen hen.

/etc/wireguard/wg0.conf — VPS
[Interface]
Address    = 10.10.0.1/24
ListenPort = 51820
PrivateKey = <VPS_PRIVATE_KEY>

# IP forwarding inschakelen + NAT voor verkeer tussen peers
PostUp   = sysctl -w net.ipv4.ip_forward=1
PostUp   = iptables -A FORWARD -i wg0 -j ACCEPT
PostUp   = iptables -A FORWARD -o wg0 -j ACCEPT
PostUp   = iptables -t nat -A POSTROUTING -s 10.10.0.0/24 -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT
PostDown = iptables -D FORWARD -o wg0 -j ACCEPT
PostDown = iptables -t nat -D POSTROUTING -s 10.10.0.0/24 -o eth0 -j MASQUERADE

# Site A — homelab Gent
[Peer]
PublicKey           = <SITE_A_PUBLIC_KEY>
AllowedIPs          = 10.10.0.2/32, 192.168.1.0/24
PersistentKeepalive = 25

# Site B — homelab Brussel
[Peer]
PublicKey           = <SITE_B_PUBLIC_KEY>
AllowedIPs          = 10.10.0.3/32, 192.168.2.0/24
PersistentKeepalive = 25

Let op de AllowedIPs: naast het tunnel-IP (/32) staan hier de volledige LAN-subnetten van elke site. WireGuard gebruikt AllowedIPs als routing-tabel én als access control list tegelijk — pakketten met een bronIP buiten deze ranges worden stilletjes weggegooid.

Maak het ip_forward-instelling ook persistent over reboots:

VPS — persistente sysctl
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sysctl -p

Site A en Site B: de spoke-configs

Beide sites zijn spaken in het hub-and-spoke model. Ze verbinden naar de VPS en kennen elkaars subnetten via de AllowedIPs.

/etc/wireguard/wg0.conf — Site A (Gent, gateway 192.168.1.1)
[Interface]
Address    = 10.10.0.2/24
PrivateKey = <SITE_A_PRIVATE_KEY>
MTU        = 1420

# Forwarding zodat LAN-clients via deze gateway door de tunnel kunnen
PostUp   = sysctl -w net.ipv4.ip_forward=1
PostUp   = iptables -A FORWARD -i wg0 -j ACCEPT
PostUp   = iptables -A FORWARD -o wg0 -j ACCEPT
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT
PostDown = iptables -D FORWARD -o wg0 -j ACCEPT

[Peer]
PublicKey           = <VPS_PUBLIC_KEY>
Endpoint            = 95.217.x.x:51820
# Eigen tunnel-IP + subnetten van VPS-tunnel én Site B
AllowedIPs          = 10.10.0.0/24, 192.168.2.0/24
PersistentKeepalive = 25
/etc/wireguard/wg0.conf — Site B (Brussel, gateway 192.168.2.1)
[Interface]
Address    = 10.10.0.3/24
PrivateKey = <SITE_B_PRIVATE_KEY>
MTU        = 1420

PostUp   = sysctl -w net.ipv4.ip_forward=1
PostUp   = iptables -A FORWARD -i wg0 -j ACCEPT
PostUp   = iptables -A FORWARD -o wg0 -j ACCEPT
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT
PostDown = iptables -D FORWARD -o wg0 -j ACCEPT

[Peer]
PublicKey           = <VPS_PUBLIC_KEY>
Endpoint            = 95.217.x.x:51820
AllowedIPs          = 10.10.0.0/24, 192.168.1.0/24
PersistentKeepalive = 25

Op Site A en Site B heb je geen MASQUERADE nodig op de WireGuard-interface zelf — de VPS doet de NAT voor naar buiten gaand verkeer. Wat je wel nodig hebt, is een route op je LAN-clients of op de router. Als de gateway van het lokale netwerk dezelfde machine is als je WireGuard-node, volstaat IP forwarding. Als de gateway een aparte router is (bv. een Mikrotik of je ISP-modem), voeg je een statische route toe:

Statische route op de LAN-router (voorbeeld Mikrotik)
# Op de router van Site A: stuur 192.168.2.0/24 naar de WireGuard-gateway
/ip route add dst-address=192.168.2.0/24 gateway=192.168.1.10

# Op de router van Site B: stuur 192.168.1.0/24 naar de WireGuard-gateway
/ip route add dst-address=192.168.1.0/24 gateway=192.168.2.10

"AllowedIPs is tegelijk een routing-tabel én een access control list — een dubbele rol die de meeste problemen verklaart bij site-to-site setups."

Routing en de firewall-regels die vaak vergeten worden

De drie meest vergeten stappen bij een site-to-site WireGuard setup:

1. FORWARD-chain staat standaard op DROP

Op een verse Debian-installatie staat de iptables FORWARD-chain op ACCEPT, maar veel VPS-providers leveren images met een geharde firewall waarbij FORWARD op DROP staat. Controleer dit:

Controleer de FORWARD-policy
iptables -L FORWARD -n -v

# Als de policy DROP is en de PostUp-regels nog niet actief zijn:
iptables -P FORWARD ACCEPT   # tijdelijk, of laat PostUp het afhandelen

2. UDP 51820 open op de VPS-firewall

Hetzner Cloud heeft naast iptables ook een externe firewall in de console. Zorg dat UDP 51820 open staat, anders bereiken de site-peers de VPS nooit:

VPS — iptables (of Hetzner Cloud Firewall via console)
iptables -A INPUT -p udp --dport 51820 -j ACCEPT
# Persistent maken:
apt install iptables-persistent -y
netfilter-persistent save

3. MTU — de stille verbindingskiller

WireGuard gebruikt standaard MTU 1420. Dat is al conservatiever dan Ethernet's 1500, maar over bepaalde provider-netwerken (PPPoE, dubbele encapsulatie) kan het nog steeds te groot zijn. Het verraderlijke symptoom: ping werkt prima, maar grote TCP-sessies (SSH-commando's, bestandsoverdracht) hangen of vallen weg.

MTU-rekenregel
Underlying transportAanbevolen WireGuard MTU
Standaard Ethernet (1500)1420
PPPoE (1492)1412
WireGuard-over-WireGuard1340

WireGuard voegt 60 bytes overhead toe (20 IP + 8 UDP + 32 WireGuard header). Bij twijfel: zet MTU expliciet in de [Interface]-sectie op 1420 en test met:

MTU diagnostiek
# Stuur een ICMP-pakket van exacte grootte (DF-bit aan)
ping -M do -s 1392 10.10.0.1   # 1392 + 28 bytes ICMP-header = 1420 totaal

# Als dit faalt maar kleiner slagen: verlaag MTU in de config
# en herstart: systemctl restart wg-quick@wg0

Tunnel opstarten en testen

Start de interfaces op alle drie nodes, begin bij de VPS:

Opstarten + autostart inschakelen
# Op elke node
wg-quick up wg0
systemctl enable wg-quick@wg0

# Status bekijken
wg show

# Ping vanuit Site A naar Site B
ping 192.168.2.1

# Ping vanuit Site B naar een host in Site A
ping 192.168.1.100

In de uitvoer van wg show zie je per peer wanneer het laatste handshake plaatsvond en hoeveel bytes er over de tunnel gingen. Als latest handshake leeg blijft, bereikt de peer de VPS niet — controleer UDP 51820 en de publieke key in de [Peer]-sectie.

Snelle troubleshooting-checklist
  • Geen handshake → UDP 51820 geblokkeerd op VPS-firewall of foute Endpoint-waarde
  • Handshake OK, geen ping → IP forwarding niet actief (sysctl net.ipv4.ip_forward) of FORWARD-chain op DROP
  • Ping naar tunnel-IP werkt, LAN niet → Statische routes op de LAN-router ontbreken, of AllowedIPs mist het subnet
  • Grote bestanden falen → MTU te hoog, verlaag naar 1380 en test opnieuw
  • Verbinding valt weg na minuten → PersistentKeepalive = 25 ontbreekt op de NAT-kant

Veelgestelde vragen

Kan ik direct peer-to-peer verbinden zonder VPS als beide sites achter NAT zitten?

In theorie wel via UDP hole punching, maar in de praktijk werkt dat niet betrouwbaar bij carrier-grade NAT (CG-NAT) of strenge firewall-configuraties. Een VPS als relay is voor homelabs verreweg de meest stabiele aanpak en kost bij Hetzner minder dan een kopje koffie per maand.

Waarom PersistentKeepalive = 25 en niet een andere waarde?

25 seconden is de gangbare default omdat de meeste NAT-routers UDP-sessies na 30 seconden inactiviteit sluiten. Door elke 25 seconden een klein pakketje te sturen houdt de spoke de NAT-mapping open. Op de VPS zelf is keepalive niet nodig — die heeft een publiek IP.

Is het veilig om de private key in een platte tekstfile te bewaren?

De permissies (chmod 600) en het feit dat root-toegang vereist is zijn de minimale bescherming. Voor hogere zekerheid kun je de key opslaan in systemd-credentials of een secrets manager zoals HashiCorp Vault. Voor een homelab-setup is chmod 600 doorgaans acceptabel.

Werkt dit ook met IPv6?

Ja — voeg een IPv6-adres toe aan Address (bv. fd10::/64), zet net.ipv6.conf.all.forwarding = 1 in sysctl en pas de iptables/ip6tables-regels aan. De logica is identiek aan IPv4.

Wat als de VPS crasht — valt alles weg?

Ja, in een hub-and-spoke topologie is de VPS een single point of failure voor het inter-site verkeer. Wil je redundantie, dan configureer je twee VPS-peers per site met een lagere PersistentKeepalive en een failover-route. Voor de meeste homelabs is de uptime van een Hetzner-instantie (doorgaans >99,9%) meer dan voldoende.

Verder lezen

Uit de categorie Tutorials
ESC
Recent geopend