sysopsandClaude Sonnet 5 6eeea65ede Fix "Text file busy" on reinstall while service is running
cp truncates the destination in place, which fails with ETXTBSY when
the binary is currently executing (e.g. running update.sh while the
systemd service is active). Copy to a temp file and mv it into place
instead - mv is a rename within the same filesystem, which the
kernel allows even for a running binary.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-10 18:23:20 +02:00

wireguard-ui-multi

Native Multi-Server-Verwaltungsoberfläche für WireGuard — ohne Docker. Im Gegensatz zum ursprünglichen wireguard-ui, das genau eine WireGuard-Instanz verwaltet, kann wireguard-ui-multi mehrere unabhängige WireGuard-Interfaces gleichzeitig verwalten (z. B. wg-home, wg-rz, wg-winter), jedes mit eigenem Port, eigenem Adressbereich, eigenen Peers und eigenem Status.

Zielumgebungen: Debian/Ubuntu, Proxmox LXC Container, generisches Linux mit systemd. Betrieb als natives Go-Binary.

Features

  • Multi-Server-Verwaltung: beliebig viele WireGuard-Server, jeder mit eigenem Interface-Namen, Port, Private/Public Key, Adressbereich, DNS, MTU und Enabled/Disabled-Status (Tabelle servers in SQLite).
  • Peer-Verwaltung pro Server: Peers gehören zu genau einem Server (Fremdschlüssel server_id), inklusive Name, E-Mail, Public/Private/ Preshared Key, Allowed IPs, Endpoint, Persistent Keepalive, Enabled-Status und optionalem Ablaufdatum (expires_at).
  • Automatische Config-Erzeugung: Server-Configs werden nach /etc/wireguard/<interface>.conf im Standard-wg-quick-Format geschrieben.
  • Service-Steuerung: Start/Stop/Reload je Interface über wg-quick up, wg-quick down und wg syncconf (Hot-Reload ohne Verbindungsabbruch), Status-Abfrage über wg show.
  • QR-Code & Config-Download: Peer-Konfiguration kann als .conf-Datei heruntergeladen oder als QR-Code (PNG) angezeigt werden — Private Keys verlassen den Server nur in dieser generierten Peer-Config, nie über die UI/JSON-API.
  • REST-API für Server- und Peer-Verwaltung (siehe unten) plus Web-Dashboard.
  • Firewall-Vorbereitung: optionale Lifecycle-Hook-Skripte (server-start, server-stop, peer-add, peer-remove) in /etc/wireguard-manager/hooks/ sowie ein Generator für einen Vorschlags-nftables-Ruleset pro Server (Port freigeben, Forwarding Tunnel ↔ LAN-Interface).
  • Audit Log: Tabelle audit_log protokolliert Aktionen mit Akteur, Aktion, Ziel und Detail.
  • Sitzungsbasierte Authentifizierung mit CSRF-Schutz: jede mutierende Anfrage (POST/PUT/DELETE) benötigt einen gültigen Session-Cookie plus den Header X-CSRF-Token.
  • Optional HTTPS über --tls-cert / --tls-key.

Installation

Hardware-Anforderungen

Betrieb selbst ist sehr genügsam (kleines Go-Binary + SQLite, kein Docker/JVM):

  • Betrieb: 1 vCPU, 128-256 MB RAM reichen locker
  • Build aus Quellcode: mind. 1 GB RAM während go build — das modernc.org/sqlite-Package (reines Go, kein cgo, aber sehr großzügiger generierter Code) sprengt den go-Compiler bei 512 MB LXC-RAM (signal: killed, OOM-Killer). Bei 1 GB lief der Build durch.
  • Nach dem Build kann der Container/Server wieder auf 256-512 MB reduziert werden, falls Ressourcen knapp sind.
  • Alternative ohne Build-RAM-Bedarf: fertiges Release-Binary nutzen, sobald eine Release-Pipeline existiert (bootstrap.sh versucht das automatisch zuerst und fällt nur bei Fehlschlag auf den Source-Build zurück).

Schnellinstallation (Einzeiler)

Auf einem frischen Debian/Ubuntu-Host (als root), lädt und installiert alles in einem Schritt (Abhängigkeiten, Go-Toolchain falls nötig, Quellcode, Build, install.sh):

curl -fsSL https://gitea.perlbach24.de/scripte/wireguard-ui-multi/raw/branch/main/bootstrap.sh | bash

Danach nur noch:

sudo systemctl enable --now wireguard-ui-multi.service

Der Quellcode bleibt unter /opt/wireguard-ui-multi-src liegen; erneutes Ausführen des Einzeilers aktualisiert die Installation.

Update

