Wie kommst du an deine Nextcloud, wenn du im Zug sitzt? Und an das Pi-hole-Dashboard, wenn die Familie anruft, weil „das Internet kaputt" ist und du drei Städte weiter bist? Der Reflex vieler Anfänger ist eine Portfreigabe im Router: Port 8080 auf, Nextcloud aus dem Internet erreichbar, fertig. Das funktioniert, und es ist die Einstellung, vor der ich in jeder Anleitung hier warne, weil dann jeder Scanner auf der Welt an deiner Anmeldeseite rütteln darf.
Der bessere Weg ist ein VPN: ein einziger Port am Router, dahinter ein Tunnel, den nur deine eigenen Geräte mit ihrem Schlüssel öffnen können. Wer drin ist, sieht das Heimnetz wie vom Sofa aus. Wer den Schlüssel nicht hat, sieht nicht einmal, dass da etwas lauscht. wg-easy macht daraus eine Weboberfläche mit QR-Codes, und der Rest dieses Beitrags ist der Weg dahin.
15), geprüft am 24-09-2026.
Was wg-easy ist, und warum VPN statt Portfreigabe
WireGuard ist das VPN-Protokoll, das seit 2020 im Linux-Kernel steckt. Es ist klein, schnell und braucht pro Gerät genau ein Schlüsselpaar. Was es nicht hat, ist eine Oberfläche: Wer WireGuard von Hand einrichtet, tippt Schlüssel in Textdateien und verteilt sie auf seine Geräte. Genau diese Arbeit nimmt wg-easy ab. Es ist ein Container, in dem WireGuard läuft, plus eine Weboberfläche, in der du Geräte anlegst, einen QR-Code zeigst und fertig bist. Das Projekt ist Open Source unter der AGPL, Version 15 ist der große Umbau von 2025 mit Setup-Assistent, Benutzerkonten und Zwei-Faktor-Anmeldung. Die aktuelle Ausgabe 15.4.0 vom 14-08-2026 hat dazu eine Anmeldung über fremde Konten und einige Sicherheitsverbesserungen gebracht.
Der Unterschied zur Portfreigabe ist, wer die Tür bewacht. Bei einer Portfreigabe für Nextcloud steht die Anmeldeseite von Nextcloud im Internet, und ihre Sicherheit hängt an Nextcloud. Beim VPN steht nur WireGuard im Internet, und WireGuard antwortet grundsätzlich niemandem, der nicht den richtigen Schlüssel mitschickt. Ein Scanner sieht einen Port, der nicht reagiert. Was dahinter läuft, ob Nextcloud, Pi-hole oder eine Testinstallation mit dem Passwort „admin", ist von außen nicht mehr erreichbar. Deshalb steht in meinen Anleitungen so oft der Satz „keine Portfreigabe, VPN davor". Das hier ist das VPN.
Was du brauchst
- Einen Linux-Rechner mit Docker und Docker Compose v2. Das Image gibt es für amd64 und arm64; ein Raspberry Pi 4 reicht, ARMv7 wird seit 15.2.2 nicht mehr bedient. Prüfen:
docker compose versionmuss eine 2.x oder höher ausgeben. Wer Docker noch nicht hat: Die Compose-Grundlagen erklären Installation und die fünf Befehle. - Das WireGuard-Kernelmodul. Bei Debian, Ubuntu und Raspberry Pi OS ist es seit Kernel 5.6 dabei. Prüfen:
sudo modprobe wireguard && lsmod | grep wireguard; kommt eine Zeile mitwireguardzurück, ist es da. Fehlt es, läuft wg-easy seit 15.2.2 auch ohne, im sogenannten Userspace-Modus, nur langsamer. - Eine feste IP-Adresse für den Rechner. Die Portfreigabe zeigt auf eine Adresse, und die darf sich nicht ändern. In der FritzBox: Heimnetz, Netzwerk, beim Rechner auf Bearbeiten, dort das Häkchen, das ihm immer dieselbe IPv4-Adresse zuweist. Prüfen:
hostname -Izeigt die Adresse, die du gleich brauchst. - Eine öffentliche IPv4-Adresse am Anschluss. Das ist die Voraussetzung, die am häufigsten fehlt, und sie fehlt still. In der FritzBox unter Internet, Online-Monitor steht die IPv4-Adresse, mit der du im Internet unterwegs bist. Beginnt sie mit 100.64 bis 100.127, oder steht dort nur eine IPv6-Adresse, hat dein Anbieter dich auf DS-Lite gesetzt. Dann teilst du dir die IPv4-Adresse mit anderen Kunden, und eine Portfreigabe kommt nie bei dir an. Was dann geht, steht unten bei „Wo es klemmt".
- Einen Namen für deinen Anschluss. Deine öffentliche IP wechselt; deine Geräte brauchen einen Namen, der ihr folgt. Die FritzBox liefert ihn kostenlos: Internet, MyFRITZ!-Konto, mit E-Mail-Adresse registrieren, Bestätigungslink klicken. Danach steht dort eine Adresse wie
abc123xyz.myfritz.net. Die kommt gleich in den Setup-Assistenten. - Die Ports 51820 und 51821 frei auf dem Rechner. Prüfen:
sudo ss -tulpn | grep -E '5182[01]'darf nichts ausgeben. Wenn doch, hilft der Beitrag zum belegten Port.
- Rechner mit Docker (fest vergeben):
192.168.178.20 - Gateway (deine FritzBox):
192.168.178.1 - Heimnetz:
192.168.178.0/24 - MyFRITZ!-Adresse (bei dir anders):
abc123xyz.myfritz.net - Ordner für die Compose-Datei:
~/wg-easy - Tunnel-Port am Router und am Rechner:
51820/udp - Weboberfläche im Heimnetz:
http://192.168.178.20:51821
Schritt 1: Die Compose-Datei
Zuerst ein Ordner, dann die Datei. Der Editor nano öffnet sie; speichern mit Strg+O, Enter, schließen mit Strg+X.
mkdir -p ~/wg-easy
cd ~/wg-easy
nano compose.yamlDie Datei ist die offizielle aus dem wg-easy-Repository, mit genau einer Änderung, die weiter unten erklärt wird. Hinein damit, wörtlich:
volumes:
etc_wireguard:
services:
wg-easy:
image: ghcr.io/wg-easy/wg-easy:15
container_name: wg-easy
environment:
- INSECURE=true
networks:
wg:
ipv4_address: 10.42.42.42
ipv6_address: fdcc:ad94:bacf:61a3::2a
volumes:
- etc_wireguard:/etc/wireguard
- /lib/modules:/lib/modules:ro
ports:
- "51820:51820/udp"
- "51821:51821/tcp"
restart: unless-stopped
cap_add:
- NET_ADMIN
- SYS_MODULE
sysctls:
- net.ipv4.ip_forward=1
- net.ipv4.conf.all.src_valid_mark=1
- net.ipv6.conf.all.disable_ipv6=0
- net.ipv6.conf.all.forwarding=1
- net.ipv6.conf.default.forwarding=1
networks:
wg:
driver: bridge
enable_ipv6: true
ipam:
driver: default
config:
- subnet: 10.42.42.0/24
- subnet: fdcc:ad94:bacf:61a3::/64Ein paar Zeilen davon sehen nach mehr aus, als eine Compose-Datei sonst braucht, und jede hat einen Grund.
image: ghcr.io/wg-easy/wg-easy:15 ist der Tag für die Hauptversion. Die Doku empfiehlt ihn ausdrücklich: Du bekommst jede 15.x automatisch, aber nie einen Sprung auf 16, der dir die Konfiguration umbaut. Und sie warnt vor latest: Der Tag zeigt noch auf Version 14. Wer ihn nimmt, installiert das alte wg-easy ohne Assistenten. Das ist die Art Stolperfalle, die in der Doku ein einziger Halbsatz ist und in den Discussions des Projekts ein Dauerthema.
INSECURE=true ist die eine Änderung gegenüber der Vorlage, und ohne sie kommst du nicht hinein. wg-easy 15 verweigert die Anmeldung über eine unverschlüsselte Verbindung; der Wortlaut lautet „You can't log in with an insecure connection. Use HTTPS." Im Heimnetz über eine IP-Adresse gibt es aber kein HTTPS, also erlaubt die Variable HTTP. Die Doku sagt dazu zwei Dinge, und beide stimmen: Das ist unsicher, und es ist in Ordnung, solange die Oberfläche von außen nicht erreichbar ist. Port 51821 bekommt deshalb nie eine Portfreigabe. Wer die Oberfläche mit Zertifikat will, setzt einen Reverse Proxy davor und nimmt die Zeile wieder heraus.
cap_add und sysctls geben dem Container Rechte, die ein Container normalerweise nicht hat: Netzwerkschnittstellen anlegen (NET_ADMIN), das WireGuard-Modul laden (SYS_MODULE, dafür auch der Lesezugriff auf /lib/modules) und Pakete zwischen Tunnel und Heimnetz weiterreichen (ip_forward). Ein VPN ist nun mal ein Stück Netzwerk, kein Webdienst. Und das eigene Netz wg mit IPv6 braucht wg-easy, damit es auch IPv6-Adressen an die Geräte im Tunnel verteilen kann. Läuft bei dir kein IPv6, stört das nicht; die Doku kennt für diesen Fall die Variable DISABLE_IPV6=true, die die IPv6-Regeln weglässt.
Schritt 2: Starten und nachsehen
docker compose up -d
docker compose psDer erste Aufruf lädt das Image, das dauert je nach Leitung eine Minute. Nach dem Start braucht wg-easy etwa eine Minute, bis es auf Port 51821 antwortet. Die zweite Zeile ist die Kontrolle. Sie soll ungefähr so aussehen:
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
wg-easy ghcr.io/wg-easy/wg-easy:15 "docker-entrypoint.s…" wg-easy About a minute ago Up About a minute (healthy) 0.0.0.0:51820->51820/udp, [::]:51820->51820/udp, 0.0.0.0:51821->51821/tcp, [::]:51821->51821/tcpSteht unter STATUS etwas anderes als Up, zeigt docker compose logs -f den Grund; Strg+C beendet die Anzeige. Eine Sache noch, bevor du weitergehst, und sie steht so in der wg-easy-Doku: Zum Anhalten und Starten nimmst du docker compose down und docker compose up -d, nicht stop und start. Der Container räumt beim Herunterfahren seine Netzwerkregeln auf, und stop lässt ihm dafür keine Gelegenheit.
Schritt 3: Der Setup-Assistent
Jetzt der Browser, auf einem Rechner im Heimnetz. Die Adresse ist die des Docker-Rechners mit Port 51821.
Stand wg-easy 15.4. Im Browser http://192.168.178.20:51821 öffnen. Es erscheint die Seite Willkommen zur Ersteinrichtung von wg-easy. Die Oberfläche spricht die Sprache deines Browsers, und vor dem Konto-Formular steht eine Begrüßungsseite, die du mit Weiter bestätigst. Dann der Reihe nach:
- Benutzername, Passwort und Passwort bestätigen für dein Admin-Konto eintragen, Konto erstellen. Der Assistent verlangt ein starkes Passwort.
- Die Frage Haben Sie eine bestehende Einrichtung? mit Nein beantworten. (Yes ist nur für den Umzug von Version 14, dort lädt man die alte
wg0.jsonhoch.) - Host: die MyFRITZ!-Adresse, im Beispiel
abc123xyz.myfritz.net. Das ist die Adresse, die später in jedem Handy-Profil steht, deshalb hier keine interne IP. - Port:
51820. Dann Weiter.
Danach erscheint erst eine Seite Einrichtung erfolgreich; ein Klick auf Anmelden führt zur Anmeldeseite. Mit dem eben angelegten Konto einloggen; du siehst die leere Client-Liste mit dem Button Neuer Client.



