Zum Inhalt springen
Serverküche
Suche

Die Suche wird geladen … (nur in der veröffentlichten Seite verfügbar).

Sicherheit Schwierigkeit: Fortgeschritten

WireGuard-VPN einrichten: sicherer Zugang zum eigenen Server

Ein schlankes WireGuard-VPN nativ auf dem netcup-Server: Schlüssel, Server- und Client-Konfig, Firewall, Handy-QR – plus der Docker-Fallstrick beim Full-Tunnel.

· 11 Min. Lesezeit ·Dauer: ca. 40 Minuten
Inhaltsverzeichnis

Bisher ist alles auf deinem Server öffentlich hinter Traefik erreichbar. Manches soll aber nur für dich laufen – ein Admin-Dashboard, eine Datenbank, ein interner Dienst. Mit WireGuard baust du dir einen verschlüsselten Tunnel direkt in den Server, ohne dafür weitere Ports ins Internet zu öffnen.

Was bauen wir?

Ein WireGuard-VPN nativ auf dem Server (kein Container – WireGuard steckt im Linux-Kernel, das ist die schlankeste und stabilste Variante). Deine Geräte – Laptop, Handy – bekommen einen verschlüsselten Tunnel zum Server und darüber eine private IP im Netz 10.8.0.0/24. Zwei Betriebsarten, die du über eine einzige Client-Zeile umschaltest:

  • Split-Tunnel (Standard): Nur der Weg zum Server und seinen internen Diensten läuft durchs VPN. Damit erreichst du Dinge, die nicht öffentlich stehen sollen (ein Dashboard, eine Datenbank, später ein eigener DNS-Filter), ohne dafür einen Port zu veröffentlichen.
  • Full-Tunnel (optional): Der gesamte Internetverkehr deines Geräts läuft über den Server – praktisch im offenen Café-WLAN, weil dann alles verschlüsselt über deine eigene IP rausgeht.

Getestet mit wireguard-tools 1.0.20210914 unter Debian 13 (Kernel 6.12, WireGuard ist dort fest eingebaut).

Warum WireGuard und nicht OpenVPN oder ein offener Port? WireGuard läuft im Kernel, ist mit wenigen tausend Zeilen Code winzig (leicht prüfbar, kleine Angriffsfläche), braucht nur einen einzigen UDP-Port und kommt mit einer Handvoll Konfigzeilen aus. Der Handshake ist so schlank, dass eine mobile Verbindung nach dem Aufwachen praktisch sofort wieder steht. Statt also jeden internen Dienst mit eigener Authentifizierung ins Netz zu stellen, legst du einen sicheren Tunnel – und alles dahinter bleibt privat.

Voraussetzungen

  • Ein Server mit aktiver UFW-Firewall und root- bzw. sudo-Zugang.
  • Wenn du zusätzlich die netcup-Firewall nutzt: den WireGuard-Port dort später freigeben (fertige Vorlage im Firewall-Tutorial).
  • Ein Client-Gerät mit der offiziellen WireGuard-App (Windows, macOS, Linux, iOS, Android).
🍳 Empfehlung Anzeige

VPS 1000 G12

4 vCore · 8 GB RAM · 256 GB NVMe

ab 10,36 €/Monat

Ein WireGuard-VPN braucht kaum Ressourcen – der kleinste VPS reicht locker.

Zu netcup →

💶 5 € Gutschein für netcup-Neukunden:36nc17844976032 (nur Neukunden, keine Domains)

Schritt für Schritt

Schritt 1: WireGuard installieren

Der Kernel bringt WireGuard schon mit; du brauchst nur die Userspace-Werkzeuge (und qrencode für den Handy-QR-Code):

Terminal
sudo apt update
sudo apt install -y wireguard wireguard-tools qrencode

Prüfe, dass das Kernel-Modul geladen werden kann:

Terminal
sudo modprobe wireguard && lsmod | grep wireguard
Ausgabe
wireguard             118784  0

