SSD Nodes Learn 8GB RAM — $66/Jahr
Anleitungen Matt ConnorVon Matt Connor · Aktualisiert 2026-08-01

wg-easy mit Docker: WireGuard-Weboberfläche einrichten

Richten Sie WireGuard mit wg-easy und Docker Compose ein: Ports, NET_ADMIN, wichtige sysctl-Werte und QR-Codes für die Einrichtung auf Smartphones.

Was Sie einrichten

wg-easy ist WireGuard mit einer Weboberfläche und läuft als einzelner Docker-Container. Es verwaltet die WireGuard-Schnittstelle für Sie und stellt eine Browseroberfläche zum Erstellen von Clients bereit. Jeder erstellte Client erhält eine Konfigurationsdatei und einen QR-Code. Ein Smartphone kann dem VPN beitreten, indem Sie die Kamera auf den Bildschirm richten.

Der Tunnel selbst ist gewöhnliches WireGuard. Das Kernelmodul überträgt die Pakete, daher ist der Datendurchsatz genauso hoch wie bei einer manuell erstellten Einrichtung. Sie gewinnen eine Verwaltung des Client-Lebenszyklus: Peers hinzufügen, deaktivieren und löschen, ohne eine Konfigurationsdatei über SSH zu bearbeiten. Sie geben dafür die direkte Kontrolle über diese Konfiguration auf. Dieses Thema wird in der manuellen WireGuard-Einrichtung auf einem VPS behandelt.

Sie benötigen einen KVM-VPS mit einer öffentlichen IPv4-Adresse, Docker Engine mit dem Compose-Plugin und root-Zugriff. Container-Virtualisierung, die den Kernel des Hosts gemeinsam nutzt, kann das WireGuard-Modul normalerweise nicht laden. Dazu gehören beispielsweise OpenVZ und LXC. Der Container kann die Schnittstelle dann nicht aktivieren.

Version 15 hat die Einstellungen aus der Umgebung verschoben

Die meisten Anleitungen, die Sie finden, wurden für wg-easy 14 geschrieben. Dort setzen Sie WG_HOST auf die Adresse Ihres Servers und PASSWORD_HASH auf einen bcrypt-Hash des Administratorpassworts. Beide Werte werden als Umgebungsvariablen gesetzt. Version 15 ist eine Neufassung. In den offiziellen Migrationshinweisen steht ausdrücklich, dass v15 nicht dieselben Umgebungsvariablen wie v14 verwendet und dass die meisten davon in das Admin-Panel der Weboberfläche verschoben wurden.

WG_HOST und PASSWORD_HASH haben daher keine Wirkung mehr. Wenn Sie eine alte Compose-Datei kopieren, startet der Container, ignoriert diese Zeilen und fordert Sie anschließend im Browser auf, ein Administratorkonto anzulegen. Das ist kein Fehler. Dies ist der neue Einrichtungsablauf.

Ab Juli 2026 sollten Sie als Major-Tag 15 festlegen. Verwenden Sie nicht latest, sondern pinnen Sie die Major-Version, weil ein Major-Upgrade das Format der Konfiguration auf der Festplatte ändert und kein sauberes Rollback ermöglicht.

Die Compose-Datei

Erstellen Sie ein Verzeichnis für den Stack und schreiben Sie die offizielle Compose-Datei hinein. Dies ist die unveränderte Datei aus dem Upstream-Projekt.

sudo mkdir -p /etc/docker/containers/wg-easy
sudo curl -o /etc/docker/containers/wg-easy/docker-compose.yml \
  https://raw.githubusercontent.com/wg-easy/wg-easy/master/docker-compose.yml

Der Inhalt sieht so aus:

volumes:
  etc_wireguard:

services:
  wg-easy:
    image: ghcr.io/wg-easy/wg-easy:15
    container_name: wg-easy
    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::/64

