Zum Hauptinhalt springen
S-EDV news
← Alle Anleitungen
📘 Anleitung Server & Netzwerk 06.08.2026 · 9 min Lesezeit

wg-easy mit Docker installieren: WireGuard-VPN mit Web-UI in einem Container

wg-easy 15 mit Docker Compose einrichten: Admin-Konto über Setup-Assistent oder INIT-Variablen, Weboberfläche nur an 127.0.0.1, INSECURE richtig setzen, ersten Client anlegen und Tunnel prüfen.

Geprüft am 25.10.2026 · für wg-easy 15.5.0

WerbelinksMit * markierte Links sind Werbelinks: Bei einem Kauf erhalten wir eine Provision, der Preis bleibt gleich. Als Amazon-Partner verdiene ich an qualifizierten Verkäufen. Mehr dazu

Silberner Mini-Server auf einem hellen Schreibtisch, über ein leuchtendes Kabel mit einem Laptop und einem Smartphone verbunden

wg-easy verbindet einen WireGuard-Server mit einer Weboberfläche, in der Sie VPN-Clients anlegen, sperren und per QR-Code verteilen. Version 15 ist eine Neuentwicklung: Die bekannten Variablen WG_HOST und PASSWORD_HASH aus Version 14 wirken nicht mehr, das Admin-Konto entsteht in einem Setup-Assistenten oder über INIT_*-Variablen, und die meisten Einstellungen liegen jetzt in der Admin-Konsole. Diese Anleitung richtet wg-easy 15 nach der offiziellen Dokumentation mit Docker Compose auf einem Linux-Server ein, mit Weboberfläche nur an 127.0.0.1 und einem getesteten Tunnel.

Voraussetzungen

  • Linux-Server oder VPS mit x86_64 oder ARM64; armv6 und armv7 unterstützt Version 15 nicht mehr
  • 1 bis 2 CPU-Kerne und 1 GB RAM genügen für wg-easy, auf einem Server mit 2 Kernen und 4 GB RAM bleibt Platz für weitere Dienste
  • etwa 300 MB Speicher für Image und Datenbank
  • öffentliche IPv4-Adresse oder DNS-Name, UDP-Port 51820 in Firewall und gegebenenfalls Router freigegeben
  • Kernel mit WireGuard-Modul; prüfen mit modinfo wireguard. Ab Version 15.2.2 bringt das Image zusätzlich wireguard-go als Userspace-Ausweichlösung mit
  • Docker Engine mit Compose-Plugin v2, siehe Docker-Installation; Grundschutz des Servers siehe VPS absichern mit UFW, SSH-Keys und Fail2Ban

Eckdaten

PunktWert
Imageghcr.io/wg-easy/wg-easy:15 (neueste 15.x, getestet 15.5.0)
Ports51820/udp WireGuard, 51821/tcp Weboberfläche
Volumeetc_wireguard:/etc/wireguard mit wg-easy.db und wg0.conf
RechteNET_ADMIN, SYS_MODULE, Sysctls für IP-Forwarding
Wichtige VariablenINSECURE, INIT_*, PORT, HOST, DISABLE_IPV6
Standardnetz der ClientsIPv4 10.8.0.0/24, DNS 1.1.1.1

Schritt 1: Kernelmodul und Projektordner

Prüfen Sie, ob der Kernel WireGuard mitbringt, und legen Sie den Projektordner an:

modinfo wireguard | head -1
sudo mkdir -p /opt/wg-easy
cd /opt/wg-easy

Das Modul muss nicht geladen sein. Im Test lud der Container es beim ersten Start selbst; dafür sind die Rechte SYS_MODULE und der Nur-lese-Mount /lib/modules in der Compose-Datei gedacht.

Verifizieren: modinfo gibt eine Zeile wie filename: /lib/modules/…/wireguard.ko.zst aus. Fehlt das Modul, meldet wg-easy später laut FAQ Cannot find device "wg0".