Für ein gezieltes Update (holt neuesten Code, baut neu, installiert neu und startet den Dienst neu):

cd /opt/wireguard-ui-multi-src
sudo ./update.sh

Manuelle Installation

1. Aus dem Quellcode bauen

go build -o wireguard-ui-multi ./cmd/wireguard-ui-multi

2. Installationsskript ausführen (als root)

sudo ./scripts/install.sh

Das Skript ist idempotent und:

  • kopiert die Binary nach /usr/local/bin/wireguard-ui-multi
  • legt /etc/wireguard-ui-multi, /var/lib/wireguard-ui-multi und /etc/wireguard-manager/hooks an
  • installiert die systemd-Unit nach /etc/systemd/system/wireguard-ui-multi.service
  • setzt chmod 0700 auf das Datenverzeichnis (dort liegt die SQLite-DB mit Passwort-Hashes)

Wichtig: Das Skript startet den Dienst nicht automatisch. Danach manuell aktivieren:

sudo systemctl enable --now wireguard-ui-multi.service
sudo systemctl status wireguard-ui-multi.service
sudo journalctl -u wireguard-ui-multi.service -f

Konfiguration

Die Anwendung wird über Kommandozeilen-Flags konfiguriert (siehe cmd/wireguard-ui-multi/main.go):

Flag Default Bedeutung
--listen :8443 Listen-Adresse des Webservers
--db /var/lib/wireguard-ui-multi/wireguard-ui-multi.db Pfad zur SQLite-Datenbankdatei
--config-dir /etc/wireguard Zielverzeichnis für generierte wg-quick-Configs
--hooks-dir /etc/wireguard-manager/hooks Verzeichnis mit optionalen Hook-Skripten
--lan-iface eth0 LAN-Interface für die vorgeschlagenen nftables-Forward-Regeln
--tls-cert (leer) Pfad zum TLS-Zertifikat (aktiviert HTTPS zusammen mit --tls-key)
--tls-key (leer) Pfad zum TLS-Private-Key

Die in systemd/wireguard-ui-multi.service hinterlegte ExecStart-Zeile setzt --db, --config-dir und --hooks-dir bereits passend zur Installationsstruktur.

Erststart / Admin-Passwort

Beim allerersten Start (leere users-Tabelle) wird automatisch ein admin-Benutzer mit einem zufällig erzeugten 32-stelligen Hex-Passwort angelegt. Das Klartext-Passwort wird genau einmal auf stderr ausgegeben (z. B. sichtbar via journalctl -u wireguard-ui-multi.service) und danach nur noch als bcrypt-Hash in der Datenbank gespeichert. Nach dem ersten Login sollte das Passwort umgehend geändert werden.

LXC / Proxmox Hinweise

WireGuard benötigt Zugriff auf das wireguard-Kernelmodul des Hosts sowie CAP_NET_ADMIN und Zugriff auf /dev/net/tun im Container:

  • Auf dem Proxmox-Host muss das wireguard-Kernelmodul geladen sein (modprobe wireguard; bei Bedarf /etc/modules ergänzen).
  • Der LXC-Container sollte entweder privilegiert betrieben werden, oder als unprivilegierter Container mit gezielten Lockerungen (lxc.cap.drop ohne net_admin, lxc.cgroup2.devices.allow: c 10:200 rwm für /dev/net/tun) konfiguriert werden. In der Praxis ist ein privilegierter Container für WireGuard-Hosting deutlich unkomplizierter.
  • /dev/net/tun muss im Container vorhanden und beschreibbar sein (ls -l /dev/net/tun); ggf. per Bind-Mount/lxc.mount.entry durchreichen.
  • Die systemd-Unit läuft als root mit AmbientCapabilities=CAP_NET_ADMIN, weil sie wg-quick, systemctl und nft aufruft — diese Tools benötigen in der Praxis root-Rechte im Container.
  • Läuft nftables bereits als eigener Dienst im Container/Host, sollte der von wireguard-ui-multi vorgeschlagene Ruleset (siehe unten) manuell in die bestehende Regelbasis integriert statt blind angewendet werden, um Konflikte mit vorhandenen Tabellen/Chains zu vermeiden.

Server- & Peer-Verwaltung

Server anlegen (UI oder POST /api/servers): Name, Interface-Name (z. B. wg-home), Listen-Port, Adressbereich (z. B. 10.20.22.0/24), DNS, MTU angeben. Private/Public Key werden serverseitig automatisch erzeugt.

Server starten/stoppen/neuladen: über die Dashboard-Buttons oder POST /api/servers/{id}/start|stop|reload. Start schreibt zunächst die wg-quick-Config nach /etc/wireguard/<interface>.conf und ruft dann wg-quick up <interface> auf; Reload nutzt wg syncconf für einen Hot-Reload ohne Tunnelabbruch.