etc_wireguard ist ein benanntes Volume, das den Serverschlüssel und jeden von Ihnen erstellten Client enthält. Sichern Sie dieses Volume, da bei einer Neuerstellung alle Ihre Peers verworfen werden. Wenn Sie diese Dateien stattdessen im Host-Dateisystem sehen möchten, ersetzen Sie es durch einen Bind-Mount. Lesen Sie zuvor den Unterschied zwischen Bind-Mounts und benannten Volumes, da sich die Berechtigungen unterschiedlich verhalten.

Warum NET_ADMIN, SYS_MODULE und die sysctls erforderlich sind

Ein Container darf standardmäßig nicht auf den Netzwerk-Stack zugreifen. Jede dieser Zeilen hebt eine bestimmte Einschränkung auf.

NET_ADMIN ermöglicht dem Container, die Schnittstelle wg0 zu erstellen, ihr eine Adresse zuzuweisen und Routen zu schreiben. Ohne diese Berechtigung startet der Container und beendet sich anschließend beim Aktivieren der Schnittstelle, weil ip link add wg0 type wireguard Operation not permitted zurückgibt.

SYS_MODULE und der schreibgeschützte Mount /lib/modules ermöglichen dem Container, das WireGuard-Kernelmodul zu laden, wenn der Host es noch nicht geladen hat. Das Modul befindet sich im Host-Kernel, nicht im Image. Deshalb muss das Host-Verzeichnis sichtbar sein. Bei einem modernen Kernel ist das Modul normalerweise bereits integriert. Sie können dies auf dem Host mit sudo modprobe wireguard && echo ok überprüfen.

net.ipv4.ip_forward=1 weist den Kernel an, Pakete weiterzuleiten, die nicht an den Host selbst adressiert sind. Ohne diese Einstellung stellt ein Client die Verbindung her, der Handshake ist erfolgreich, und anschließend wird jedes Paket ins Internet verworfen. Daher läuft ping 1.1.1.1 ab, während die VPN-Verbindung als aktiv angezeigt wird.

net.ipv4.conf.all.src_valid_mark=1 ist die Einstellung, die viele überrascht. WireGuard markiert seine ausgehenden Pakete, damit sie nicht zurück in den Tunnel geroutet werden. Eine strikte Reverse-Path-Filterung erkennt ein Paket, dessen Quelladresse nicht zur erwarteten Route passt, und verwirft es. Diese sysctl weist den Kernel an, markierte Pakete zu akzeptieren. Dadurch wird verhindert, dass ein Full-Tunnel sich selbst unterbricht.

Starten und das Administratorkonto erstellen

cd /etc/docker/containers/wg-easy
sudo docker compose up -d
sudo docker compose logs -f

Verwenden Sie docker compose up und docker compose down, nicht start und stop. Upstream warnt davor, dass start bei einem Container, der unter anderen Einstellungen erstellt wurde, einen inkonsistenten Netzwerkzustand hinterlässt. Wenn der Stack nach einem Neustart wieder verfügbar sein soll, deckt restart: unless-stopped dies bereits ab. Das Startverhalten von Compose-Services erklärt, was diese Richtlinie zusichert und was nicht.

Die Weboberfläche lauscht auf TCP 51821. Beim ersten Aufruf wird eine Einrichtungsseite angezeigt. Dort erstellen Sie das Administratorkonto und bestätigen die Hostadresse, über die Clients den Server erreichen. Diese Hostadresse wird in der Endpoint-Zeile jeder Clientkonfiguration verwendet. Sie muss daher die öffentliche IP-Adresse oder der DNS-Name des VPS sein. Ist sie falsch, verweist der QR-Code, den Sie an ein Smartphone übergeben, auf ein nicht erreichbares Ziel. Der Handshake wird dann nicht abgeschlossen.

Noch ein Hinweis zu diesem Port: wg-easy 15 lehnt unverschlüsseltes HTTP ab, sofern Sie INSECURE=true nicht setzen. Der Zugriff über HTTPS mit einem nicht vertrauenswürdigen Zertifikat ist in Ordnung. Auch die TLS-Terminierung an einem vorgeschalteten Reverse-Proxy ist möglich. Der Zugriff über http:// mit den Standardeinstellungen ist dagegen nicht möglich.

