Skip to content

Betrieb

Diese Seite beschreibt, was ZPO für den laufenden Betrieb mitbringt: das Audit-Log als Geschichte aller Änderungen, die eingebaute Sicherung, Alarme über SMTP und Webhook, den /metrics-Endpunkt für Prometheus und den Notzugang per CLI, wenn die Oberfläche einmal nicht erreichbar ist.

ZPO zeichnet jede Änderung an der HTTP-Grenze auf — dort sind Akteur und IP des Aufrufs bekannt. Aufgezeichnet werden Standorte, Proxy- und DNS-Knoten, Backend-Pools, Dienste, Zertifikate, ACME-Konten, DNS-Provider, Benutzer und API-Schlüssel sowie Anmeldungen, Sicherungen und Rücksicherungen.

Jeder Eintrag enthält:

  • Aktion — create, update, delete, rollback, login, backup oder restore,
  • Entität und Entitäts-ID — etwa proxy_host mit der ID des Dienstes,
  • Vorher und Nachher als JSON — die Grundlage zum Zurückrollen,
  • Benutzer und IP des Aufrufs; Systemvorgänge bleiben ohne Benutzer.

Geheimnis-Felder (Passwörter, Tokens, Schlüssel) sind in den Domain-Structs von der Serialisierung ausgenommen und tauchen nicht im Log auf. Einträge werden unbegrenzt aufbewahrt — das Log ist die Geschichte der Infrastruktur. Ein Schreibfehler im Audit-Log wird nur protokolliert und verhindert die Bedienhandlung nicht.

Das Log liegt in der Oberfläche unter Einrichtung → Audit, gefiltert nach Entität. Jeder Eintrag zeigt Vorher und Nachher.

Einträge zu einem Dienst (proxy_host) mit gefülltem Vorher-Stand lassen sich per Knopf zurückrollen: Existiert der Dienst noch, wird er auf den alten Stand aktualisiert; wurde er gelöscht, wird er mit neuer ID neu angelegt — Standort-Auswahl und Überschreibungen kommen aus dem Audit-Eintrag mit. Für andere Entitäten gibt es keinen definierten Rückweg. Dasselbe kann der CLI-Notzugang, siehe Notzugang.

Die eingebaute Sicherung erzeugt über VACUUM INTO eine konsistente Kopie der Datenbank — auch während ZPO läuft — und packt sie als zpo-backup-<zeitstempel>.tar.gz. Im Paket liegen:

DateiInhalt
zpo.dbkonsistente Kopie der Datenbank — alle Standorte, Knoten, Dienste, Pools, Zertifikate samt Schlüsseln, Zugänge, Profile, Benutzer, Audit-Log und Ereignisse
config.jsondie Grundeinstellungen des Servers
secret.key.sealednur mit Sicherungspasswort: der Hauptschlüssel, verschlüsselt (Argon2id + AES-256-GCM)
MANIFEST.jsonVersion, Zeitpunkt, ob der Schlüssel dabei ist, und die SHA-256-Prüfsumme jedes Teils

Mit secret.key sind alle gespeicherten Zugangsdaten verschlüsselt: Knoten-Passwörter, DNS-Provider, private Schlüssel der Zertifikate, SFTP-Passwort. Eine Sicherung ohne ihn ist auf einem neuen Rechner nur halb brauchbar.

  • Mit Sicherungspasswort (mindestens 12 Zeichen) kommt der Schlüssel verschlüsselt mit in jede Sicherung. Eine Sicherung ist dann allein vollständig wiederherstellbar; das Passwort gut aufbewahren — ohne es bleibt der Schlüssel verschlossen.
  • Ohne Sicherungspasswort bleibt der Schlüssel draußen und gehört in eine eigene, getrennte Sicherung (siehe Installation).

Unter Allgemeine Einstellungen → Sicherung:

EinstellungBedeutung
AktivSchaltet den Zeitplan ein.
Intervall (Stunden)Abstand der Sicherungen, 1 bis 720.
AufbewahrenAnzahl der vorgehaltenen Sicherungen, 1 bis 500 — beim Verzeichnis wie bei SFTP.
ZielVerzeichnis auf dem ZPO-Host oder SFTP.
VerzeichnisLeer oder relativ heißt: im Datenverzeichnis, Vorgabe backups (beim Debian-Paket /var/lib/zpo/backups).
SFTP-Host, -Port, -Benutzer, -Passwort, -PfadZielangaben; der Port fällt auf 22 zurück.
Sicherungspasswortsiehe oben; leer lassen heißt unverändert.

Schreibrechte: Unter systemd läuft ZPO mit DynamicUser und darf nur in seinem Datenverzeichnis schreiben — alles andere ist schreibgeschützt. Das Debian-Paket legt deshalb /var/lib/zpo/backups gleich mit an (StateDirectory=zpo zpo/backups). Ein anderes Verzeichnis prüft ZPO schon beim Speichern, indem es probehalber hineinschreibt. Für Sicherungen auf einem anderen Rechner ist SFTP der vorgesehene Weg.

SFTP: Den Schlüssel des Servers merkt sich ZPO bei der ersten Verbindung und verlangt ihn danach — zeigt der Server einen anderen, bricht die Sicherung ab. Wer den Server tauscht, speichert das Ziel mit dem neuen Host neu.

Letzte Sicherung und letzter Fehler stehen in der Ansicht, Jetzt sichern löst die Sicherung sofort aus. Die Dateiliste zeigt das Verzeichnisziel.

Die Rücksicherung läuft aus der Oberfläche: Sicherungsdatei wählen, bei einer Sicherung mit Schlüssel das Sicherungspasswort eingeben. ZPO prüft vorher alles und fasst bis dahin nichts an:

  1. die Prüfsumme jedes Teils gegen das Manifest,
  2. die Version — eine Sicherung aus einer neueren ZPO-Version wird abgelehnt,
  3. den Schlüssel — der mitgesicherte oder, ohne ihn, der laufende muss die Zugangsdaten der Sicherung öffnen,
  4. die Datenbank selbst (PRAGMA integrity_check).

Dann legt ZPO Datenbank, Konfiguration (mit dem Datenbankpfad dieses Rechners) und gegebenenfalls den Schlüssel bereit und startet neu. Eingesetzt wird beim Start, bevor die Datenbank geöffnet ist; die WAL-Dateien der alten Datenbank verschwinden dabei — SQLite würde sie sonst auf die neue anwenden. systemd (Restart=always) oder Docker bringen den Prozess wieder hoch.

Von Hand geht es genauso: ZPO stoppen, Paket entpacken, zpo.db und config.json im Datenverzeichnis ersetzen, zpo.db-wal und zpo.db-shm löschen, ZPO starten.

IP-Gruppen sind benannte CIDR-Listen (mindestens ein Netz, Name 2 bis 64 Zeichen). Ein Dienst, der eine Gruppe gebunden hat, ist nur aus deren Netzen erreichbar — Clients außerhalb bekommen ein 403. Das Rate-Limit eines Dienstes begrenzt die Anfragen je Client-IP innerhalb von zehn Sekunden (0 bis 100000, 0 schaltet es aus); darüber antwortet der Proxy mit 429.

Beides wirkt über die Map-Dateien zpo_ipgroups.map und zpo_ratelimits.map (siehe Knoten einrichten): Einträge setzt ZPO über die Runtime-API zur Laufzeit — kein Reload des Proxys. Eine Gruppe lässt sich nicht löschen, solange noch Dienste sie gebunden haben; der Aufruf nennt die Anzahl.

Ereignisse aus dem Zertifikats-Erneuerer, dem Failover und dem Abgleich gehen über die Alarmkanäle hinaus. Der Alarmdienst läuft im Minutentakt und verschickt die Ereignisse, die noch nicht alarmiert sind — so übersteht die Alarmierung einen Neustart. Erst wenn alle aktiven Kanäle bedient waren, gilt ein Ereignis als alarmiert; ein streikender Kanal lässt nichts untergehen.