Schritt 2: Compose-Datei

Die Datei entspricht dem offiziellen docker-compose.yml des Projekts mit zwei Änderungen: Die Weboberfläche lauscht nur auf 127.0.0.1, und die Umgebungsvariablen sind gesetzt. Legen Sie /opt/wg-easy/compose.yaml an:

services:
  wg-easy:
    image: ghcr.io/wg-easy/wg-easy:15
    container_name: wg-easy
    environment:
      - INSECURE=true            # nur für Zugriff per SSH-Tunnel über HTTP
      - INIT_ENABLED=true
      - INIT_USERNAME=vpnadmin
      - INIT_PASSWORD=${WG_INIT_PASSWORD}
      - INIT_HOST=vpn.example.com
      - INIT_PORT=51820
    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"
    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

volumes:
  etc_wireguard:

Das Passwort legen Sie in einer .env im selben Ordner ab, damit es nicht im Compose-Text steht:

echo "WG_INIT_PASSWORD='$(openssl rand -base64 24)'" | sudo tee /opt/wg-easy/.env
sudo chmod 600 /opt/wg-easy/.env

Ersetzen Sie vpn.example.com durch den Namen oder die IP, unter der Clients den Server erreichen. Wer lieber den Assistenten nutzt, lässt die fünf INIT_-Zeilen weg. Verwendet Ihr Netz bereits 10.42.42.0/24, wählen Sie ein anderes Subnetz und passen ipv4_address an.

Verifizieren: docker compose config --quiet endet ohne Ausgabe, und docker compose config | grep INIT_PASSWORD zeigt das erzeugte Passwort statt eines leeren Werts.

Schritt 3: Starten und Log prüfen

docker compose up -d
docker compose logs --no-log-prefix | grep -E "wg-easy:|initial|wg0 started"

Laut Dokumentation starten und stoppen Sie wg-easy nur mit docker compose up und docker compose down, nicht mit start und stop, sonst bleibt ein inkonsistenter Zustand zurück.

Verifizieren: Das Log zeigt im Kasten wg-easy: v15.5.0 (oder neuer), dann Creating initial user..., Setting initial host and port... und Wireguard Interface wg0 started successfully.. ss -ltn | grep 51821 zeigt nur 127.0.0.1:51821.

Schritt 4: Anmelden und Ersteinrichtung

Öffnen Sie von Ihrem Rechner aus einen SSH-Tunnel und dann http://127.0.0.1:51821 im Browser:

ssh -N -L 51821:127.0.0.1:51821 benutzer@ihr-server

Mit vollständigen INIT_-Variablen landen Sie direkt auf der Anmeldeseite. Ohne sie führt der Assistent durch vier Seiten: Willkommen, Admin-Konto (Benutzername, Passwort, Bestätigung), die Frage „Haben Sie eine bestehende Einrichtung?“ und schließlich Host und Port. „Ja“ bei der dritten Frage importiert eine wg0.json aus Version 14. Der Assistent verlangt mindestens 12 Zeichen und meldet sonst „Passwort muss mindestens 12 Zeichen lang sein“. INIT_PASSWORD prüft wg-easy laut Doku nicht; ist es zu kurz, scheitert später die Anmeldung.

Nach der Anmeldung aktivieren Sie über das Benutzermenü oben rechts unter Konto die Zwei-Faktor-Anmeldung per TOTP. Entfernen Sie danach die INIT_-Zeilen und die .env, wie es die Doku empfiehlt; beim nächsten Start meldet das Log ohnehin Setup already done. Skiping initial setup.

Verifizieren: Nach der Anmeldung zeigt die Startseite „Es gibt noch keine Clients.“. Ein Anmeldeversuch mit falschem Passwort liefert „Invalid username or password“.

Schritt 5: Ersten Client anlegen und Tunnel testen

