SSD Nodes Learn
Anleitungen Matt ConnorVon Matt Connor · Aktualisiert 2026-07-24

WireGuard auf Linux VPS selbst hosten

Lernen Sie die Konfiguration von wg0.conf, IP Forwarding und NAT. Wir lösen Probleme bei Handshake-Fehlern und erklären die AllowedIPs Logik für Ihren VPS.

Was Sie aufbauen

Ein WireGuard VPN auf einem eigenen Server benötigt etwa vierzig Zeilen Konfiguration: ein Key-Paar, eine Interface-Datei, einen sysctl-Eintrag, eine NAT-Regel und eine Firewall-Freigabe. Die Installation ist trivial. Daher behandelt dieser Leitfaden hauptsächlich Fehlerquellen wie Key-Berechtigungen, AllowedIPs, Forwarding und DNS.

WireGuard ist ein Layer-3-Tunnel im Kernel. Seit Linux 5.6 ist er im Mainline-Kernel enthalten, sodass Ubuntu 24.04 und Debian 13 ihn ohne externe Module ausliefern. Es gibt keine Aushandlung von Chiffren, keine Certificate Authority und keinen Benutzername/Passwort-Schritt: Ein Peer besteht aus einem Public Key und den IP-Adressen, die dieser Key verwenden darf. Pakete, die die MAC-Prüfung nicht bestehen, werden ohne Antwort verworfen; der Port reagiert daher nicht auf Scans. Der Nachteil: Es existiert kein Authentifizierungsserver. Um den Zugriff zu entziehen, muss der Peer auf dem System gelöscht werden.

Prüfen Sie zuerst die Virtualisierung

WireGuard benötigt einen Kernel, in den ein Modul geladen werden kann. Auf einem KVM VPS funktioniert dies direkt. Bei Container-Virtualisierung, die den Host-Kernel teilen — OpenVZ, LXC —, schlägt der erste Befehl mit RTNETLINK answers: Operation not supported fehl. Die Alternative ist die wireguard-go Userspace-Implementierung. Prüfen Sie dies zuerst mit sudo modprobe wireguard && echo ok.

Schlüssel ohne Datenabfluss generieren

Eine für alle lesbare /etc/wireguard/server.key entspricht einer fehlenden VPN-Verbindung. Die übliche umask 077 && wg genkey | sudo tee ...-Zeile ist unzuverlässig, da sudo eine eigene umask auf die von tee erstellte Datei tee anwendet. Legen Sie den Modus explizit fest.

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.key

Generieren Sie das Client-Paar auf die gleiche Weise. wg genpsk fügt einen optionalen Pre-Shared Key hinzu, der jeweils eine Zeile in jeder Konfiguration benötigt.

Die Server-Schnittstelle: /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/32

chmod 600 bedeutet, dass Sie diesen Schritt übersprungen haben, falls eine Startwarnung erscheint, dass die Datei für alle Benutzer lesbar ist. Address ist die Adresse des Servers innerhalb des Tunnels und repräsentiert das gesamte VPN-Subnetz. Wählen Sie einen Bereich, der nicht in öffentlichen Netzwerken vorkommt — 192.168.1.0/24 kollidiert mit der Hälfte der Heimrouter, hinter denen sich Ihre Clients befinden, wodurch der Tunnel ohne Fehlermeldung gegen die lokale Route verliert.

Die AllowedIPs eines Peers auf der Server-Seite ist eine /32, also die eine Tunnel-Adresse, die der Client besitzt. Wenn Sie zwei Peers mit derselben allowed IP konfigurieren, wird diese der zuletzt konfigurierten IP zugewiesen; der erste Peer erhält dann keinen Traffic mehr, ohne dass eine Fehlermeldung ausgegeben wird. Lassen Sie SaveConfig leer, da wg-quick down diese Datei sonst aus dem Live-Zustand überschreibt.

Den Server als Router konfigurieren

