WireGuard VPN op eigen VPS installeren: handleiding
Bouw uw eigen WireGuard VPN op Linux. Deze gids behandelt de wg0.conf configuratie, IP forwarding, NAT-regels en het oplossen van veelvoorkomende handshake-fouten.
Wat u bouwt
Een WireGuard VPN op een server in eigen beheer bestaat uit ongeveer veertig regels configuratie: één sleutelpaar, één interfacebestand, één sysctl-instelling, één NAT-regel en één firewall-poort. De installatie is triviaal, dus het grootste deel van deze handleiding behandelt mogelijke problemen, sleutelrechten, AllowedIPs, forwarding en DNS.
WireGuard is een Layer 3-tunnel in de kernel en is sinds Linux 5.6 onderdeel van de mainline. Ubuntu 24.04 en Debian 13 leveren het daarom zonder externe modules. Er is geen cipher-onderhandeling, geen certificaatautoriteit en geen gebruikersnaam/wachtwoord-stap: een peer is een publieke sleutel plus de IP-adressen die deze sleutel mag gebruiken. Een pakket dat de MAC-controle niet doorstaat, wordt genegeerd zonder antwoord, waardoor de poort niet reageert op scans. De keerzijde hiervan is dat er geen authenticatieserver bestaat; het intrekken van toegang betekent dus dat u een peer op de server moet verwijderen.
Controleer eerst de virtualisatie
WireGuard vereist een kernel waarin een module kan worden geladen; op een KVM VPS werkt dit direct. Bij containervirtualisatie die de host-kernel deelt, zoals OpenVZ of LXC, mislukt het eerste commando met RTNETLINK answers: Operation not supported en is de fallback de wireguard-go userspace-implementatie. Controleer dit eerst met sudo modprobe wireguard && echo ok.
Sleutels genereren zonder dat deze uitlekken
Een /etc/wireguard/server.key die voor iedereen leesbaar is, staat gelijk aan het ontbreken van een VPN. De gebruikelijke umask 077 && wg genkey | sudo tee ...-regel werkt: tenzij sudoers umask_override instelt, wat standaard uitgeschakeld is, combineert sudo uw umask met de standaardwaarde 0022 en verlaagt deze nooit. Hierdoor krijgt het bestand dat tee aanmaakt de modus 600. Sleutels lekken wanneer u die pipe uitvoert zonder de umask 077, onder een standaard 022 umask, of op een systeem waar sudoers umask_override inschakelt. Stel de modus expliciet in en dan maakt het niet meer uit.
sudo apt update && sudo apt install -y wireguard nftables
sudo install -d -m 700 /etc/wireguard
sudo sh -c 'umask 077; wg genkey > /etc/wireguard/server.key'
sudo sh -c 'wg pubkey < /etc/wireguard/server.key > /etc/wireguard/server.pub'
sudo chmod 600 /etc/wireguard/server.keyGenereer het client-paar op dezelfde manier. wg genpsk voegt een optionele pre-shared key toe, één regel in elke configuratie.
De serverinterface: /etc/wireguard/wg0.conf
[Interface]
Address = 10.8.0.1/24
ListenPort = 51820
PrivateKey = <contents of /etc/wireguard/server.key>
[Peer]
PublicKey = <laptop public key>
PresharedKey = <psk, optional>
AllowedIPs = 10.8.0.2/32chmod 600 het; een waarschuwing bij het opstarten dat het bestand voor iedereen toegankelijk is, betekent dat u die stap heeft overgeslagen. Address is het adres van de server binnen de tunnel, inclusief het masker van het volledige VPN-subnet. Kies een bereik dat u in de praktijk niet zult tegenkomen; 192.168.1.0/24 botst met de helft van de thuisrouters waar uw clients achter zitten, waardoor de tunnel ongemerkt verkeer verliest aan de lokale route.
De AllowedIPs van een peer aan de serverzijde is een /32, het specifieke tunneladres dat de client bezit. Als u twee peers hetzelfde AllowedIP geeft, wordt het verkeer verplaatst naar degene die als laatste is geconfigureerd, terwijl de eerste zonder foutmelding stopt met het ontvangen van verkeer. Laat SaveConfig oningesteld, anders overschrijft wg-quick down dit bestand op basis van de actuele status.
Maak van de server een router
Een Linux-server negeert pakketten die niet aan het eigen adres zijn gericht. IP-forwarding en source NAT zijn standaard uitgeschakeld.
printf 'net.ipv4.ip_forward = 1\nnet.ipv6.conf.all.forwarding = 1\n' \
| sudo tee /etc/sysctl.d/99-wireguard.conf
sudo sysctl --system
sysctl net.ipv4.ip_forwardEen kale sysctl -w werkt tot de volgende herstart en stopt daarna zonder melding. NAT vereist de egress-interface, de netwerkkaart die verbinding maakt met het internet, niet wg0. Ga niet uit van eth0; bepaal uw eigen interface via ip route show default, aangezien huidige images namen gebruiken zoals enp1s0 of ens3.
Firewall: de poort en het doorstuurpad
Eén nftables-bestand dekt zowel filter als NAT. Schrijf /etc/nftables.conf; dit leegt de bestaande regelset, dus sla dit over op een server die al door ufw of Docker wordt beheerd.
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority filter; policy drop;
ct state established,related accept
iif lo accept
tcp dport 22 accept
udp dport 51820 accept
}
chain forward {
type filter hook forward priority filter; policy drop;
ct state established,related accept
iifname "wg0" oifname "enp1s0" accept
}
}
table ip nat {
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 10.8.0.0/24 oifname "enp1s0" masquerade
}
}Pas het toe met sudo systemctl enable --now nftables en houd een tweede SSH-sessie open: policy drop in combinatie met een typefout in de SSH-regel sluit u buiten van uw eigen server. Let op wat de forward-chain niet toestaat, wg0 tot wg0. Peers bereiken het internet, maar niet elkaar; voeg iifname "wg0" oifname "wg0" accept toe voor een peer-to-peer VPN. Wat een peer op de server zelf mag benaderen, is niet de taak van deze chain: pakketten die aan de server zijn gericht, passeren de input-hook, nooit de forward-hook. De input-chain beslist dus, en zoals geschreven staat, laat deze een peer alleen SSH bereiken en niets anders, zelfs geen ping naar 10.8.0.1. Voeg daar iifname "wg0" icmp type echo-request accept toe, plus één iifname "wg0"-regel per service die u alleen via de tunnel bereikbaar wilt maken. Dit is van belang wanneer de server ook fungeert als een remote development box die Claude Code in tmux draait en u die kant liever niet publiekelijk blootstelt.
Op een ufw-server: ufw allow 51820/udp, DEFAULT_FORWARD_POLICY="ACCEPT" in /etc/default/ufw, en een *nat POSTROUTING MASQUERADE-regel bovenaan /etc/ufw/before.rules.
Activeer het onder systemd
sudo systemctl enable --now wg-quick@wg0
sudo wg showwg-quick maakt de interface aan, voegt de adressen toe en installeert routes die zijn afgeleid van AllowedIPs. enable --now is het essentiële onderdeel: een handmatig uitgevoerde wg-quick up wg0 verdwijnt na de volgende herstart, en kernel-upgrades vereisen herstarts. Een unit die na zo'n herstart niet automatisch opstart, blijft inactief totdat iemand probeert verbinding te maken. Daarom is een OnFailure= drop-in op wg-quick@wg0, gericht op uw eigen ntfy server, de goedkoopste manier om hierover op uw telefoon bericht te ontvangen in plaats van via een buitengesloten gebruiker.
De clientconfiguratie en de instelling die iedereen verkeerd begrijpt
[Interface]
PrivateKey = <laptop private key>
Address = 10.8.0.2/32
DNS = 10.8.0.1
[Peer]
PublicKey = <server public key>
Endpoint = vpn.example.com:51820
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25AllowedIPs vervult twee verschillende taken tegelijkertijd, en het verwarren van deze twee is de bron van de meeste onduidelijkheid over WireGuard.
Uitgaand fungeert het als een routeringstabel. Een pakket waarvan de bestemming overeenkomt met de AllowedIPs van een peer, wordt versleuteld en naar die peer verzonden. 0.0.0.0/0, ::/0 stuurt alles door de tunnel, een volledige tunnel, waarbij de server als standaardroute fungeert. Een split-tunnel is een beperktere lijst: AllowedIPs = 10.8.0.0/24, 10.20.0.0/16 transporteert VPN-verkeer plus één privénetwerk achter de server, terwijl al het overige verkeer de lokale route behoudt. Die beperkte lijst stelt u in staat om services volledig buiten het publieke internet te houden, zoals een private Nextcloud-instantie op een VPS die gebonden is aan het tunneladres, of de nested-virtualization lab-VM's die op dezelfde machine draaien, bereikbaar blijven voor peers en onzichtbaar voor iedereen anders.
Inkomend fungeert het als een toegangscontrolelijst (ACL). Een ontsleuteld pakket van een peer waarvan het bronadres niet voorkomt in de AllowedIPs van die peer, wordt geweigerd. Daarom specificeert de server 10.8.0.2/32 voor de laptop: een vermelding van 0.0.0.0/0 daar zou de client in staat stellen om elk adres in de tunnel te spoofen.
PersistentKeepalive is bedoeld voor clients achter NAT, waarbij de router de UDP-mapping alleen openhoudt zolang er pakketten worden verstuurd. Wanneer deze verloopt, kan de server de client niet langer bereiken. PersistentKeepalive = 25 houdt de mapping open; stel dit in op de client, niet op een server met een publiek IP-adres.
DNS, en het lek dat niemand opmerkt
Met AllowedIPs = 0.0.0.0/0 en geen DNS =-regel behoudt de client de resolver die hij van het lokale netwerk heeft geleerd, de café-router op 192.168.1.1. Die route is specifieker dan de standaardroute, waardoor DNS-query's via de lokale verbinding in leesbare tekst (cleartext) worden verzonden, terwijl al het overige verkeer wordt getunneld. Het verkeer is privé; de lijst met namen niet.
Er zijn twee eerlijke opties. Wijs DNS naar een publieke resolver (DNS = 9.9.9.9) en de query's reizen door de tunnel en verlaten deze via uw server, al ziet die resolver ze nog steeds. Of draai unbound of dnsmasq gebonden aan 10.8.0.1, stel DNS = 10.8.0.1 in, voeg udp dport 53 iifname "wg0" accept toe aan de input-chain, stel die regel in en vergeet de resolver, waarna niets meer wordt omgezet.
Op Linux-clients past wg-quick de DNS toe via resolvconf; als deze ontbreekt, krijgt u resolvconf: command not found. Installeer openresolv, of stel PostUp = resolvectl dns %i 10.8.0.1 in op een systemd-resolved client.
Peers toevoegen en verwijderen zonder de tunnel te verbreken
Het herstarten van de interface verbreekt de verbinding voor alle actieve gebruikers. Voeg het [Peer]-blok toe aan wg0.conf en laad vervolgens de peer-set opnieuw in zonder de verbinding te verbreken.
sudo bash -c 'wg syncconf wg0 <(wg-quick strip wg0)'wg-quick strip toont de configuratie zonder de wg-quick-specifieke sleutels (Address, DNS, PostUp), en syncconf past de wijzigingen toe terwijl actieve sessies behouden blijven. Dit werkt alleen voor peers: een gewijzigde Address vereist nog steeds een volledige down/up-cyclus. Trek de toegang in met sudo wg set wg0 peer <public key> remove en verwijder daarna het blok uit het bestand, anders keert de configuratie terug bij de volgende herlaadactie.
Foutmodi en bijbehorende meldingen
Handshake wordt nooit voltooid. wg show toont de peer zonder latest handshake, en de client logt:
Handshake for peer 1 (10.0.0.10:51820) did not complete after 5 seconds, retrying (try 2)Er komt niets aan, of er wordt niets geaccepteerd. Controleer in deze volgorde: staat UDP 51820 open op de firewall van de VPS en op de netwerkfirewall van uw provider (een aparte instelling in de meeste beheerpanelen); zijn het Endpoint-adres en de poort correct; zijn de keys verwisseld. De key in het [Peer]-blok van de client moet de public key van de server zijn, en vice versa. Het invullen van een private key of de eigen public key van de client resulteert precies in dit symptoom. sudo tcpdump -ni any udp port 51820 op de server toont of er überhaupt pakketten aankomen. De kernelmodule logt standaard niets; WireGuard-berichten verschijnen pas in dmesg nadat u dynamic debug (echo module wireguard +p | sudo tee /sys/kernel/debug/dynamic_debug/control) inschakelt. Met deze optie aan, wordt een key-mismatch zichtbaar als een invalid-MAC drop.
Handshake werkt, geen internet. ping 10.8.0.1 slaagt, maar ping 1.1.1.1 geeft een timeout: forwarding of NAT ontbreekt. Controleer of sysctl net.ipv4.ip_forward op 1 staat en bekijk de tellers terwijl de client pingt, met sudo nft list ruleset of sudo iptables -t nat -L POSTROUTING -n -v. Nul pakketten op de masquerade-regel betekent dat de naam van de egress-interface onjuist is; een oplopende teller zonder antwoorden wijst op het beleid van de forward-chain.
Internet werkt, namen niet. ping 1.1.1.1 slaagt en curl https://example.com geeft Could not resolve host terug. De DNS-regel ontbreekt, of deze verwijst naar een resolver die onbereikbaar is vanuit de tunnel.
Sommige HTTPS-sites blijven hangen. SSH en ping werken, maar grote pagina's laden niet. Dit is een path MTU-probleem: de tunnel voegt overhead toe en een tussenliggende verbinding verwijdert de te grote pakketten zonder dat er een ICMP-bericht terugkomt. Stel MTU in op de [Interface] van de client. Op een standaard 1500-byte verbinding kiest wg-quick al 1420 (1500 minus de 80 bytes overhead), dus 1420 invullen verandert niets: probeer 1380, en daarna 1280. Als het verlagen van de MTU de problemen oplost maar de doorvoer tegenvalt, stop dan met gokken en volg het bepalen van de werkelijke path MTU via bisection en TCP MSS-clamping, wat ook oorzaken uitsluit die niets met de tunnel te maken hebben.
Interface weigert te starten. Address already in use betekent dat een ander proces UDP 51820 bezet houdt. Cannot find device wg0 na een mislukte up betekent meestal dat de configuratie is afgewezen; lees journalctl -u wg-quick@wg0 -n 50.
Migreren van Streisand of OpenVPN
Streisand wordt niet langer onderhouden en het repository is gearchiveerd. Het draaien van een VPN op verouderde automatisering vormt een sluimerend beveiligingsrisico. Er is geen mogelijkheid voor een in-place upgrade en de PKI van OpenVPN is niet converteerbaar: WireGuard gebruikt geen certificaten, heeft geen CA en kent geen verloopdata, waardoor elk client-apparaat een nieuw sleutelpaar krijgt.
Migreer parallel; WireGuard op UDP 51820 kan naast OpenVPN op 1194 op dezelfde server draaien. Zet wg0 op, verplaats clients één voor één en stop daarna de oude service. Het gebruikersnaam/wachtwoord-model en de revocatie-methode van OpenVPN zijn niet overdraagbaar; als u accounts of een audit-trail nodig heeft, dient u dit bovenop WireGuard te implementeren.
Back-ups, upgrades en schaalbaarheid
/etc/wireguard is de server. Maak er een back-up van (sudo tar czf wg-backup.tgz -C /etc wireguard, modus 600, bewaard buiten de server) en u kunt binnen enkele minuten herbouwen op een nieuwe VPS. Verliest u de private key van de server, dan moet elke clientconfiguratie opnieuw worden uitgegeven, aangezien clients de public key van de server pinnen. Upgrades zijn een standaard apt upgrade plus een herstart voor kernel-updates, en wg-quick@wg0 keert vanzelf terug als u dit heeft ingeschakeld.
De status per peer is klein en de cryptografie draait in de kernel, dus de beperking is de CPU en bandbreedte van uw VPS in plaats van deze configuratie. Meet dit met iperf3 over de tunnel in plaats van te vertrouwen op gepubliceerde cijfers. Wat bij schaalvergroting voor problemen zorgt, is het beheer. Elke peer heeft een uniek tunnel-IP nodig, en het handmatig bewerken van zestig [Peer]-blokken is hoe dubbele AllowedIPs-adressen binnensluipen: genereer de configuraties met een script. Eén server is één UDP-eindpunt en één single point of failure, en WireGuard heeft geen clustering: redundantie betekent een tweede server met eigen keys. Key-rotatie blijft handmatig, dus noteer wie welke key bezit en hoe u er een intrekt. Zodra die administratie uit een tekstbestand groeit, is het gebruikelijke antwoord een control plane bovenop hetzelfde kernel-dataplane, en een zelfgehoste NetBird-server regelt de adresallocatie, peer-distributie en setup-keys die u anders handmatig zou doen. Als het zelf draaien van die control plane één server te veel is, host Tailscale er een voor u, en het gratis Personal-abonnement dekt zes gebruikers met onbeperkte apparaten en, om te beginnen, maximaal 50 getagde resources zoals servers, genoeg voor de meeste persoonlijke vloten. Voorbij dat punt betaalt u voor mensen in plaats van machines, dus wat een huishouden of klein team daadwerkelijk betaalt hangt af van hoeveel mensen logins hebben, niet van hoeveel peers u handmatig in wg0.conf had ingevoerd. Aan die kant wordt de split-tunnel AllowedIPs-administratie het adverteren van uw privébereiken vanaf een subnet-router, eenmalig aangekondigd vanaf één VPS en centraal goedgekeurd in plaats van in elk clientbestand geplakt. Of die afweging de moeite waard is, hangt af van wat een gehoste control plane daadwerkelijk kan bereiken, en het bezit nooit de keys die uw verkeer versleutelen, hoewel het wel beslist welke peers van elkaar op de hoogte worden gesteld.
Dit alles vereist een Linux-server die u beheert, een publiek IP, een kernel waarin u een module kunt laden en een firewall die u volledig in eigen beheer heeft.
FAQ
Waarom voltooit de WireGuard-handshake nooit?
wg show het vermelden van een peer zonder latest handshake betekent dat pakketten niet aankomen of niet worden geaccepteerd. Controleer UDP 51820 op zowel de VPS-firewall als de afzonderlijke netwerkfirewall van uw provider, bevestig de Endpoint host en poort, en controleer vervolgens of de sleutels niet zijn verwisseld; het [Peer] blok van de client moet de publieke sleutel van de server bevatten. sudo tcpdump -ni any udp port 51820 op de server toont of er überhaupt pakketten aankomen; dmesg rapporteert alleen WireGuard-handshakefouten nadat u dynamische debug (echo module wireguard +p | sudo tee /sys/kernel/debug/dynamic_debug/control) heeft ingeschakeld, waarna een sleutel-mismatch verschijnt als een invalid-MAC drop.
De tunnel maakt verbinding, maar ik heb geen internet. Wat ontbreekt er?
Als ping 10.8.0.1 werkt terwijl ping 1.1.1.1 een time-out geeft, wijst dit op forwarding of NAT. Bevestig dat sysctl net.ipv4.ip_forward de waarde 1 bevat en dat dit is ingesteld in /etc/sysctl.d/, en niet alleen met een sysctl -w die na een reboot verdwijnt. Controleer vervolgens of de masquerade-regel uw werkelijke uitgaande interface gebruikt vanuit ip route show default, enp1s0 of ens3, zelden eth0.
Heb ik de DNS = regel nodig in mijn clientconfiguratie?
Bij een volledige tunnel zonder DNS = regel behoudt de client de resolver die hij van het lokale netwerk heeft geleerd, en die queries verlaten het netwerk in cleartext via de lokale verbinding terwijl al het andere verkeer door de tunnel gaat. Wijs DNS naar een publieke resolver, of draai unbound/dnsmasq gebonden aan 10.8.0.1 en open udp dport 53 iifname "wg0" in de input chain.
Wat regelt AllowedIPs precies?
Het voert twee taken uit. Uitgaand is het een routeringstabel: verkeer dat overeenkomt met de AllowedIPs van een peer wordt versleuteld en naar die peer verzonden. Inkomend is het een toegangscontrolelijst: een ontsleuteld pakket waarvan de bron buiten de AllowedIPs van die peer valt, wordt geweigerd. Daarom vermeldt de serverzijde één /32 per client, terwijl de clientzijde 0.0.0.0/0 kan vermelden.
Werkt WireGuard op elke VPS?
Op een KVM VPS werkt het met de in-kernel module zonder extra configuratie. Bij containervirtualisatie die de host-kernel deelt, zoals OpenVZ of LXC, faalt modprobe wireguard met Operation not supported en is de fallback de wireguard-go userspace-implementatie. Voer sudo modprobe wireguard && echo ok uit voordat u iets anders doet.