Peer hinzufügen (UI oder POST /api/server/{id}/peer): Name, optional E-Mail/Beschreibung und Ablaufdatum angeben — Schlüsselpaar und Preshared Key werden automatisch generiert.

Config/QR-Code abrufen: GET /api/server/{id}/peer/{peerid}/config liefert die fertige .conf-Datei zum Download, GET /api/server/{id}/peer/{peerid}/qrcode liefert denselben Inhalt als PNG-QR-Code zum Scannen mit der WireGuard-App.

REST-API-Übersicht

POST   /api/login
POST   /api/logout

GET    /api/servers
POST   /api/servers
GET    /api/servers/{id}
PUT    /api/servers/{id}
DELETE /api/servers/{id}
POST   /api/servers/{id}/start
POST   /api/servers/{id}/stop
POST   /api/servers/{id}/reload
GET    /api/servers/{id}/config

GET    /api/server/{id}/peers
POST   /api/server/{id}/peer
DELETE /api/server/{id}/peer/{peerid}
GET    /api/server/{id}/peer/{peerid}/config
GET    /api/server/{id}/peer/{peerid}/qrcode

Alle Endpunkte außer /api/login erfordern einen gültigen Session-Cookie; mutierende Methoden (POST/PUT/DELETE) benötigen zusätzlich den Header X-CSRF-Token mit dem beim Login ausgegebenen Token.

Backup / Restore

Ein automatisiertes Backup-/Restore-Werkzeug ist aktuell nicht implementiert. Für ein manuelles Backup genügt es, folgende Pfade zu sichern:

  • die SQLite-Datenbank: /var/lib/wireguard-ui-multi/wireguard-ui-multi.db (enthält Server, Peers, Keys, Audit Log, Benutzer)
  • die generierten Interface-Configs: /etc/wireguard/*.conf
  • ggf. eigene Hook-Skripte: /etc/wireguard-manager/hooks/

Beispiel:

sudo tar czf wireguard-ui-multi-backup-$(date +%F).tar.gz \
  /var/lib/wireguard-ui-multi/wireguard-ui-multi.db \
  /etc/wireguard/*.conf \
  /etc/wireguard-manager/hooks

Restore: Dienst stoppen, Archiv an denselben Pfaden entpacken, Berechtigungen prüfen (chmod 0700 auf das Datenverzeichnis) und Dienst wieder starten:

sudo systemctl stop wireguard-ui-multi.service
sudo tar xzf wireguard-ui-multi-backup-YYYY-MM-DD.tar.gz -C /
sudo systemctl start wireguard-ui-multi.service

Migration von einer bestehenden wireguard-ui-Installation

Für den Umstieg von einer klassischen Single-Interface-Installation (/etc/wireguard/wg0.conf) ist ein Migrationswerkzeug vorgesehen, das eine bestehende wg0.conf einliest und als ersten verwalteten Server samt seiner Peers importiert. Damit lässt sich eine vorhandene WireGuard-Instanz übernehmen, ohne bestehende Clients neu konfigurieren zu müssen. Details zum genauen Ablauf und den Aufrufoptionen siehe die Implementierung im wireguard-Package des Repos, sobald verfügbar; grundsätzlich gilt: vor der Migration ein Backup der bestehenden wg0.conf anlegen.

Sicherheitshinweise

  • Private Keys werden nie im Frontend/JSON angezeigt — sie werden ausschließlich serverseitig in generierten .conf-Dateien bzw. QR-Codes für einzelne Peers ausgeliefert.
  • HTTPS verwenden: entweder direkt über --tls-cert/--tls-key, oder die Anwendung hinter einem Reverse Proxy (nginx, Caddy, Traefik) mit TLS-Terminierung betreiben. Ohne TLS gibt der Dienst beim Start eine deutliche Warnung aus.
  • Standard-Admin-Passwort sofort ändern: das beim Erststart einmalig ausgegebene zufällige Passwort sollte direkt nach dem ersten Login geändert werden.
  • Mutierende API-Aufrufe erfordern einen gültigen Session-Cookie und den CSRF-Header X-CSRF-Token — Clients/Skripte, die die API direkt ansprechen, müssen sich zunächst über /api/login anmelden und den zurückgegebenen Token mitführen.
  • Die Datenverzeichnisse (/var/lib/wireguard-ui-multi) sollten restriktive Berechtigungen (0700) behalten, da dort Schlüsselmaterial und Passwort-Hashes liegen.
S
Description
No description provided
Readme MIT
361 KiB
Languages
HTML 47.1%
Go 47%
JavaScript 3.1%
Shell 2.8%