Ein Linux-Server verwirft Pakete, die nicht an ihn selbst adressiert sind. IP-Forwarding und Source NAT sind standardmäßig deaktiviert.

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_forward

Ein nacktes sysctl -w funktioniert nur bis zum nächsten Neustart und stellt dann ohne Fehlermeldung den Dienst ein. NAT benötigt das Egress-Interface — die NIC mit Internetzugang, nicht wg0. Gehen Sie nicht von eth0 aus; ermitteln Sie Ihr Interface mit ip route show default, da aktuelle Images Namen wie enp1s0 oder ens3 verwenden.

Firewall: the port, and the forward path

One nftables file covers filter and NAT. Write /etc/nftables.conf — it flushes the existing ruleset, so skip this on a box already managed by ufw or Docker.

#!/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
  }
}

Apply it with sudo systemctl enable --now nftables, keeping a second SSH session open: policy drop plus a typo in the SSH rule locks you out of your own server. Note what the forward chain does not allow — wg0 to wg0. Peers reach the internet, not each other; add iifname "wg0" oifname "wg0" accept for a peer-to-peer VPN. The same chain governs what a peer may touch on the server itself, which matters when the box doubles as a remote development box running Claude Code in tmux and you would rather not expose that side of it publicly.

On a ufw box: ufw allow 51820/udp, DEFAULT_FORWARD_POLICY="ACCEPT" in /etc/default/ufw, and a *nat POSTROUTING MASQUERADE rule at the top of /etc/ufw/before.rules.

Inbetriebnahme unter systemd

sudo systemctl enable --now wg-quick@wg0
sudo wg show

wg-quick erstellt die Schnittstelle, fügt die Adressen hinzu und installiert die Routen, die aus AllowedIPs abgeleitet werden. enable --now ist der entscheidende Teil: Eine manuelle wg-quick up wg0 geht nach dem nächsten Neustart verloren, und Kernel-Upgrades erfordern Neustarts.

Die Client-Konfiguration und die häufig gemachte Fehlannahme