Klicken Sie auf Neu, vergeben Sie einen Namen wie laptop-mueller und speichern Sie. Den Client übernehmen Sie per QR-Code in die WireGuard-App auf dem Smartphone oder laden die Konfigurationsdatei für Windows, macOS oder Linux herunter. Im Test sah die Datei so aus (Schlüssel gekürzt):

[Interface]
PrivateKey = …
Address = 10.8.0.2/32, fdcc:ad94:bacf:61a3::cafe:2/128
MTU = 1420
DNS = 1.1.1.1, 2606:4700:4700::1111

[Peer]
PublicKey = …
PresharedKey = …
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 0
Endpoint = vpn.example.com:51820

AllowedIPs = 0.0.0.0/0, ::/0 leitet den gesamten Verkehr des Geräts durch das VPN. Soll nur das Firmennetz über den Tunnel laufen, ändern Sie unter Admin-Konsole, Konfiguration die erlaubten IP-Adressen und den DNS-Server für neue Clients.

Verifizieren: Nach dem Verbinden zeigt der Client in der Weboberfläche einen aktuellen Handshake, und auf dem Server liefert docker compose exec wg-easy wg show wg0 beim Peer latest handshake: … seconds ago. Ein ping 10.8.0.1 vom Client antwortet; im Test kamen 3 von 3 Paketen zurück.

Schritt 6: Weboberfläche per HTTPS erreichbar machen

Der SSH-Tunnel genügt für einen Administrator. Brauchen mehrere Personen Zugriff, setzen Sie einen Reverse Proxy mit HTTPS davor, zum Beispiel Caddy auf demselben Host, siehe Caddy als Reverse Proxy einrichten:

vpn-admin.example.com {
    reverse_proxy 127.0.0.1:51821
}

Setzen Sie anschließend INSECURE=false oder entfernen Sie die Zeile, und führen Sie docker compose up -d aus. Dann setzt wg-easy das Sitzungscookie mit dem Attribut Secure, im Test als set-cookie: wg-easy=…; Path=/; HttpOnly; Secure.

Verifizieren: https://vpn-admin.example.com zeigt die Anmeldeseite mit gültigem Zertifikat, und die Anmeldung bleibt nach einem Seitenwechsel bestehen.

Schritt 7: Updates, Sicherung und Passwort zurücksetzen

Updates innerhalb von Version 15 holen Sie mit dem Tag 15 ohne Brüche; so empfiehlt es das Projekt:

cd /opt/wg-easy
docker compose pull
docker compose up -d

Version 15.5.0 schließt laut Release Notes Sicherheitslücken in Node.js, aktualisiert AmneziaWG auf 3.1 und bringt zwei neue optionale Variablen: TRUSTED_PROXIES (IP-Adressen oder Netze des Reverse Proxys, deren weitergeleitete Client-Adresse wg-easy übernimmt) und WG_INTERFACE (Name der WireGuard-Schnittstelle, Standard wg0). Neue Pflichtvariablen gibt es nicht. Im Test des Updates von 15.4.0 auf 15.5.0 mit dieser Compose-Datei migrierte wg-easy die Datenbank beim Start (Migration complete), der vorher angelegte Client blieb erhalten, seine Konfiguration ließ sich abrufen, die Anmeldung mit dem bestehenden Konto funktionierte, ein falsches Passwort wurde abgewiesen, und wg show zeigte die Schnittstelle wg0 auf Port 51820.

Für die Sicherung stoppen Sie den Container und kopieren das Volume, denn dort liegen die SQLite-Datenbank mit allen Clients und die Serverschlüssel:

docker compose down
docker run --rm -v wg-easy_etc_wireguard:/data:ro -v "$PWD":/backup alpine \
  tar czf /backup/wg-easy-$(date +%F).tgz -C /data .
docker compose up -d

Haben Sie das Admin-Passwort vergessen, setzen Sie es über die mitgelieferte CLI zurück:

docker compose exec -it wg-easy cli db:admin:reset

