fix(wireguard): Tunnel reißt nie ab + Client-Endpoint auto-befüllt — v1.2.100

Zwei Bugs, die WireGuard-Verbindungen verhinderten/abrissen:
1) Client-Config-Endpoint war hartkodierter Platzhalter REPLACE_WITH_PUBLIC_HOST → neue Clients bauten nie einen Tunnel auf (Host löst nicht auf). Jetzt: WireguardHandler.PublicHost (aus setup.json FQDN, main.go) → Endpoint = <fqdn>:<port>. Platzhalter nur noch als Fallback wenn FQDN unbekannt.
2) Renderer machte bei JEDER Config-Änderung 'systemctl restart wg-quick@<iface>' → voller Link-Flap, alle Peers droppen (verstößt gegen 'wireguard darf nie abbrechen'). Jetzt: laufendes Interface → 'wg-quick strip | wg syncconf' (Peers/Listen-Port live, KEIN Abbruch); nur erstmaliges Hochfahren via systemctl start; restart nur noch als Fallback mit WARN. interfaceExists() via 'ip link show'. Neue sudoers: wg syncconf *, wg-quick strip *.
Ein edgeguard-api-Restart (Deploy) fasst wg-quick@<iface> nicht an → Tunnel bleibt während Deploy bestehen.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Debian
2026-06-06 20:51:52 +02:00
parent 7611572062
commit 91e51890dd
6 changed files with 80 additions and 13 deletions

View File

@@ -12,6 +12,7 @@ import (
"context"
"errors"
"fmt"
"log/slog"
"os"
"path/filepath"
"sort"
@@ -254,9 +255,24 @@ func (g *Generator) renderIface(ctx context.Context, ifc models.WireguardInterfa
return fmt.Errorf("symlink: %w", err)
}
_ = enableWGQuick(ifc.Name)
if !changed {
return startWGQuick(ifc.Name)
// Läuft das Interface schon, werden Änderungen LIVE per `wg syncconf`
// angewendet — KEIN Tunnel-Abbruch (WireGuard darf nie abreißen). Nur
// das erstmalige Hochfahren nutzt `systemctl start`.
if interfaceExists(ifc.Name) {
if !changed {
return nil // läuft + Config unverändert → nichts zu tun
}
if err := syncWGQuick(ifc.Name); err != nil {
// Fallback (z. B. sudoers noch ohne syncconf): voller Neustart.
// Bricht den Tunnel kurz ab — nur Notnagel.
slog.Warn("wireguard: wg syncconf fehlgeschlagen, Fallback auf restart (kurzer Tunnel-Flap)",
"iface", ifc.Name, "error", err)
return restartWGQuick(ifc.Name)
}
return nil
}
return restartWGQuick(ifc.Name)
// Interface noch nicht oben → erstmalig hochfahren.
return startWGQuick(ifc.Name)
}