[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 = 25

AllowedIPs erfüllt zwei verschiedene Aufgaben gleichzeitig. Die Vermischung dieser Aufgaben ist die Ursache für die meisten WireGuard-Missverständnisse.

In Abgangsrichtung (Outbound) ist es eine Routing-Tabelle. Ein Paket, dessen Zieladresse mit der AllowedIPs eines Peers übereinstimmt, wird verschlüsselt an diesen Peer gesendet. 0.0.0.0/0, ::/0 leitet den gesamten Datenverkehr durch den Tunnel – ein Full-Tunnel, wobei der Server als Standard-Route dient. Ein Split-Tunnel verwendet eine eingeschränkte Liste: AllowedIPs = 10.8.0.0/24, 10.20.0.0/16 leitet nur den VPN-Verkehr und ein privates Netzwerk hinter dem Server weiter; alles andere behält die lokale Route bei. Diese eingeschränkte Liste ermöglicht es, Dienste vollständig vom öffentlichen Internet fernzuhalten – eine private Nextcloud-Instanz auf einem VPS, die an die Tunnel-Adresse gebunden ist, oder die VMs in einem Nested-Virtualization-Lab, die auf demselben Host laufen, bleiben für Peers erreichbar und für alle anderen unsichtbar.

In Angangsrichtung (Inbound) ist es eine Zugriffskontrollliste (ACL). Ein entschlüsseltes Paket von einem Peer, dessen Quelladresse nicht in der AllowedIPs dieses Peers enthalten ist, wird verworfen. Deshalb listet der Server für den Laptop 10.8.0.2/32 auf: Ein Eintrag von 0.0.0.0/0 würde es diesem Client ermöglichen, jede Adresse im Tunnel zu fälschen (Spoofing).

PersistentKeepalive ist für Clients hinter einem NAT gedacht, bei dem der Router die UDP-Mapping-Verbindung nur bei aktivem Datenverkehr offen hält. Wenn die Verbindung abläuft, kann der Server den Client nicht mehr erreichen. PersistentKeepalive = 25 hält das Mapping offen – konfigurieren Sie dies auf dem Client, nicht auf einem Server mit einer öffentlichen IP.

DNS und das unbemerkte Datenleck

Mit AllowedIPs = 0.0.0.0/0 und ohne eine DNS = Zeile verwendet der Client den Resolver aus dem lokalen Netzwerk – den Café-Router unter 192.168.1.1. Diese Route ist spezifischer als die Standardroute. Daher werden DNS-Anfragen unverschlüsselt über die lokale Verbindung gesendet, während der restliche Datenverkehr durch den Tunnel geleitet wird. Der Datenverkehr ist privat; die Liste der Hostnamen ist es nicht.

Es gibt zwei korrekte Optionen. Verweisen Sie DNS auf einen öffentlichen Resolver (DNS = 9.9.9.9), dann werden die Anfragen durch den Tunnel geleitet und verlassen das Netzwerk über Ihren Server, obwohl dieser Resolver die Anfragen weiterhin sieht. Oder nutzen Sie unbound oder dnsmasq gebunden an 10.8.0.1, konfigurieren Sie DNS = 10.8.0.1 und fügen Sie udp dport 53 iifname "wg0" accept zur input chain hinzu – wenn Sie diese Zeile konfigurieren, wird der Resolver ignoriert und es findet keine Namensauflösung statt.

Auf Linux-Clients wendet wg-quick DNS über resolvconf an; wenn diese fehlt, erhalten Sie resolvconf: command not found. Installieren Sie openresolv oder setzen Sie PostUp = resolvectl dns %i 10.8.0.1 auf einem systemd-resolved Client.

Hinzufügen und Entfernen von Peers ohne Unterbrechung des Tunnels

Ein Neustart des Interfaces zum Hinzufügen eines Benutzers trennt alle bestehenden Verbindungen. Fügen Sie den [Peer] Block zu wg0.conf hinzu und laden Sie den Peer-Satz anschließend neu.

sudo bash -c 'wg syncconf wg0 <(wg-quick strip wg0)'

wg-quick strip gibt die Konfiguration ohne die wg-quick-only Keys (Address, DNS, PostUp) aus. syncconf wendet die Änderungen an, während laufende Sitzungen bestehen bleiben. Es werden nur die Peers aktualisiert: Ein geänderter Address erfordert weiterhin einen vollständigen down/up Vorgang. Entziehen Sie den Zugriff mit sudo wg set wg0 peer <public key> remove und löschen Sie anschließend den Block aus der Datei, da er sonst beim nächsten Reload wieder erscheint.

Fehlerzustände und die entsprechenden Meldungen

Handshake wird nie abgeschlossen. wg show listet den Peer ohne latest handshake auf, und der Client protokolliert:

Handshake for peer 1 (10.0.0.10:51820) did not complete after 5 seconds, retrying (try 2)

Es gehen keine Daten ein oder es werden keine Daten akzeptiert. Prüfen Sie folgende Punkte: Ist UDP 51820 sowohl in der VPS-Firewall als auch in der Netzwerk-Firewall des Providers (oft ein separates Kontrollpanel) geöffnet? Sind die Endpoint-Adresse und der Port korrekt? Sind die Schlüssel vertauscht? Der Schlüssel im [Peer]-Block des Clients muss der öffentliche Schlüssel des Servers sein und umgekehrt. Das Einfügen eines privaten Schlüssels oder des eigenen öffentlichen Schlüssels des Clients verursacht genau dieses Symptom. sudo tcpdump -ni any udp port 51820 auf dem Server zeigt an, ob Pakete überhaupt ankommen. Das Kernel-Modul protokolliert standardmäßig nichts; WireGuard-Meldungen erscheinen in dmesg erst nach Aktivierung von dynamic debug (echo module wireguard +p | sudo tee /sys/kernel/debug/dynamic_debug/control). Wenn dies aktiviert ist, wird ein falscher Schlüssel als invalid-MAC drop angezeigt.

Handshake funktioniert, kein Internet. ping 10.8.0.1 ist erfolgreich, aber ping 1.1.1.1 läuft in ein Timeout: IP-Forwarding oder NAT fehlt. Prüfen Sie, ob sysctl net.ipv4.ip_forward 1 liest, und beobachten Sie die Zähler während der Client pingt, mit sudo nft list ruleset oder sudo iptables -t nat -L POSTROUTING -n -v. Null Pakete bei der masquerade-Regel bedeuten, dass der Name des Egress-Interfaces falsch ist; ein steigender Zähler ohne Antworten deutet auf die Policy der forward-Chain hin.

Internet funktioniert, DNS funktioniert nicht. ping 1.1.1.1 ist erfolgreich und curl https://example.com gibt Could not resolve host zurück. Die DNS-Zeile fehlt oder nennt einen Resolver, der innerhalb des Tunnels nicht erreichbar ist.

Einige HTTPS-Websites laden nicht. SSH und ping funktionieren; große Seiten bleiben hängen. Dies liegt an der Path MTU: Der Tunnel erzeugt Overhead, und eine Verbindung dazwischen verwirft die zu großen Pakete, ohne eine ICMP-Meldung zurückzusenden. Senken Sie MTU in der Client-Konfiguration [Interface] — versuchen Sie 1420, dann 1380, dann 1280.

Interface lässt sich nicht starten. Address already in use bedeutet, dass ein anderer Prozess UDP 51820 belegt. Cannot find device wg0 nach einem fehlgeschlagenen up bedeutet meist, dass die Konfiguration abgelehnt wurde; lesen Sie journalctl -u wg-quick@wg0 -n 50.

Migration von Streisand oder OpenVPN

Streisand wird nicht mehr gepflegt und das Repository ist archiviert. Der Betrieb eines VPNs mit veralteter Automatisierung führt zu langfristigen Sicherheitsrisiken. Ein In-place-Upgrade ist nicht möglich. Die PKI von OpenVPN ist nicht kompatibel: WireGuard verwendet keine Zertifikate, keine CA und keine Ablaufdaten; jeder Client erhält daher ein neues Key-Pair.

Führen Sie die Migration parallel durch — WireGuard auf UDP 51820 kann gleichzeitig mit OpenVPN auf 1194 auf demselben System betrieben werden. Installieren Sie wg0, migrieren Sie die Clients nacheinander und stoppen Sie anschließend den alten Dienst. Das Benutzername/Passwort-Modell und das Revocation-Modell von OpenVPN werden nicht übernommen; falls Sie Benutzerkonten oder einen Audit-Trail benötigen, implementieren Sie diese als zusätzliche Ebene über WireGuard.

Backups, Upgrades und Skalierungsprobleme

/etc/wireguard ist der Server. Erstellen Sie ein Backup (sudo tar czf wg-backup.tgz -C /etc wireguard, Modus 600, extern auf einem anderen System speichern), um den Server in wenigen Minuten auf einem neuen VPS wiederherzustellen. Wenn der private Schlüssel des Servers verloren geht, müssen alle Client-Konfigurationen neu ausgestellt werden, da die Clients den öffentlichen Schlüssel des Servers fest hinterlegen. Upgrades sind ein gewöhnlicher apt upgrade, ergänzt durch einen Neustart bei Kernel-Updates. wg-quick@wg0 startet automatisch neu, sofern aktiviert.

Der Zustand pro Peer ist klein und die Kryptografie läuft im Kernel. Die Leistungsgrenze wird daher durch die CPU und das Bandbreitenlimit des VPS bestimmt, nicht durch diese Konfiguration. Messen Sie die Leistung mit iperf3 über den Tunnel, anstatt sich auf veröffentlichte Werte zu verlassen. Bei großen Skalierungen ist der administrative Aufwand die größte Herausforderung. Jeder Peer benötigt eine eindeutige Tunnel-IP. Das manuelle Bearbeiten von sechzig [Peer]-Blöcken führt zu Duplikaten in AllowedIPs; generieren Sie die Konfigurationen daher per Skript. Ein Server stellt einen UDP-Endpunkt und einen Single Point of Failure dar. WireGuard unterstützt kein Clustering; Redundanz erfordert einen zweiten Server mit eigenen Schlüsseln. Die Schlüsselrotation erfolgt manuell. Dokumentieren Sie daher genau, wer welchen Schlüssel besitzt und wie ein Schlüssel widerrufen wird.

Dies erfordert einen Linux-Rechner unter Ihrer Kontrolle: eine öffentliche IP, einen Kernel, in den Sie Module laden können, und eine Firewall, die Sie vollständig kontrollieren.

FAQ

Warum schließt der WireGuard-Handshake nie ab?

Wenn wg show einen Peer ohne latest handshake auflistet, kommen keine Pakete an oder werden nicht akzeptiert. Prüfen Sie UDP 51820 sowohl in der VPS-Firewall als auch in der separaten Netzwerk-Firewall Ihres Providers. Bestätigen Sie den Endpoint Host und Port. Prüfen Sie zudem, ob die Keys vertauscht sind — der [Peer] Block des Clients muss den public Key des Servers enthalten. sudo tcpdump -ni any udp port 51820 auf dem Server zeigt an, ob Pakete überhaupt ankommen; dmesg meldet WireGuard-Handshake-Fehler erst nach Aktivierung von dynamic debug (echo module wireguard +p | sudo tee /sys/kernel/debug/dynamic_debug/control). Bei einem Key-Mismatch erscheint die Meldung als invalid-MAC drop.

Der Tunnel steht, aber ich habe keine Internetverbindung. Was fehlt?

Wenn ping 10.8.0.1 funktioniert, aber ping 1.1.1.1 ein Timeout verursacht, liegt ein Problem mit dem Forwarding oder NAT vor. Bestätigen Sie, dass sysctl net.ipv4.ip_forward den Wert 1 ausgibt und dass dieser in /etc/sysctl.d/ gesetzt ist (nicht nur temporär mit einem sysctl -w, der nach einem Reboot verloren geht). Prüfen Sie dann die Masquerade-Regel. Diese verwendet das echte Egress-Interface aus ip route show defaultenp1s0 oder ens3, selten eth0.

Benötige ich die DNS = Zeile in meiner Client-Konfiguration?

Bei einem Full-Tunnel ohne DNS = Zeile nutzt der Client den Resolver des lokalen Netzwerks. Diese DNS-Anfragen werden im Klartext über die lokale Verbindung gesendet, während der restliche Datenverkehr getunnelt wird. Zeigen Sie mit DNS auf einen öffentlichen Resolver oder führen Sie unbound/dnsmasq aus, gebunden an 10.8.0.1, und öffnen Sie udp dport 53 iifname "wg0" in der input chain.

Was steuert AllowedIPs eigentlich?

Es erfüllt zwei Aufgaben. Ausgehend fungiert es als Routing-Tabelle: Datenverkehr, der auf den AllowedIPs eines Peers passt, wird verschlüsselt an diesen Peer gesendet. Eingehend fungiert es als Access-Control-List: Ein entschlüsseltes Paket, dessen Quelle außerhalb des AllowedIPs des Peers liegt, wird verworfen. Deshalb listet die Serverseite einen /32 pro Client, während die Clientseite möglicherweise 0.0.0.0/0 listet.

Läuft WireGuard auf jedem VPS?

Auf einem KVM VPS funktioniert es mit dem In-Kernel-Modul ohne zusätzliche Konfiguration. Bei Container-Virtualisierung, die den Host-Kernel teilt (wie OpenVZ oder LXC), schlägt modprobe wireguard mit Operation not supported fehl. Der Fallback ist die wireguard-go Userspace-Implementierung. Führen Sie sudo modprobe wireguard && echo ok vor allen anderen Schritten aus.

#wireguard#vpn#linux-networking#nftables#systemd#self-hosting