Schritt 2: Schlüsselpaare erzeugen

WireGuard authentifiziert rein über Schlüsselpaare – kein Passwort, keine Zertifikate. Jede Seite (Server und jeder Client) hat einen privaten und einen öffentlichen Schlüssel. Der private darf niemals die Maschine verlassen. Setz zuerst eine strikte Dateimaske, damit die Schlüssel nicht für andere lesbar sind:

Terminal
umask 077
wg genkey | sudo tee /etc/wireguard/server.key | wg pubkey | sudo tee /etc/wireguard/server.pub

Der erste Befehl erzeugt den privaten Schlüssel (server.key), leitet ihn durch wg pubkey und speichert den öffentlichen (server.pub). Erzeuge auf dieselbe Weise ein Paar für deinen ersten Client:

Terminal
wg genkey | tee client.key | wg pubkey > client.pub

Du hast jetzt vier Schlüssel. Merke dir die Zuordnung: In die Server-Konfig kommt der private Server-Schlüssel und der öffentliche Client-Schlüssel; in die Client-Konfig umgekehrt. Das ist die häufigste Fehlerquelle – nie den privaten Schlüssel der falschen Seite eintragen.

Schritt 3: Server-Konfiguration anlegen

Lege /etc/wireguard/wg0.conf an. Trag deinen privaten Server-Schlüssel und den öffentlichen Client-Schlüssel ein:

INI
[Interface]
Address = 10.8.0.1/24
ListenPort = 51820
PrivateKey = DEIN_SERVER_PRIVATE_KEY

[Peer]
PublicKey = DEIN_CLIENT_PUBLIC_KEY
AllowedIPs = 10.8.0.2/32

Was die Zeilen bedeuten:

  • Address – die VPN-interne IP des Servers (10.8.0.1); die /24 spannt das VPN-Subnetz 10.8.0.0/24 auf.
  • ListenPort – der UDP-Port, auf dem WireGuard lauscht. 51820 ist der Standard.
  • [Peer] + AllowedIPs = 10.8.0.2/32 – dieser Client darf ausschließlich unter der VPN-IP 10.8.0.2 auftauchen. Wichtig: AllowedIPs hat auf beiden Seiten eine andere Bedeutung – auf dem Server ist es die feste Tunnel-IP des Clients, auf dem Client (Schritt 5) legt es fest, was durch den Tunnel geroutet wird.

Für jeden weiteren Client fügst du später einfach einen weiteren [Peer]-Block mit der nächsten IP (10.8.0.3/32 …) hinzu.

Schritt 4: Firewall öffnen und den Tunnel starten

WireGuard spricht über UDP – gib den Port frei. In der UFW:

Terminal
sudo ufw allow 51820/udp

Sitzt zusätzlich die netcup-Firewall davor, brauchst du dort eine eingehende Regel UDP · Ziel-Port 51820 – die fertige Vorlage steht im netcup-Firewall-Tutorial. Starte nun den Tunnel und richte den Autostart ein:

Terminal
sudo wg-quick up wg0
sudo systemctl enable wg-quick@wg0

Prüfe, dass die Schnittstelle läuft:

Terminal
sudo wg show wg0
Ausgabe
interface: wg0
  public key: nZT4kozgZjtHVzGfPRL+niI4llEQCUqGpYG0ni+fAT4=
  private key: (hidden)
  listening port: 51820

peer: j5h2jl87JApAbWrJikrth3H/6fNuf6X2TgBgDSJVwwE=
  allowed ips: 10.8.0.2/32

Der Peer ist eingetragen, aber es gibt noch keinen latest handshake – logisch, der Client fehlt noch.

Schritt 5: Client einrichten

Die Client-Konfig ist das Spiegelbild. Erstelle eine Datei client.conf (auf dem Server zum Erzeugen des QR-Codes, den Inhalt trägst du dann ins Client-Gerät):