Veröffentlichen Sie den UI-Port nicht im Internet

Die Compose-Datei veröffentlicht 51821 auf jeder Schnittstelle. Das ist eine Anmeldeseite für ein System, über das Ihr Datenverkehr weitergeleitet werden kann. Sie sollte nicht weltweit erreichbar sein. Wenn Docker einen Port veröffentlicht, schreibt es Regeln in die Kette DOCKER. Diese wird vor ufw ausgewertet. Daher schließt eine ufw-deny-Regel den Port nicht. Diese Falle ist wichtig genug, um sie separat zu verstehen. Warum von Docker veröffentlichte Ports ufw ignorieren behandelt das vollständig.

Die einfache Lösung besteht darin, die UI an loopback zu binden und sie über einen SSH-Tunnel zu erreichen:

    ports:
      - "51820:51820/udp"
      - "127.0.0.1:51821:51821/tcp"
    environment:
      - INSECURE=true

Führen Sie anschließend auf Ihrem Laptop Folgendes aus:

ssh -L 51821:127.0.0.1:51821 youruser@your.server.address

Öffnen Sie http://127.0.0.1:51821 im Browser auf Ihrem Laptop. Der Datenverkehr wird von SSH verschlüsselt. Der Port antwortet niemand anderem. INSECURE=true ist hier sicher, weil der unverschlüsselte HTTP-Abschnitt die loopback-Schnittstelle nicht verlässt.

UDP 51820 öffnen und beide Firewalls prüfen

WireGuard benötigt UDP 51820, damit der Port aus dem Internet erreichbar ist. Docker veröffentlicht den Port, aber viele Anbieter schalten eine separate Netzwerk-Firewall vor die VPS, von der Docker nichts weiß. Öffnen Sie den Port an beiden Stellen. Wenn Sie die Host-Firewall mit ufw verwalten, sind die grundlegenden ufw-Regeln für eine VPS der kürzere Weg, als nftables manuell zu konfigurieren.

Prüfen Sie, ob der Container tatsächlich lauscht:

sudo ss -ulnp | grep 51820

Sie sollten einen lauschenden UDP-Socket sehen. Wenn in dieser Zeile nichts angezeigt wird, hat der Container die Schnittstelle nicht aktiviert. sudo docker compose logs wg-easy nennt den Grund.

Einen Client erstellen und auf einem Telefon scannen

Erstellen Sie in der UI einen Client und geben Sie ihm einen Namen, den Sie später wiedererkennen, zum Beispiel den Namen des Geräts, zu dem er gehört. wg-easy weist die nächste freie Tunneladresse zu und generiert das Schlüsselpaar für Sie. Jede Clientzeile enthält einen QR-Code und eine herunterladbare .conf-Datei.

Installieren Sie die offizielle WireGuard-App auf dem Telefon. Wählen Sie das Hinzufügen eines Tunnels über einen QR-Code und richten Sie die Kamera auf den Code auf Ihrem Bildschirm. Der Tunnel wird mit dem eingegebenen Namen angezeigt. Aktivieren Sie ihn. In der Clientzeile der UI werden dann Übertragungszähler und eine aktuelle Handshake-Zeit angezeigt.

Ein Client, bei dem nach der Aktivierung kein Handshake angezeigt wird, erreicht den Server überhaupt nicht. Das weist auf UDP 51820 hin, entweder auf die Firewall des Providers oder auf die in der Konfiguration enthaltene Endpoint-Adresse. Ein Client mit Handshake, aber ohne funktionierenden Internetzugriff weist dagegen auf die Weiterleitung oder auf DNS hin.

Laden Sie auf einem Desktop die .conf-Datei herunter und importieren Sie sie in den WireGuard-Client, anstatt die Konfiguration erneut einzugeben. Der private Schlüssel in dieser Datei wird einmal generiert und einmal angezeigt. Behandeln Sie die Datei wie einen privaten SSH-Schlüssel.

Wann die UI nicht mehr ausreicht