TypBedeutung
cert_expiryEin Zertifikat läuft ab, ohne dass eine Erneuerung in Sicht ist.
cert_renewal_missingEine fällige Erneuerung ist fehlgeschlagen.
failover_outageEin Proxy ist ausgefallen.
failover_switchDer DNS-Schwenk wurde ausgelöst.
failover_failbackZurückschwenken nach der Karenzzeit.
failover_maintenanceEin Knoten wurde in Wartung genommen.
site_downEin ganzer Standort antwortet nicht mehr — ZPO schwenkt bewusst nicht.
node_offlineEin einzelner Knoten ist unerreichbar.
driftDer Vollabgleich hat eine Abweichung gefunden.
crowdsec_downDer CrowdSec-Schutz eines Proxys wirkt nicht: LAPI antwortet nicht, Lesezugang abgewiesen, Bouncer steht, ist nicht verdrahtet oder holt keine Sperren ab, CrowdSec liest oder versteht die Logs nicht.
crowdsec_recoveredEntwarnung: CrowdSec wirkt wieder.

Alle Ereignisse stehen außerdem in der Oberfläche unter Ereignisse und lassen sich dort bestätigen; gelöscht werden sie nicht.

Host, Port (Vorgabe 587), Benutzer und Passwort, Absender und Empfänger (kommagetrennt). STARTTLS wird genutzt, wenn der Server es anbietet; ohne Benutzer entfällt die Anmeldung. Betreff und Text tragen Typ, Zeit und Nachricht des Ereignisses.