INI
[Interface]
Address = 10.8.0.2/24
PrivateKey = DEIN_CLIENT_PRIVATE_KEY
# DNS = 10.8.0.1   # nur aktivieren, wenn auf 10.8.0.1 wirklich ein DNS-Resolver läuft – sonst z. B. 1.1.1.1

[Peer]
PublicKey = DEIN_SERVER_PUBLIC_KEY
Endpoint = DEINE_SERVER_IP:51820
AllowedIPs = 10.8.0.0/24
PersistentKeepalive = 25

Die entscheidenden Zeilen:

  • Endpoint – die öffentliche IP deines Servers plus Port. Hierhin baut der Client den Tunnel auf.
  • AllowedIPs = 10.8.0.0/24 – das ist der Split-Tunnel: Nur Verkehr ins VPN-Subnetz läuft durch den Tunnel, dein normaler Internetverkehr bleibt direkt. Für den Full-Tunnel (alles über den Server) setzt du hier 0.0.0.0/0 – dazu Schritt 6.
  • DNS = 10.8.0.1 – bewusst auskommentiert. Diese Zeile leitet den gesamten System-DNS deines Geräts auf 10.8.0.1 um – dort lauscht aber standardmäßig nichts auf Port 53, sodass bei aktivem Tunnel die Namensauflösung bricht. Setz sie nur, wenn auf dem Server wirklich ein eigener DNS-Resolver/-Filter läuft; brauchst du im Tunnel einfach einen funktionierenden DNS, trag stattdessen einen echten Resolver wie 1.1.1.1 ein.
  • PersistentKeepalive = 25 – hält die Verbindung offen, wenn der Client hinter einem NAT/CGNAT sitzt (Handy im Mobilfunknetz).

Fürs Handy erzeugst du aus der Datei einen QR-Code direkt im Terminal – in der WireGuard-App „Tunnel hinzufügen → QR-Code scannen":

Terminal
qrencode -t ansiutf8 < client.conf

Am Desktop importierst du die client.conf einfach in der WireGuard-App. Danach die client.conf und client.key vom Server löschen (sie gehören aufs Endgerät, nicht auf den Server).

Schritt 6: Verbindung prüfen (und Full-Tunnel aktivieren)

Aktiviere den Tunnel in der Client-App und sieh auf dem Server nach:

Terminal
sudo wg show wg0
Ausgabe
peer: j5h2jl87JApAbWrJikrth3H/6fNuf6X2TgBgDSJVwwE=
  endpoint: 203.0.113.24:34582
  allowed ips: 10.8.0.2/32
  latest handshake: 45 seconds ago
  transfer: 1.58 KiB received, 1.39 KiB sent

Ein latest handshake plus wachsender transfer heißt: Der Tunnel steht. Vom Client aus erreichst du den Server jetzt unter seiner VPN-IP:

Terminal
ping 10.8.0.1

Willst du den Full-Tunnel (gesamter Verkehr übers VPN), sind zwei Änderungen nötig. Auf dem Client AllowedIPs = 0.0.0.0/0 setzen. Setz auf dem Client jetzt außerdem eine DNS =-Zeile (z. B. DNS = 1.1.1.1 oder deinen eigenen Resolver): Sobald aller Verkehr durch den Tunnel läuft, ist der DNS-Leak am Tunnel vorbei nämlich der Normalfall, nicht die Ausnahme – ohne diese Zeile fragt dein Gerät weiter die DNS-Server deines lokalen Netzes ab (Details im DNS-Leak-Eintrag im Fehlerteil). Auf dem Server das Routing plus NAT aktivieren – zuerst IP-Forwarding dauerhaft einschalten:

Terminal
echo "net.ipv4.ip_forward=1" | sudo tee /etc/sysctl.d/99-wireguard.conf
sudo sysctl -p /etc/sysctl.d/99-wireguard.conf

Dann in der [Interface]-Sektion der wg0.conf die Weiterleitungs- und NAT-Regeln ergänzen (ersetze eth0 durch dein echtes externes Interface, siehe ip route get 1.1.1.1):