wg-easy ist das richtige Tool, solange Ihre Peers Personen und Telefone sind. Die UI ist schneller als das Bearbeiten von Konfigurationsdateien. Ein verlorenes Telefon widerrufen Sie mit einem Klick.

Die Grenzen erreichen Sie, sobald Sie etwas benötigen, das die UI nicht abbildet. Site-to-Site-Routing ist meist die erste Hürde. Dabei deckt AllowedIPs eines Peers ein gesamtes entferntes Subnetz statt nur eine einzelne Adresse ab. Danach folgen Split-Tunnel-Konfigurationen mit Peer-spezifischen Routingregeln oder eine Konfiguration, die Ihr Provisioning-Tool erzeugt. An diesem Punkt ist die manuell erstellte Konfiguration nicht schwieriger. Sie ist nur anders. Der WireGuard-Leitfaden ohne UI zeigt denselben Tunnel mit wg0.conf. Wenn Sie die Control Plane nicht mehr selbst betreiben möchten, beschreibt WireGuard im Vergleich zu Tailscale die verwaltete Option.

Wenn die Compose-Syntax oben für Sie ungewohnt war und nicht WireGuard selbst, erklärt Docker-Compose-Grundlagen auf einem VPS das Dateiformat und die üblichen Befehle.

FAQ

Warum ignoriert wg-easy meine Variablen WG_HOST und PASSWORD_HASH?

Diese Variablen gehören zu wg-easy 14. Version 15 wurde neu geschrieben, und das Upstream-Projekt hat fast die gesamte Konfiguration in das Admin-Panel der Weboberfläche verschoben. Der Container liest keine der beiden Variablen, startet daher normal und fordert Sie beim ersten Aufruf auf, ein Administratorkonto zu erstellen. Legen Sie die clientseitig verwendete Hostadresse stattdessen auf dieser Einrichtungsseite fest.

Benötige ich SYS_MODULE, wenn mein Kernel WireGuard bereits unterstützt?

Nein. SYS_MODULE und der Mount /lib/modules sind vorhanden, damit der Container das Modul laden kann, wenn der Host dies nicht bereits unterstützt. Auf einem Host, auf dem sudo modprobe wireguard bereits erfolgreich ausgeführt wird, bleibt diese Fähigkeit ungenutzt. Das Entfernen ist eine sinnvolle Härtungsmaßnahme. NET_ADMIN wird in jedem Fall weiterhin benötigt.

Der Client stellt eine Verbindung her, aber es gibt keine Internetverbindung. Was ist falsch?

Ein Handshake ohne Datenverkehr weist fast immer auf die Weiterleitung hin. Stellen Sie sicher, dass net.ipv4.ip_forward=1 und net.ipv4.conf.all.src_valid_mark=1 noch in der Compose-Datei enthalten sind, da sie in einer manuell bearbeiteten Kopie häufig verloren gehen. Wenn die Weiterleitung aktiviert ist, prüfen Sie den DNS-Server, den der Client erhalten hat. Ein Tunnel, der den gesamten Datenverkehr über das VPN leitet, aber auf einen DNS-Server verweist, den er nicht mehr erreichen kann, sieht im Browser genau wie eine nicht funktionierende Verbindung aus.

Wie sichere ich meine Clients?

Alle Daten befinden sich im benannten Volume etc_wireguard, in einer wg0.json-Datei. Die Benutzeroberfläche enthält außerdem eine Schaltfläche zum Sichern, die dieselben Daten exportiert. Kopieren Sie diese Datei vor jedem Upgrade an einen Speicherort außerhalb des Servers. Die Wiederherstellung erfolgt durch einen Upload während des Einrichtungsschritts eines neuen Containers.

Kann ich wg-easy hinter einem Reverse Proxy betreiben?

Ja. Schalten Sie den Proxy vor TCP 51821, beenden Sie TLS dort und setzen Sie INSECURE=true im Container, damit dieser den unverschlüsselten HTTP-Hop vom Proxy akzeptiert. Veröffentlichen Sie UDP 51820 weiterhin direkt, da der VPN-Datenverkehr UDP verwendet und keinen HTTP-Proxy durchläuft.