NoctisNode
← HandleidingenNetwerken2026-10-239 min

Een privé-VPS-cluster bouwen met een WireGuard-mesh

Verbind VPS-nodes tot een privécluster met een volledige WireGuard-mesh: één adresplan, één [Peer] per node, /32 in AllowedIPs, een strikte firewall en diensten gebonden aan wg0.

Kort gezegd: om meerdere VPS'en tot een privécluster te maken, geef je elke VPS-node een WireGuard-interface met een adres uit één privésubnet, voeg je elke andere node toe als `[Peer]` met zijn publieke `Endpoint` en een `/32` in `AllowedIPs`, sta je UDP 51820 alleen toe vanaf je eigen nodes en bind je databases en interne diensten aan het `wg0`-adres in plaats van het publieke IP. Tot ongeveer tien nodes is dit met de hand of met een sjabloon makkelijk te onderhouden; daarboven gebruik je tooling die de configs genereert en verspreidt.

Deze gids gaat ervan uit dat je de basis al kent uit de handleiding voor een WireGuard-VPN en SSH op elke node hebt gehard zoals in de handleiding voor SSH-hardening; om nodes via een bastion te bereiken zonder agent forwarding, zie de handleiding over StrictModes en agent forwarding.

Adresplan voor de VPN-nodes

Kies één privébereik dat met niets anders botst wat je gebruikt (LAN thuis, Docker, pod-ranges van Kubernetes). Een `/24` volstaat voor een klein cluster en houdt adressen leesbaar. Geef elke node een vast adres en bewaar het plan in versiebeheer, want elke config wordt ervan afgeleid.

NodeRolPubliek IPwg0-adresListenPort
node1app203.0.113.1110.88.0.1/2451820
node2app203.0.113.1210.88.0.2/2451820
node3database203.0.113.1310.88.0.3/2451820
node4monitoring203.0.113.1410.88.0.4/2451820

Config per peer op elke VPS-node

In een volledige mesh praat elke node rechtstreeks met elke andere node, dus elke config heeft één `[Interface]` en N-1 `[Peer]`-secties. Vier nodes betekent in totaal zes tunnels; tien nodes betekent er 45. Elke node heeft een publiek IP, dus `PersistentKeepalive` is meestal niet nodig; de details staan in de handleiding over keepalive en PresharedKey.

  1. 01.Voer op elke node `apt install wireguard` uit, en daarna `umask 077; wg genkey | tee /etc/wireguard/wg0.key | wg pubkey > /etc/wireguard/wg0.pub`.
  2. 02.Verzamel alle publieke sleutels en het adresplan op één plek.
  3. 03.Genereer eventueel één `wg genpsk`-sleutel per nodepaar als post-quantum-buffer.
  4. 04.Schrijf `/etc/wireguard/wg0.conf` op elke node zoals hieronder.
  5. 05.Voer `systemctl enable --now wg-quick@wg0` uit en controleer met `wg show` of er met elke peer een recente handshake is.
# /etc/wireguard/wg0.conf on node1
[Interface]
Address = 10.88.0.1/24
ListenPort = 51820
PrivateKey = <node1 private key>

[Peer]
# node2
PublicKey = <node2 public key>
Endpoint = 203.0.113.12:51820
AllowedIPs = 10.88.0.2/32

[Peer]
# node3
PublicKey = <node3 public key>
Endpoint = 203.0.113.13:51820
AllowedIPs = 10.88.0.3/32

[Peer]
# node4
PublicKey = <node4 public key>
Endpoint = 203.0.113.14:51820
AllowedIPs = 10.88.0.4/32

Hoe AllowedIPs werkt in een mesh

`AllowedIPs` doet twee dingen tegelijk. Uitgaand is het een routeringstabel: pakketten voor `10.88.0.3` gaan naar de peer die `10.88.0.3/32` vermeldt. Inkomend is het een toegangslijst: een pakket van die peer wordt alleen geaccepteerd als het bronadres binnen de `AllowedIPs` van die peer valt. Daarom krijgt elke peer precies zijn eigen `/32`, niet de hele `/24`.

De `/24` op de regel `Address` maakt alleen de kernelroute voor het subnet op `wg0` aan; WireGuard kiest daarna per bestemming de juiste peer.

  • ▹Twee peers mogen op dezelfde interface nooit een overlappend `AllowedIPs`-bereik delen; de laatste wint.
  • ▹Routeert een node ook een privésubnet (bijvoorbeeld Docker op node3), voeg dat subnet dan op de andere nodes toe aan de `AllowedIPs` van node3.
  • ▹Zet geen `0.0.0.0/0` in een mesh-peer, tenzij je echt wilt dat al het verkeer via die node naar buiten gaat.