Wenn statt des Assistenten die Meldung mit „insecure connection" kommt, fehlt INSECURE=true oder der Container lief noch mit der alten Datei. Mehr dazu unten.
Schritt 4: Die FritzBox öffnet einen Port
Bis hierhin läuft alles im Heimnetz. Damit dein Handy von unterwegs anklopfen kann, muss die FritzBox UDP-Pakete auf Port 51820 an den Docker-Rechner durchreichen. Nur diesen einen Port, nur UDP, nur an diese eine Adresse.
Stand FRITZ!OS 8, Wortlaut nach der AVM-Wissensdatenbank. Im Browser http://fritz.box öffnen und anmelden. Dann Internet, Freigaben, Reiter Portfreigaben.
- Gerät für Freigaben hinzufügen klicken und in der Liste den Docker-Rechner auswählen (er heißt so, wie er sich bei der FritzBox gemeldet hat; die IP 192.168.178.20 steht daneben).
- Im Abschnitt Freigaben auf Neue Freigabe, dann Portfreigabe.
- Anwendung: Andere Anwendung. Bezeichnung:
wg-easy. Protokoll: UDP. Port an Gerät:51820. Port extern gewünscht:51820. - OK, dann Übernehmen. In der Liste steht jetzt eine Zeile mit dem Rechner, UDP 51820 und einem grünen Status.
Zwei Dinge, die hier nicht passieren: Es gibt keine Freigabe für 51821, die Oberfläche bleibt drinnen. Und es gibt keine Freigabe für TCP; WireGuard spricht nur UDP, ein TCP-Eintrag wäre eine offene Tür für nichts.
Schritt 5: Das Handy verbinden
Jedes Gerät, das in den Tunnel soll, ist in wg-easy ein Client mit eigenem Schlüssel. Fürs Handy geht das per QR-Code, für den Laptop per Datei. Die WireGuard-App gibt es für Android, iOS, Windows, macOS und Linux auf wireguard.com unter Installation, alle vom WireGuard-Projekt selbst.
In wg-easy: Neuer Client in der Mitte, oder oben rechts Neu. Name: handy-sakis oder wie das Gerät heißt. Ablaufdatum leer lassen, das Feld ist für Gäste gedacht, deren Zugang von selbst auslaufen soll. Client erstellen. Der neue Client erscheint in der Liste; seine Symbole tragen keine Beschriftung, das zweite öffnet den QR-Code.
Auf dem Handy: WireGuard-App öffnen, auf das Plus tippen, den Weg über den QR-Code wählen, den Code auf dem Bildschirm scannen, dem Tunnel einen Namen geben. Danach WLAN aus, Mobilfunk an, und den Schalter neben dem Tunnel umlegen.
Für den Laptop: Statt des QR-Codes das dritte Symbol, Konfiguration herunterladen, die Datei in der WireGuard-App als Tunnel importieren.