INI
PostUp = iptables -I FORWARD 1 -i wg0 -j ACCEPT; iptables -I FORWARD 1 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

Docker auf demselben Server? Dann müssen die Regeln nach oben

Läuft auf dem Server auch Docker (z. B. dein Traefik), setzt Docker die FORWARD-Policy auf DROP und schiebt eigene Ketten davor. Hängst du die WireGuard-Regeln mit -A (anhängen) an, wird der Rückweg deiner Antwortpakete von Docker verworfen – der Handshake klappt, aber es kommt kein Internet an. Deshalb oben -I FORWARD 1 (einfügen ganz vorne) und die RELATED,ESTABLISHED-Regel für den Rückweg. Dasselbe gilt bei aktiver UFW, denn auch die setzt eine FORWARD-Default-Policy auf DROP – das -I FORWARD 1 übersteuert sie, sodass die Regeln in beiden Fällen greifen. Genau so getestet: Danach geht der Client mit der IP des Servers ins Netz.

Nach sudo wg-quick down wg0 && sudo wg-quick up wg0 prüfst du den Full-Tunnel, indem du auf dem Client deine öffentliche IP abfragst – sie sollte jetzt die Server-IP sein:

Terminal
curl -s ifconfig.me

Schritt 7: Einen Dienst nur übers VPN erreichbar machen

Jetzt der eigentliche Gewinn. Ein Dienst, den nur du brauchst, muss nicht öffentlich hinter Traefik stehen – du bindest ihn an die VPN-IP des Servers (10.8.0.1), dann ist er ausschließlich durch den Tunnel erreichbar, ohne einen einzigen Port im Internet.

Bei einem Docker-Dienst heißt das: den Port nicht an 0.0.0.0, sondern gezielt an die VPN-IP veröffentlichen. Statt - "8080:80" also:

YAML
    ports:
      - "10.8.0.1:8080:80"

Der Dienst hört damit nur auf der WireGuard-Schnittstelle – aus dem Internet ist er unsichtbar, über das VPN erreichst du ihn unter http://10.8.0.1:8080. (Wichtig: wg0 muss beim Start des Containers schon oben sein – der systemctl enable aus Schritt 4 sorgt dafür.)

Nach demselben Prinzip kannst du auch SSH nur noch übers VPN zulassen: In der UFW den öffentlichen SSH-Zugang entfernen und stattdessen nur aus dem VPN-Subnetz erlauben –

Terminal
sudo ufw allow from 10.8.0.0/24 to any port 22 proto tcp

– dann die öffentliche SSH-Regel löschen. Vorher unbedingt eine zweite Verbindung übers VPN testen, sonst sperrst du dich aus (im Notfall hilft die VNC-Konsole im netcup-SCP).

Wenn es nicht funktioniert

In wg show erscheint nie ein latest handshake. Der UDP-Port ist nicht erreichbar oder die Schlüssel passen nicht. WireGuard ist bei falschen Schlüsseln stumm – es gibt keine Fehlermeldung, nur keinen Handshake. Prüfe: sudo ufw status (Port 51820/udp offen?), die netcup-Firewall (eingehend UDP 51820), den Endpoint im Client (richtige öffentliche IP?) und dass privater und öffentlicher Schlüssel nicht vertauscht sind.

Handshake ist da, aber im Full-Tunnel kommt kein Internet an. Fast immer das Routing/NAT. Ist net.ipv4.ip_forward=1 gesetzt (sysctl net.ipv4.ip_forward)? Läuft Docker mit – oder ist UFW aktiv –, greift die FORWARD-DROP-Falle aus dem Warnkasten oben; beide setzen die Forward-Policy auf DROP. Die Regeln müssen mit -I FORWARD 1 vor den bestehenden Ketten stehen. Stimmt das externe Interface im MASQUERADE (eth0 vs. etwas anderes)?