Firewall: alleen je eigen nodes bereiken de tunnel

WireGuard antwoordt niet op niet-geauthenticeerde pakketten, maar UDP 51820 beperken tot bekende node-IP's vermindert toch ruis. Open binnen de tunnel alleen de poorten die elke dienst nodig heeft. Dit nftables-voorbeeld voor Debian 12/13 en Ubuntu 24.04 hoort in `/etc/nftables.conf`; laad het met `nft -f /etc/nftables.conf` en schakel `nftables.service` in. Houd tijdens het testen een SSH-sessie open.

table inet filter {
  set mesh_peers {
    type ipv4_addr
    elements = { 203.0.113.11, 203.0.113.12, 203.0.113.13, 203.0.113.14 }
  }
  chain input {
    type filter hook input priority 0; policy drop;
    ct state established,related accept
    iif lo accept
    meta l4proto { icmp, ipv6-icmp } accept
    tcp dport 22 accept
    udp dport 51820 ip saddr @mesh_peers accept
    iifname "wg0" ip saddr 10.88.0.0/24 tcp dport { 5432, 6379, 9100 } accept
  }
}

Diensten aan de wg-interface binden

Een firewall is één laag; de tweede is helemaal niet op het publieke adres luisteren. Bind interne diensten aan het `wg0`-adres van de node, zodat een fout in de firewall ze niet blootstelt. Omdat `wg0` moet bestaan voordat de dienst bindt, orden je de units met een systemd-drop-in, of sta je binden aan adressen die nog niet actief zijn toe met `net.ipv4.ip_nonlocal_bind = 1`.

# PostgreSQL on node3: postgresql.conf
listen_addresses = '10.88.0.3'
# pg_hba.conf
host  all  all  10.88.0.0/24  scram-sha-256

# Redis: /etc/redis/redis.conf
bind 10.88.0.3

# systemctl edit postgresql  (repeat for other services)
[Unit]
[email protected]
[email protected]

Note · Controleer het resultaat met `ss -tlnp`: interne diensten horen `10.88.0.x` te tonen, nooit `0.0.0.0` of het publieke IP.

Opschalen: wanneer je overstapt op tooling

Een met de hand geschreven mesh is prima zolang het aantal nodes klein is en wijzigingen zeldzaam zijn. Elke nieuwe node betekent dat je elke bestaande config moet bewerken, dus het werk groeit kwadratisch. Wordt dat een karwei, genereer de configs dan in plaats van ze te schrijven.

Bij NoctisNode worden alle nieuwe VPS-nodes uitgerold in FI-1 (Finland), elk met een dedicated IPv4 en een onbeperkte poort van 1 Gbps, en door de facturering per uur plus de agent-API (met een TTL voor automatisch verwijderen) is het goedkoop om testnodes toe te voegen en weg te halen. Pakketten beginnen bij Wisp; zie de VPS-pakketten.

ClustergrootteAanpak
2–5 nodesMet de hand geschreven configs, adresplan in een tekstbestand
5–15 nodesAnsible of een andere configuratietool die wg0.conf uit één inventory genereert
15+ nodes of veel wisselingenEen mesh-manager die sleutels en peers automatisch verspreidt, of een hub-and-spoke-ontwerp

Veelgestelde vragen

QHoe verbind ik meerdere VPS'en tot een privénetwerk?

AInstalleer WireGuard op elke VPS, geef elke node een adres uit één privésubnet en vermeld elke andere node als peer met zijn publieke endpoint en een /32 in AllowedIPs. Bind daarna interne diensten aan het WireGuard-adres.

QHebben VPN-nodes in een WireGuard-mesh PersistentKeepalive nodig?

AMeestal niet, omdat elke VPS-node een publiek IP heeft en direct bereikbaar is. Voeg `PersistentKeepalive = 25` alleen toe voor een node die achter NAT zit.

QWat moet AllowedIPs zijn voor elke VPS-node?

AElke peer krijgt alleen zijn eigen WireGuard-adres als /32, plus elk subnet dat die node routeert. Het hele clustersubnet voor elke peer gebruiken veroorzaakt overlappende routes en breekt de mesh.

QHoeveel nodes kan een WireGuard-mesh hebben?

AWireGuard zelf kan veel peers aan, maar een met de hand onderhouden volledige mesh wordt na ongeveer tien nodes omslachtig, omdat elke node de config van elke andere node nodig heeft. Daarboven genereer je de configs met automatisering of gebruik je een mesh-manager.

Een privé-VPS-cluster bouwen met een WireGuard-mesh · NoctisNode