WireGuard gehört zu den schnellsten und modernsten VPN-Lösungen. Die manuelle Verwaltung von Schlüsseln, Konfigurationsdateien und Clients kann jedoch schnell unübersichtlich werden.
Mit wg-easy lässt sich ein vollständiger WireGuard-Server inklusive übersichtlicher Weboberfläche als Docker-Container betreiben. Neue VPN-Clients können mit wenigen Klicks erstellt, als Konfigurationsdatei heruntergeladen oder direkt per QR-Code auf ein Smartphone übertragen werden.
In dieser Anleitung installieren wir wg-easy mit Docker Compose auf einem Linux-Server oder VPS. Die Verwaltungsoberfläche wird dabei zunächst nicht öffentlich ins Internet gestellt, sondern sicher über einen SSH-Tunnel geöffnet.
Was ist wg-easy?
wg-easy kombiniert zwei Komponenten in einem Container:
- einen vollständigen WireGuard-VPN-Server
- eine browserbasierte Verwaltungsoberfläche
Über die Weboberfläche können unter anderem:
- WireGuard-Clients erstellt und gelöscht werden
- Clients vorübergehend deaktiviert werden
- QR-Codes für Smartphones angezeigt werden
- WireGuard-Konfigurationen heruntergeladen werden
- verbundene Clients überprüft werden
- übertragene Daten angezeigt werden
- zeitlich begrenzte Clients angelegt werden
- Zwei-Faktor-Authentifizierung aktiviert werden
Zusätzlich unterstützt wg-easy IPv6, Prometheus-Metriken und serverseitige Firewall-Regeln pro Client.
Voraussetzungen
Für diese Anleitung benötigen wir:
- einen Linux-Server oder VPS
- Ubuntu 24.04 oder eine vergleichbare Linux-Distribution
- eine öffentliche IPv4- oder IPv6-Adresse
- SSH-Zugriff auf den Server
- Docker und Docker Compose
- einen geöffneten UDP-Port für WireGuard
- optional einen DNS-Namen wie
vpn.example.de
wg-easy unterstützt aktuell die Architekturen x86_64 und arm64. Damit kann es sowohl auf typischen VPS-Systemen als auch auf ARM-Servern wie einem Raspberry Pi betrieben werden.
Docker installieren
Falls Docker noch nicht installiert ist, kann die offizielle Installationsroutine verwendet werden:
curl -fsSL https://get.docker.com | sudo sh
Anschließend fügen wir unseren Benutzer der Docker-Gruppe hinzu:
sudo usermod -aG docker "$USER"
Danach einmal abmelden und erneut per SSH anmelden.
Die Installation kontrollieren wir mit:
docker --version
docker compose version
Beide Befehle sollten eine installierte Version anzeigen.
Installationsverzeichnis erstellen
Wir legen ein eigenes Verzeichnis für den wg-easy-Stack an:
sudo mkdir -p /opt/stacks/wg-easy
sudo chown -R "$USER":"$USER" /opt/stacks/wg-easy
cd /opt/stacks/wg-easy
Die Verzeichnisstruktur sieht anschließend so aus:
/opt/stacks/wg-easy/
└── docker-compose.yml
Docker-Compose-Datei erstellen
Nun erstellen wir die Compose-Datei:
nano docker-compose.yml
Folgenden Inhalt einfügen:
volumes:
etc_wireguard:
services:
wg-easy:
image: ghcr.io/wg-easy/wg-easy:15
container_name: wg-easy
restart: unless-stopped
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"
- "127.0.0.1:51821:51821/tcp"
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::/64
Die Konfiguration orientiert sich an der offiziellen Compose-Datei von wg-easy. Das Projekt empfiehlt, für stabile Installationen den Major-Tag 15 anstelle eines unbestimmten Tags wie latest zu verwenden. Dadurch werden Updates innerhalb der Hauptversion installiert, ohne automatisch auf eine möglicherweise inkompatible neue Hauptversion zu wechseln.
Warum wird Port 51821 nur an localhost gebunden?
Die Zeile
- "127.0.0.1:51821:51821/tcp"
sorgt dafür, dass die Weboberfläche nur auf dem Server selbst erreichbar ist.
Der Verwaltungsport wird dadurch nicht direkt im Internet veröffentlicht. Für die Ersteinrichtung verwenden wir stattdessen einen verschlüsselten SSH-Tunnel.
Der eigentliche WireGuard-Port bleibt dagegen öffentlich erreichbar:
- "51820:51820/udp"
wg-easy starten
Vor dem Start prüfen wir die Compose-Datei:
docker compose config
Werden keine Fehler angezeigt, starten wir den Container:
docker compose up -d
Den Status überprüfen wir mit:
docker compose ps
Die laufenden Protokolle können wir mit folgendem Befehl anzeigen:
docker compose logs -f
Die Ausgabe wird mit Strg + C beendet.
Firewall konfigurieren
Für den WireGuard-Tunnel muss standardmäßig der UDP-Port 51820 erreichbar sein.
Bei Verwendung von UFW öffnen wir ihn mit:
sudo ufw allow 51820/udp
Falls SSH noch nicht freigegeben wurde:
sudo ufw allow OpenSSH
Anschließend kann die Firewall aktiviert werden:
sudo ufw enable
Den Status prüfen wir mit:
sudo ufw status
Port 51821/tcp muss nicht freigegeben werden, da die Weboberfläche nur über localhost und den SSH-Tunnel erreichbar ist. Die offizielle Dokumentation nennt UDP-Port 51820 als notwendigen externen WireGuard-Port.
Bei einem VPS muss der Port möglicherweise zusätzlich in der Firewall oder Sicherheitsgruppe des Hosting-Anbieters freigeschaltet werden.
SSH-Tunnel zur Weboberfläche aufbauen
Auf dem eigenen Computer öffnen wir ein Terminal und bauen einen SSH-Tunnel zum VPS auf:
ssh -L 51821:127.0.0.1:51821 benutzer@SERVER-IP
Beispiel:
ssh -L 51821:127.0.0.1:51821 [email protected]
Bei Verwendung eines SSH-Schlüssels:
ssh -i ~/.ssh/id_ed25519 \
-L 51821:127.0.0.1:51821 \
[email protected]
Solange diese SSH-Verbindung geöffnet bleibt, erreichen wir die wg-easy-Weboberfläche im Browser unter:
http://127.0.0.1:51821
Die Verbindung zur Weboberfläche läuft dabei durch den verschlüsselten SSH-Tunnel.
Ersteinrichtung durchführen
Beim ersten Aufruf startet der Einrichtungsassistent.
Zunächst legen wir den Administrator fest:
- Benutzername
- Passwort
- Passwortbestätigung
Danach folgt die Konfiguration des WireGuard-Servers.
Host
Als Host tragen wir die Adresse ein, über die sich die VPN-Clients später verbinden.
Das kann beispielsweise eine Domain sein:
vpn.example.de
Alternativ kann die öffentliche IPv4-Adresse des Servers verwendet werden:
203.0.113.10
Bei einer direkten IPv6-Adresse müssen laut Dokumentation eckige Klammern verwendet werden:
[2001:db8:1234::10]
Port
Als Port verwenden wir:
51820
Der hier konfigurierte Port muss mit der Portfreigabe im Docker-Compose-Stack und in der Firewall übereinstimmen.
Nach Abschluss des Assistenten wird die WireGuard-Schnittstelle automatisch eingerichtet.
Einen WireGuard-Client erstellen
Nach der Anmeldung sehen wir die Clientübersicht.
Über die Schaltfläche zum Erstellen eines neuen Clients vergeben wir einen Namen, beispielsweise:
Notebook
oder:
Smartphone
wg-easy erzeugt anschließend automatisch:
- einen privaten Schlüssel
- einen öffentlichen Schlüssel
- eine interne VPN-Adresse
- eine vollständige WireGuard-Konfiguration
Für jeden Client stehen mehrere Möglichkeiten zur Verfügung.
Konfigurationsdatei herunterladen
Für einen Desktop-PC oder ein Notebook laden wir die Konfiguration als Datei herunter.
Die Datei trägt beispielsweise den Namen:
Notebook.conf
Diese Datei kann anschließend in den offiziellen WireGuard-Client importiert werden.
QR-Code verwenden
Auf Android oder iOS kann der QR-Code direkt mit der WireGuard-App gescannt werden.
Dazu:
- WireGuard-App öffnen
- neuen Tunnel hinzufügen
- „Aus QR-Code erstellen“ auswählen
- QR-Code aus wg-easy scannen
- Tunnel aktivieren
Der private Schlüssel ist Bestandteil des QR-Codes. Der QR-Code sollte deshalb niemals veröffentlicht oder an Dritte weitergegeben werden.
Verbindung testen
Nachdem der Tunnel auf dem Client aktiviert wurde, testen wir zunächst die öffentliche IP-Adresse.
Auf einem Linux-Client beispielsweise:
curl https://ifconfig.me
Wird die öffentliche IP-Adresse des VPN-Servers angezeigt, wird der gesamte Internetverkehr über WireGuard geleitet.
Zusätzlich kann die interne WireGuard-Adresse des Servers getestet werden:
ping 10.8.0.1
Die tatsächliche Adresse hängt von den im Einrichtungsassistenten gewählten Einstellungen ab.
In der wg-easy-Weboberfläche sollte der Client nach dem ersten erfolgreichen Handshake als verbunden erscheinen.
Split-Tunneling oder vollständiger VPN-Tunnel
Über die Einstellung Allowed IPs wird festgelegt, welcher Datenverkehr über den Tunnel geleitet wird.
Gesamten IPv4-Verkehr über das VPN leiten
0.0.0.0/0
Gesamten IPv4- und IPv6-Verkehr über das VPN leiten
0.0.0.0/0, ::/0
Nur ein internes Netzwerk erreichbar machen
192.168.10.0/24
Mehrere interne Netze verwenden
192.168.10.0/24, 192.168.20.0/24
Wichtig: Allowed IPs beeinflusst in erster Linie das Routing auf dem Client. Für echte serverseitige Zugriffsbeschränkungen sollte die per-Client-Firewall von wg-easy oder eine eigene Firewall verwendet werden.
Die per-Client-Firewall kann in der Administration aktiviert werden und erzwingt die erlaubten Ziele auf dem Server. Diese Funktion benötigt iptables beziehungsweise bei IPv6 zusätzlich ip6tables und wird in der Dokumentation derzeit noch als experimentell bezeichnet.
Clients über die Kommandozeile anzeigen
wg-easy besitzt zusätzlich eine CLI.
Die interaktive CLI starten wir mit:
cd /opt/stacks/wg-easy
docker compose exec -it wg-easy cli
Die vorhandenen Clients können dort aufgelistet werden:
clients:list
Der QR-Code eines Clients lässt sich ebenfalls über die Kommandozeile anzeigen:
clients:qr CLIENT-ID
Die entsprechende Client-ID ist in der Ausgabe von clients:list enthalten.
Administrator-Passwort zurücksetzen
Falls das Administrator-Passwort vergessen wurde, kann es über die CLI zurückgesetzt werden:
cd /opt/stacks/wg-easy
docker compose exec -it wg-easy cli db:admin:reset
Danach fordert wg-easy zur Eingabe eines neuen Passworts auf.
Alternativ kann das Passwort direkt als Argument übergeben werden:
docker compose exec -it wg-easy \
cli db:admin:reset --password 'NEUES-SICHERES-PASSWORT'
Die interaktive Variante ist sicherer, weil das Passwort dann nicht in der Shell-History gespeichert wird.
wg-easy aktualisieren
Vor einem Update wechseln wir in das Stack-Verzeichnis:
cd /opt/stacks/wg-easy
Anschließend laden wir das aktuelle Image der verwendeten Hauptversion:
docker compose pull
Danach wird der Container neu erstellt:
docker compose up -d
Nicht mehr benötigte Images können anschließend entfernt werden:
docker image prune
Die offizielle Dokumentation empfiehlt für das Starten und Aktualisieren docker compose up beziehungsweise für das vollständige Entfernen docker compose down. docker compose start und stop sollen vermieden werden, da dabei inkonsistente Containerzustände entstehen können.
Backup erstellen
Die WireGuard-Konfiguration liegt in unserem Beispiel im Docker-Volume:
etc_wireguard
Zunächst ermitteln wir den tatsächlichen Namen:
docker volume ls | grep etc_wireguard
Anschließend erstellen wir ein Backup:
mkdir -p ~/backups
docker run --rm \
-v wg-easy_etc_wireguard:/source:ro \
-v "$HOME/backups":/backup \
alpine \
tar -czf /backup/wg-easy-$(date +%F).tar.gz -C /source .
Der Volume-Name wg-easy_etc_wireguard muss gegebenenfalls an die Ausgabe von docker volume ls angepasst werden.
Das Backup enthält sensible private Schlüssel. Es sollte daher verschlüsselt und ausschließlich an einem geschützten Speicherort aufbewahrt werden.
Weboberfläche dauerhaft über Traefik bereitstellen
Soll die Verwaltungsoberfläche später über eine Domain wie
https://vpn-admin.example.de
erreichbar sein, kann wg-easy hinter einem Reverse Proxy wie Traefik betrieben werden.
Dabei sollte Port 51821 nicht direkt am Host veröffentlicht werden. Stattdessen befinden sich Traefik und wg-easy in einem gemeinsamen Docker-Netzwerk. Traefik leitet HTTPS-Anfragen intern an Port 51821 des Containers weiter.
Die wg-easy-Dokumentation stellt dafür eine eigene Traefik-Anleitung bereit. Der dort gezeigte Dienst verwendet den internen Webport des Containers und ein gemeinsames externes Docker-Netzwerk.
Auch mit Reverse Proxy sollte die Verwaltungsoberfläche zusätzlich geschützt werden, beispielsweise durch:
- die integrierte wg-easy-Anmeldung
- Zwei-Faktor-Authentifizierung
- eine IP-Allowlist
- Authelia oder Authentik
- Zugriff ausschließlich über das bereits bestehende VPN
Eine unverschlüsselte, öffentlich erreichbare Weboberfläche sollte vermieden werden. Die wg-easy-Dokumentation bezeichnet den Betrieb ohne Reverse Proxy und ohne HTTPS ausdrücklich als unsicher.
Wichtige Sicherheitshinweise
Beim Betrieb von wg-easy sollten einige Grundregeln beachtet werden:
- Die Weboberfläche nicht ungeschützt im Internet veröffentlichen.
- Ein langes und einzigartiges Administrator-Passwort verwenden.
- Nach Möglichkeit Zwei-Faktor-Authentifizierung aktivieren.
- Nur UDP-Port
51820öffentlich freigeben. - WireGuard-Konfigurationen und QR-Codes vertraulich behandeln.
- Nicht mehr benötigte Clients deaktivieren oder löschen.
- Regelmäßig Updates und Backups durchführen.
- Für produktive Systeme einen festen Major-Version-Tag verwenden.
- Den SSH-Zugriff ausschließlich mit Schlüsseln absichern.
- Zugriffsbeschränkungen tatsächlich testen und nicht nur konfigurieren.
Fazit
wg-easy macht den Betrieb eines eigenen WireGuard-VPN-Servers deutlich komfortabler. Besonders das Erstellen neuer Clients, der Export von Konfigurationsdateien und die QR-Code-Funktion erleichtern die tägliche Verwaltung.
Mit Docker Compose ist der Dienst schnell installiert und ebenso einfach aktualisiert. Wird die Weboberfläche nur über einen SSH-Tunnel, einen abgesicherten Reverse Proxy oder direkt über das VPN erreichbar gemacht, lässt sich wg-easy auch auf einem öffentlich erreichbaren VPS sicher betreiben.
Damit eignet sich wg-easy sowohl für den privaten Fernzugriff auf das Heimnetz als auch für den geschützten Zugriff auf Server, interne Anwendungen und Verwaltungsoberflächen.