Full-Tunnel steht, aber DNS-Anfragen laufen weiter am Tunnel vorbei (DNS-Leak). Ohne DNS =-Zeile fragt dein Gerät weiter die DNS-Server deines lokalen Netzes – im offenen WLAN sieht der Betreiber also weiter, welche Domains du aufrufst. Prüfe unter Linux mit resolvectl status, welcher DNS-Server dem Interface wg0 zugeordnet ist, oder mach einen Leak-Test (z. B. auf dnsleaktest.com): Tauchen dort fremde Resolver auf, trägst du in der Client-Konfig einen echten Resolver ein (DNS = 1.1.1.1) – oder den Server selbst (10.8.0.1), falls dort ein eigener DNS-Resolver läuft.

Der Tunnel steht, aber große Übertragungen (SSH, HTTPS, Downloads) hängen oder brechen ab. Ein MTU-Problem. wg-quick setzt die MTU auf 1420; in manchen Netzen (DS-Lite, bestimmte Mobilfunknetze) ist das noch zu hoch. Setz testweise MTU = 1412 oder 1280 in der [Interface]-Sektion des Clients.

wg-quick up meldet resolvconf: command not found. Die DNS =-Zeile braucht resolvconf. Entweder sudo apt install openresolv installieren oder die DNS-Zeile entfernen, wenn du den VPN-DNS nicht brauchst.

Die Verbindung schläft ein, sobald das Handy kurz nichts sendet. Der Client sitzt hinter NAT/CGNAT. PersistentKeepalive = 25 in der Client-Konfig hält die Verbindung offen.

Wartung & Backups

  • Weitere Geräte hinzufügen. Pro Gerät ein eigenes Schlüsselpaar und ein weiterer [Peer]-Block in der wg0.conf mit der nächsten freien IP (10.8.0.3/32 …). Nie denselben Schlüssel auf zwei Geräten verwenden. Damit bestehende Tunnel dabei nicht abreißen, lädst du die geänderte Konfig im Betrieb neu, statt down/up zu machen:

    Terminal
    sudo wg syncconf wg0 <(wg-quick strip wg0)
  • Schlüssel sichern – sie sind das Herz des VPN. Nimm /etc/wireguard/ in dein verschlüsseltes Restic-Backup auf. Wer die privaten Schlüssel hat, kommt ins VPN – behandle sie wie Passwörter.

  • Aktuell halten. wireguard-tools bekommt seine Updates über automatische Sicherheitsupdates; das Kernel-Modul kommt mit den Kernel-Updates.

  • Interne Dienste ans VPN binden. Der eigentliche Gewinn: Dienste, die niemand aus dem Internet erreichen soll, lässt du nur auf 10.8.0.1 lauschen (statt 0.0.0.0) – dann sind sie ausschließlich über den Tunnel erreichbar, ganz ohne öffentlichen Port.

  • Bei Server-Umzug die neue öffentliche IP im Endpoint jedes Clients nachziehen – sonst findet der Client den Server nicht mehr.

  • Ehrlich zum Aufwand: Einmal eingerichtet, läuft WireGuard praktisch wartungsfrei. Der einzige wiederkehrende Handgriff ist das Anlegen eines Peers pro neuem Gerät.

Viele Geräte? Dann lohnt ein Mesh-Manager

Solange du eine Handvoll Geräte zu einem Server verbindest, ist das reine WireGuard hier genau richtig – volle Kontrolle, nichts läuft über Dritte. Sobald du aber viele Geräte untereinander vernetzen willst (Laptop ↔ Handy ↔ mehrere Server), wird die manuelle Peer-Pflege mühsam. Dann lohnt ein Blick auf Tailscale oder das selbstgehostete Headscale: Beide bauen auf WireGuard auf und übernehmen nur den Schlüsselaustausch und das Vernetzen automatisch. Das Fundament aus diesem Tutorial verstehst du dann trotzdem – es ist dasselbe darunter.

Feedback per E-Mail: feedback@serverkueche.de

Wie geht's weiter?

Das könnte dir auch schmecken