Und jetzt die Kontrolle, die zählt. Auf dem Handy im Mobilfunk mit aktivem Tunnel den Browser öffnen und http://192.168.178.1 aufrufen: Die Anmeldeseite deiner FritzBox erscheint, obwohl du nicht zu Hause bist. Wer lieber Zahlen sieht, macht es vom Laptop aus:
ping -c 3 192.168.178.164 bytes from 192.168.178.1: icmp_seq=1 ttl=64 time=38.2 ms
64 bytes from 192.168.178.1: icmp_seq=2 ttl=64 time=41.7 ms
64 bytes from 192.168.178.1: icmp_seq=3 ttl=64 time=36.9 msDie dreißig, vierzig Millisekunden sind der Umweg über den Mobilfunk. In wg-easy siehst du dasselbe von der anderen Seite: Beim Client stehen jetzt übertragene Bytes und der Zeitpunkt des letzten Handshakes. Das ist der Moment, in dem ein Anschluss zu Hause zu deinem Netz wird, egal wo du gerade stehst. Der darf kurz gefeiert werden.
Wichtig für den Test: Er geht nur von außen. Ein Handy im heimischen WLAN spricht die MyFRITZ!-Adresse an, die auf die FritzBox selbst zeigt, und viele Router reichen das nicht nach innen durch. Kein Tunnel im WLAN heißt also noch nichts; Mobilfunk ist die ehrliche Probe.
Was am Ende eingestellt ist
- Das Admin-Konto bekommt einen zweiten Faktor. Oben rechts das Menü, Account, dort Enable Two Factor Authentication: QR-Code mit einer Authenticator-App scannen, den sechsstelligen Code eingeben, bestätigen. Das Konto verwaltet die Schlüssel zu deinem ganzen Netz; ein Passwort allein wäre mir dafür zu wenig, auch im Heimnetz.
- Die Oberfläche bleibt drinnen.
INSECURE=trueist der Preis dafür, dass wg-easy ohne Zertifikat läuft, und der Preis ist nur zahlbar, solange Port 51821 keine Freigabe hat. Von unterwegs erreichst du die Oberfläche trotzdem: durch den Tunnel, unter derselben Adresse wie zu Hause. Das ist kein Trick, das ist genau der Zweck des Tunnels. - Was durch den Tunnel geht, entscheidest du pro Client. Beim Client auf Edit, Abschnitt Netzwerk, Feld Allowed IPs. Steht dort
0.0.0.0/0, ::/0, läuft der gesamte Verkehr des Handys durch dein Heimnetz, auch YouTube. Das schützt im Hotel-WLAN und kostet Upload zu Hause. Trägst du stattdessen192.168.178.0/24ein, geht nur der Heimnetz-Verkehr durch den Tunnel, alles andere wie bisher. Im Feld DNS daneben kannst du die Adresse deines Pi-hole eintragen; dann filtert es wie im WLAN auch unterwegs. - Updates kommen mit einem Befehl. Die Doku nennt
docker compose up -d --pull always, im Ordner der Compose-Datei; der Tag15sorgt dafür, dass dabei keine 16 hereinkommt. Wer es automatisch will, findet in der Doku ein Watchtower-Beispiel. Ich würde bei einem VPN von Hand updaten, einmal im Monat, nach einem Blick in die Release Notes. Ein Tunnel, der nach einem nächtlichen Update nicht mehr aufgeht, fällt dir erst auf, wenn du ihn brauchst. - Das Backup ist ein Volume. Alles, was wg-easy weiß, liegt im Docker-Volume
etc_wireguard: Schlüssel, Clients, dein Admin-Konto. Ein Verlust bedeutet neue Schlüssel und neue QR-Codes auf jedem Gerät. Der Admin-Bereich hat dafür einen eigenen Punkt Backup & Restore; die Sicherungsdatei gehört an einen Ort außerhalb dieses Rechners. Du weißt, dass dieser Satz kommt, und ich schreibe ihn trotzdem hin.
Wo es klemmt
„You can't log in with an insecure connection. Use HTTPS." Der häufigste Treffer in den Discussions des Projekts, gleich mehrfach mit demselben Titel. Zwei Ursachen: Entweder fehlt INSECURE=true in der Compose-Datei, oder sie steht drin, aber der Container lief noch mit der alten Fassung. In einem der Threads löste der Maintainer den Fall mit einer Gegenfrage: „Did you restart your container after editing the docker compose?" Die Antwort war ein Neustart. Also docker compose down, dann docker compose up -d, und die Variable greift.
Handshake da, aber kein Internet durch den Tunnel. Der Client verbindet sich, ping 10.8.0.1 antwortet, aber Webseiten laden nicht. In Discussion #2503 lag es an der Weiterleitung auf dem Host: Die Regeln, die den Tunnel-Verkehr auf die richtige Netzwerkkarte übersetzen, passten nicht zur tatsächlichen Schnittstelle. Der Verfasser hat im Admin-Bereich unter Interface das Feld für die Schnittstelle auf den echten Namen gesetzt, bei ihm eno1; welcher es bei dir ist, verrät ip route in der Zeile mit default via. Wer nur das Heimnetz braucht, umgeht das ganze Thema mit den Allowed IPs aus Punkt 3.
DS-Lite: Die Freigabe ist da, aber nichts kommt an. Wenn der Online-Monitor keine echte IPv4-Adresse zeigt, hilft keine noch so richtige Portfreigabe, weil die Pakete beim Anbieter hängen bleiben. Drei Auswege, in dieser Reihenfolge: beim Anbieter eine echte IPv4-Adresse erfragen, das gibt es oft kostenlos auf Nachfrage; die Freigabe als IPv6-Freigabe anlegen, dann klappt es nur aus Netzen, die IPv6 können, was im Mobilfunk in Deutschland meist der Fall ist; oder ein Dienst wie Tailscale, der ohne offenen Port auskommt, weil beide Seiten nach draußen wählen. Der bekommt hier einen eigenen Beitrag.
Das Modul fehlt. Auf älteren Kerneln oder in manchen Containern auf einem NAS meldet das Log, dass WireGuard im Kernel nicht verfügbar ist. Seit 15.2.2 fällt wg-easy dann auf eine Userspace-Fassung zurück; es läuft, nur mit mehr CPU-Last. Auf einem Proxmox-LXC ist es meist einfacher, WireGuard auf dem Host zu laden, damit der Container es sieht.
Ein VPN ist der Schritt, ab dem ein Homelab nicht mehr nur zu Hause funktioniert. Und er ist der Grund, warum ich bei jeder anderen Anleitung ruhig schlafen kann, wenn ich schreibe: keine Freigabe für diesen Dienst. Die eine für UDP 51820 ersetzt sie alle.
Welches Gerät hängt bei dir als Erstes im Tunnel, und wofür: Nextcloud, Pi-hole, oder einfach der Blick aufs Dashboard, ob zu Hause noch alles läuft? Schreib's in die Kommentare.
Wer die Oberfläche lieber mit echtem HTTPS und einem Namen wie vpn.heimnetz.lan erreichen will, findet den Anfang dazu im Beitrag Was ist ein Reverse Proxy?; im Newsletter melde ich mich, sobald der Tailscale-Beitrag für die DS-Lite-Anschlüsse fertig ist.
Quellen
- wg-easy-Doku: Getting Started (Voraussetzungen, Image-Tags, up/down statt start/stop)
- wg-easy-Doku: Basic Installation (Docker Compose)
- wg-easy: offizielle docker-compose.yml
- wg-easy-Doku: No Reverse Proxy (INSECURE)
- wg-easy-Doku: Optional Config (PORT, HOST, INSECURE, DISABLE_IPV6)
- wg-easy-Doku: Setup-Assistent
- wg-easy-Doku: Zwei-Faktor-Anmeldung
- wg-easy-Doku: Auto Updates
- wg-easy: Releases (15.4.0 vom 14-08-2026, 15.2.2 mit Userspace-Modus)
- wg-easy Discussion #2039: „You can't log in with an insecure connection"
- wg-easy Discussion #2503: Verbindung steht, aber kein Internet
- AVM-Wissensdatenbank: Statische Portfreigaben in FRITZ!Box einrichten
- AVM: MyFRITZ!-Konto erstellen und in FRITZ!Box einrichten
- WireGuard: Installation der Apps