Ein JSON-POST an die konfigurierte Adresse (http:// oder https://) mit type, message, time und source: "zpo"; ein optionaler Token geht als Authorization: Bearer mit. HTTP-Status ab 300 gilt als Fehlschlag.

Die Einstellungen liegen unter Allgemeine Einstellungen → Alarme. Passwort und Token werden verschlüsselt gespeichert; beim Ändern heißt ein leeres Feld: der bisherige Wert bleibt. Jeder Kanal hat einen eigenen Testknopf — Test-E-Mail senden und Webhook testen. Der Test nimmt die Werte, die gerade in der Maske stehen, auch vor dem Speichern, und zeigt die Antwort des Servers, wenn er scheitert.

Beim SMTP-Versand gilt: Port 465 spricht TLS von Anfang an, jeder andere Port (üblich 587) wechselt per STARTTLS, sobald der Server es anbietet. Eine Anmeldung ohne Verschlüsselung lehnt ZPO ab, außer gegen localhost.

Die Ansicht Statistik zeigt, was durch die Proxys läuft und was abgewehrt wird — gesamt oder eingegrenzt auf einen Standort, einen Proxy oder einen Dienst, für 24 Stunden, 7 oder 30 Tage:

  • Verkehr: Aufrufe, Datenmenge, Fehlantworten (4xx) und Serverfehler (5xx), als Verlauf und je Dienst. Ohne Auswahl eines Dienstes zählt alles, was an die Proxys kam — auch, was sie selbst beantwortet haben (gesperrt, abgewiesen, unbekannter Name).
  • Abwehr: von der WAF geblockte Anfragen, CrowdSec-Alarme mit Angriffsmuster, angegriffenem Dienst, Herkunftsland und Adresse, dazu die aktiven Sperren.

Dafür liest ZPO alle fünf Minuten die Zähler von HAProxy (über die Data Plane API) und der WAF (Metriken des Agents) und speichert die Differenz zum letzten Stand — HAProxy zählt nur seit seinem Start bzw. Reload. CrowdSec- Alarme holt ZPO mit dem Maschinen-Zugang je LAPI; was ZPO selbst abgleicht, zählt nicht als Angriff. Aufbewahrung: 5-Minuten-Werte zwei Tage, Stundenwerte und Alarme 90 Tage. Die Statistik beginnt mit dem Update auf 0.7 — ältere Zahlen gibt es nicht.

Der Endpunkt /metrics steht außerhalb der API und ist ohne Anmeldung lesbar, damit Prometheus ihn erreichen kann. Der Konfigurationsschlüssel metrics_token schützt ihn bei Bedarf — als Authorization: Bearer <token> oder als ?token=… (siehe Konfiguration).

KennzahlTypBedeutung
zpo_uptime_secondsGaugeLaufzeit des Prozesses.
zpo_node_status{kind,node,status}GaugeZustand je Knoten (1 = aktueller Zustand).
zpo_objects_pending{kind,node}GaugeOffene Aufträge des Abgleichs je Knoten.
zpo_certificate_days_left{name}GaugeVerbleibende Tage bis zum Zertifikatsablauf — ein Alarm darauf deckt den drohenden Ablauf ab.
zpo_events_total{type}CounterEreignisse je Typ seit Bestehen der Datenbank.

Liegt die Oberfläche hinter einem Proxy, den ZPO selbst verwaltet, darf eine fehlerhafte Änderung nicht aussperren. Zwei Wege führen zurück hinein:

  • local_port in der Konfiguration — ein zusätzlicher Listener auf 127.0.0.1, siehe Konfiguration.
  • zpo rollback — ein Subcommand, das direkt auf der Datenbank arbeitet, ohne HTTP und ohne den Hauptschlüssel:
Terminal window
# Dienst auf den letzten Audit-Stand zurückrollen (stellt auch
# gelöschte Dienste wieder her):
zpo rollback -data /var/lib/zpo --host app.beispiel.de
# Notbremse: Dienst deaktivieren — der Abgleich entfernt die
# Routen beim nächsten Lauf:
zpo rollback -data /var/lib/zpo --disable-host app.beispiel.de

Ohne -data gilt das Verzeichnis des Binaries, wie beim Dienst.

DateiInhalt
config.jsonGrundeinstellungen, siehe Konfiguration
zpo.dbSQLite-Datenbank — alle Zustände und Einstellungen
secret.keyder Hauptschlüssel — mit Sicherungspasswort Teil der Sicherung, sonst getrennt sichern
backups/Vorgabeverzeichnis der Sicherungen
version.jsonVersionsmarke der Installation; steuert die Datenübernahme beim Update

Beim Debian-Paket ist das /var/lib/zpo, im Container /data.

Debian-Paket: apt update && apt install zpo — das Paket startet einen laufenden Dienst neu. Der Dienst läuft als systemd-Unit mit dynamischem Benutzer (kein root); Geheimnisse wie ZPO_SECRET_KEY gehören in /etc/zpo/secret.env (Rechte 0600), das die Unit einliest. Vor dem Update eine Sicherung auslösen — und daran denken, dass secret.key separat liegt.

Docker: neues Image ziehen und den Container mit demselben Volume auf /data neu erzeugen:

Terminal window
docker pull registry.techeve.de/techeve/zpo:latest
docker stop zpo && docker rm zpo
docker run -d --name zpo -p 8080:8080 -v zpo-data:/data \
registry.techeve.de/techeve/zpo:latest

In beiden Fällen liest ZPO beim Start die version.json neben der Datenbank und zieht die Daten automatisch auf den Stand der neuen Version.

Nach dem Update die Proxys aktualisieren: Bringt eine neue Version eigene Inhalte mit — etwa neue Fehlerseiten — oder schreibt sie die Konfiguration anders auf den Knoten, sieht der Abgleich darin keine Änderung am Sollzustand. Unter Proxy-Knoten spielt der Knopf Konfiguration aktualisieren (Kreispfeile) deshalb alles, was ZPO auf diesem Proxy führt, sofort neu ein. Lehnt der Knoten einen Teil ab, nennt ZPO die Anzahl; die Einzelheiten stehen unter Abgleich. Deaktivierte Proxys bekommen auch auf Knopfdruck nichts.