Verifizieren: Nach dem Update zeigt das Log die neue Version. tar tzf wg-easy-*.tgz listet ./wg-easy.db und ./wg0.conf. Nach dem Zurücksetzen meldet die CLI Successfully updated admin user 1 (vpnadmin); im Test wurde danach das alte Passwort mit 401 abgewiesen, das neue angenommen.

Grundlagen zum Betrieb finden Sie in Docker Compose absichern: Secrets, Healthchecks, Non-Root.

Typische Fehler

  • Neustartschleife mit can't initialize ip6tables table `nat': Der Host stellt keine IPv6-NAT-Tabelle bereit, etwa ein LXC- oder Incus-Container als Docker-Host. Im Test trat genau das auf, wg-quick up wg0 scheiterte. Mit DISABLE_IPV6=true in den environment-Einträgen (laut Doku schaltet das die IPv6-Firewallregeln ab) startete wg0 fehlerfrei; die Clients nutzen dann nur IPv4.
  • Setup-Assistent erscheint trotz INIT_-Variablen: Die Gruppe 1 war unvollständig. Ohne INIT_HOST und INIT_PORT legte wg-easy im Test weder Konto noch Konfiguration an und leitete auf /setup/1 um, ohne Fehlermeldung im Log. Alle vier Werte setzen. Die Variablen wirken nur beim ersten Start mit leerem Volume.
  • Anmeldung scheinbar erfolgreich, danach sofort wieder abgemeldet: Zugriff per HTTP ohne INSECURE=true. Das Cookie trägt dann Secure, der Browser schickt es über HTTP nicht zurück. Im Test über die Container-IP: Anmeldung 200, danach /api/session mit 401.
  • WG_HOST und PASSWORD_HASH wirken nicht: Das sind Variablen aus Version 14. Host und Port stehen in Version 15 in der Admin-Konsole unter Konfiguration.
  • Cannot find device "wg0": Das Kernelmodul fehlt. Laut FAQ mit sudo modprobe wireguard laden und über /etc/modules dauerhaft eintragen.
  • can't initialize iptables table 'nat': Laut FAQ fehlt das Modul iptable_nat (bei IPv6 ip6table_nat); mit modprobe laden.
  • Clients verbinden, aber kein Handshake: UDP 51820 ist in Firewall oder Router nicht freigegeben, oder INIT_HOST zeigt auf eine falsche Adresse.

Häufige Fragen

Wie migriere ich von Version 14?

Laden Sie in der alten Oberfläche über Backup die wg0.json herunter, notieren Sie Ihre Umgebungsvariablen und stoppen Sie den alten Container mit docker compose down. Starten Sie Version 15 mit neuem Volume und wählen Sie im Assistenten „Ja“ bei der bestehenden Einrichtung. Die alten Variablen übernimmt wg-easy nicht.

Kann ich einzelne Clients auf bestimmte Netze beschränken?

Ja, über Firewall pro Client aktivieren unter Admin-Konsole, Interface. Anders als die erlaubten IP-Adressen setzt der Server diese Regeln per iptables durch. Die Funktion ist laut Doku experimentell.

Gibt es eine API?

Ja, unter /api mit Basic Authentication. Sie ist laut Projekt noch nicht stabil und funktioniert nicht, wenn für das Konto 2FA aktiv ist.

Brauche ich wg-easy oder reicht WireGuard allein?

Für feste Standortverbindungen reicht WireGuard, siehe WireGuard für Homeoffice und Standortvernetzung. wg-easy lohnt sich, wenn Sie regelmäßig Geräte hinzufügen und sperren.

Fazit

wg-easy 15 ist schnell eingerichtet, wenn Sie die neue Logik kennen: Tag 15 statt latest, INIT_-Variablen nur vollständig und nur beim ersten Start, INSECURE nur für HTTP. Mit der Weboberfläche an 127.0.0.1 ist nach außen nur der WireGuard-Port offen.

Weiterführende Anleitungen und Quellen