fix: harden DynDNS recovery and publish v1.5.1

This commit is contained in:
admin committed 2026-10-10 02:26:47 +02:00
1 parent 3383b91e49
commit 81def77e3c
37 files changed
+2415 -250

No files matched your search

+64 -3
View File
@@ -25,7 +25,7 @@ Beim ersten Start werden Datenbank und Verschlüsselungsschlüssel automatisch i
```yaml
services:
dyndns:
image: &image git.j-mahler.de/admin/domain-control-webinterface-prod:v1.5.0
image: &image git.j-mahler.de/admin/domain-control-webinterface-prod:v1.5.1
restart: unless-stopped
stop_grace_period: 20s
ports: ["9090:8080"]
@@ -61,7 +61,7 @@ Soll ein anderer Port verwendet werden, muss nur die linke Zahl geändert werden
Eine vollständige Schritt-für-Schritt-Anleitung für WebUI, Docker Compose,
Portainer/Dockge und Rollbacks steht in [`UPDATE.md`](UPDATE.md).
Administratoren können im Menü **Update** nach stabilen Releases suchen und eine neue Version direkt installieren. Dabei dürfen auch mehrere Versionen bis hin zu einem kompatiblen Major-Release übersprungen werden. Vor dem Neustart prüft der Agent Versionsgrenze, Agent-Protokoll, Datenbankvertrag, Laufzeitkonfiguration und Healthcheck des Ziel-Images. Gitea-Benutzername und wahlweise Passwort oder Token werden einmalig in der Weboberfläche hinterlegt; das Geheimnis wird mit dem Master-Key verschlüsselt gespeichert und weder an Templates noch an den Browser zurückgegeben.
Administratoren können im Menü **Update** nach stabilen Releases suchen und eine neue Version direkt installieren. Dabei dürfen auch mehrere Versionen bis hin zu einem kompatiblen Major-Release übersprungen werden. Vor dem Neustart prüft der Agent Versionsgrenze, Agent-Protokoll, Datenbankvertrag, Laufzeitkonfiguration und Healthcheck des Ziel-Images. Öffentliche Releases und öffentliche Container-Images funktionieren ohne Anmeldung. Für private Repositories oder Images können Gitea-Benutzername und Passwort oder Token einmalig hinterlegt werden; das Geheimnis wird mit dem Master-Key verschlüsselt gespeichert und weder an Templates noch an den Browser zurückgegeben.
`v1.4.0` ist die sichere Basis für diesen Update-Weg. Eine ältere Installation wird einmalig mit Docker Compose auf `v1.4.0` gebracht; danach kann der Agent auch spätere kompatible Releases direkt installieren. Web-App und Agent dürfen dabei unterschiedliche Versionsnummern haben: Maßgeblich ist das ausdrücklich ausgewiesene Protokoll. Verlangt ein Ziel-Image einen neueren Vertrag, bleibt der laufende Container unverändert und die Oberfläche fordert ein Compose-Update an.
@@ -94,8 +94,69 @@ Benutzer, Domains und Einstellungen bleiben in `dyndns-data`. Der Schlüssel fü
- eine Pi-hole-v6-Verbindung mit verschlüsseltem Anwendungspasswort und geschützter Anzeige nach erneuter Admin-Passwortprüfung
- lokale Pi-hole-DNS-Einträge für IPv4 und IPv6 anlegen, aktivieren/deaktivieren, bearbeiten, aus der WebUI trennen, wiederherstellen und vollständig löschen
Der Container muss die verbundene Pi-hole-Adresse direkt im internen Netz erreichen können. Pi-hole-Sitzungen werden nur für die jeweilige Aktion erstellt und danach aktiv beendet; dauerhaft gespeichert wird ausschließlich das mit dem Master-Key verschlüsselte Anwendungspasswort. Secret- und Datenverzeichnis werden auf `0700`, Master-Key und SQLite-Datei auf `0600` gehärtet. Das Compose-Setup verwendet außerdem ein schreibgeschütztes Root-Dateisystem und ein begrenztes `/tmp`-Tmpfs. HTTPS mit gültigem Zertifikat ist empfohlen.
Die Pi-hole-Seite zeigt sofort den gespeicherten Stand. **Records neu einlesen** aktualisiert ihn mit einer begrenzten API-Abfrage. Eine nicht mehr erreichbare Verbindung kann über **Lokale Verbindung entfernen** entfernt werden. Der Container muss die verbundene Pi-hole-Adresse für API-Aktionen direkt im internen Netz erreichen können. Pi-hole-Sitzungen werden nur für die jeweilige Aktion erstellt und danach aktiv beendet; dauerhaft gespeichert wird ausschließlich das mit dem Master-Key verschlüsselte Anwendungspasswort. Secret- und Datenverzeichnis werden auf `0700`, Master-Key und SQLite-Datei auf `0600` gehärtet. Das Compose-Setup verwendet außerdem ein schreibgeschütztes Root-Dateisystem und ein begrenztes `/tmp`-Tmpfs. HTTPS mit gültigem Zertifikat ist empfohlen.
Damit ein Pi-hole-Anwendungspasswort lokale DNS-Einträge ändern darf, muss am Pi-hole `webserver.api.app_sudo=true` gesetzt sein; Pi-hole verwendet hierfür standardmäßig `false`. Zusätzlich darf der globale Schalter `misc.readOnly` nicht aktiviert sein. Bei einem Pi-hole-Docker-Container entspricht das beispielsweise `FTLCONF_webserver_api_app_sudo: "true"` und `FTLCONF_misc_readOnly: "false"`.
Port 9090 verwendet zunächst unverschlüsseltes HTTP. Den Port daher nur in einem vertrauenswürdigen Netz freigeben und nicht offen ins Internet stellen.
## Netzwerkausfälle und Diagnose
Der Build und die Container-Prüfungen verwenden Go 1.26.9. Damit sind auch
die vom Sicherheitscheck gemeldeten HTTP-/Template-Probleme der bisherigen
Go-1.25.13-Basis behoben (siehe etwa [GO-2026-6617](https://pkg.go.dev/vuln/GO-2026-6617)).
Nach fehlgeschlagenen DynDNS-Läufen folgen weitere Versuche nach 5, 10, 20,
40 und höchstens 60 Sekunden; nach einem erfolgreichen Lauf gilt wieder das
konfigurierte Intervall. Ein IP-Endpunkt hat einschließlich DNS, TLS und
Antwort höchstens zehn Sekunden Zeit. IPv4 und IPv6 werden unabhängig und
parallel ermittelt. Fehlgeschlagene Abfragen liefern keine alte IP für ein
DNS-Update; vorhandene DNS-Records bleiben dann bestehen.
Hetzner-Änderungen gelten erst dann als erfolgreich, wenn der asynchrone
API-Auftrag `success` meldet; `running`, spätere Fehler und Zeitüberschreitungen
werden nicht als Erfolg gespeichert. Die Bestätigung wird bis zu 20 Sekunden
abgewartet. Ein Fehler beim A-Record verhindert die Aktualisierung des
AAAA-Records nicht und umgekehrt; bestätigte Teiländerungen bleiben sichtbar.
Siehe den [Hetzner-API-Vertrag für Actions](https://docs.hetzner.cloud/reference/cloud#actions).
WebUI-Änderungen an DNS-Zielen und automatische Läufe werden vollständig
nacheinander ausgeführt, damit ein alter Lauf keine gelöschten Ziele neu
anlegt oder feste Adressen überschreibt. Dauert ein laufender Vorgang länger
als fünf Sekunden, wird die neue WebUI-Änderung mit einer Meldung zum erneuten
Senden abgewiesen. Unveränderte IP-Endpunkte brauchen beim Speichern der
Updater-Einstellungen keine erneute DNS-Prüfung. Neue Endpunkte werden weiter
geprüft (höchstens acht je IP-Familie).
Laufhistorie und letzter Status werden gemeinsam gespeichert, auch nach einem
kontrollierten Abbruch. Beim Prozessstart werden durch einen Absturz offene
Läufe als unterbrochen markiert. Der aktive Updater beginnt automatisch mit
einer neuen Prüfung; beim Herunterfahren wird sein Abschluss abgewartet.
Bei einem vorübergehenden Fehler des System-DNS (Timeout/SERVFAIL) werden
**nur** `api.ipify.org`, `api6.ipify.org`, `ifconfig.co` und
`api.hetzner.cloud` zusätzlich direkt über Cloudflare und Quad9 aufgelöst
(`1.1.1.1`, `9.9.9.9`, `2606:4700:4700::1111`, `2620:fe::fe`, Port 53).
System-DNS und die parallelen Ausweichabfragen haben jeweils zwei Sekunden.
Jede neue Abfrage beginnt wieder mit System-DNS. Negative DNS-Antworten
(NXDOMAIN), eigene Endpunkte und lokale Pi-hole-Namen erhalten keinen solchen
Ausweichweg. HTTPS-Zertifikate und öffentliche IP-Endpunkte werden weiterhin
geprüft. Dieser Mechanismus ersetzt keine funktionierende Route oder
Firewall-Freigabe auf dem Produktionsserver.
Unter **Fehler → Diagnose-Logs herunterladen** können Administratoren einen
JSON-Bericht exportieren. Er enthält Version, letzte Laufstatus, IP-Abfragen,
DNS-Ausweichversuche, Fehlertypen, Wartezeiten, Wiederherstellung und
DNS-/IPv4-Routing-Daten. Die Ereignisse werden im bestehenden Daten-Volume in
zwei Dateien zu höchstens je 4 MiB mit Dateirechten `0600` gespeichert und
überleben Container-Neustarts. Bei langen Ausfällen wird der Netzwerkzustand
beim ersten Fehler und anschließend alle 15 Minuten festgehalten.
Der Export enthält ausschließlich festgelegte technische Felder. Rohmeldungen,
Audit-Texte, Zugangsdaten, Cookies, Sitzungs-IDs, HTTP-Header, URL-Pfade und
Query-Parameter werden nicht übernommen. IP-Adressen und Netzwerkrouten sind
zur Diagnose enthalten. Die Aufzeichnung beginnt mit dieser Funktion; alte
Läufe sind nur mit Zeit und Status enthalten. Der lokale Healthcheck bestätigt
die Erreichbarkeit der Web-App, nicht die Erreichbarkeit von Internet/Hetzner.
Bei `no_route` müssen auf Prod Gateway, Docker-Bridge, Forwarding/NAT und
Firewall geprüft werden; ein Container-Neustart allein belegt keine Behebung.