monitor/README_UPDATE.md
fds2610-bot 65f6bc6c2e Update-Event des Monitorings und PR-Flag bestehender Tickets
update.sh meldet nach dem Neustart ein Event (POST /api/v1/events/system, Admin-Key).
upsertPullRequest markiert bereits vorhandene Tickets als Pull Request, damit sie den
/pulls/-Link bekommen.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 12:48:10 +02:00

6.6 KiB

Auto-Update auf einem Produktionsserver

Dieses Dokument beschreibt, wie ein bereits laufendes monitor auf einem Produktionsserver sich selbst aktualisiert, sobald der Repo-Besitzer einen Pull Request nach main mergt. Anders als im parallelen Agent-Projekt gibt es hier keine Trennung zwischen einem unveraenderlichen "Bootstrap"-Updater und dem eigentlichen Projekt-Code - update.sh gehoert direkt zum Projekt und wird bei jedem Update mit aktualisiert.

Bausteine

  • update.sh (Projekt-Wurzel) - holt die neueste Version des konfigurierten Branches per git pull --ff-only, baut die Docker-Images neu, startet api, web und sync neu und fuehrt (per Default) die Testsuiten aus. Kann jederzeit auch manuell aufgerufen werden, siehe Kommentar am Kopf der Datei fuer die Umgebungsvariablen UPDATE_REMOTE, UPDATE_BRANCH, UPDATE_RUN_TESTS. Nach dem Neustart meldet das Skript ein Event "Monitor: Update eingespielt ()" per POST /api/v1/events/system (Admin-Key aus der .env); schlaegt das fehl, bleibt das Update gueltig.
  • deploy-webhook.py (Projekt-Wurzel) - kleiner HTTP-Server (nur Python-Standardbibliothek, keine Abhaengigkeiten) auf Basis von http.server. Prueft eingehende Codeberg-Webhooks per HMAC-Signatur (X-Forgejo-Signature/X-Gitea-Signature, analog zum bestehenden POST /api/v1/webhooks/codeberg aus API.md) und ruft bei einem Push auf den konfigurierten Branch update.sh auf. Laeuft auf dem Host, nicht im Docker-Compose-Stack
    • update.sh selbst ruft docker compose auf dem Host auf, das waere aus einem Container heraus nur mit riskantem Zugriff auf den Docker-Socket moeglich.
  • deploy/monitor-deploy-webhook.service - systemd-Unit-Vorlage, um deploy-webhook.py dauerhaft im Hintergrund laufen zu lassen.

Manuelle Vorarbeiten auf dem Server

Diese Schritte sind einmalig und nicht Teil dieses Repos (unterschiedlich je nach Server), daher hier nur als Checkliste:

  1. Repo auskecken. git clone https://codeberg.org/fds2610/monitor.git (oder per SSH, falls Push-Zugangsdaten fuer git pull als Deploy-Key/SSH-Key eingerichtet werden) nach z.B. /opt/monitor, Branch main ausgecheckt. Versionierte Dateien duerfen dort nicht lokal veraendert werden - update.sh bricht kontrolliert ab, statt die Aenderungen zu ueberschreiben (Notausgang: UPDATE_ALLOW_DIRTY=1). Unversionierte Dateien neben dem Repo (.env, hosts.conf, monitor-api.conf, credentials.conf) stoeren dagegen nicht, sie bleiben beim Update unangetastet.
  2. Docker + Docker Compose installieren (docker compose version muss funktionieren). Der Benutzer, unter dem deploy-webhook.py laeuft, braucht Mitgliedschaft in der docker-Gruppe (oder aequivalente Rechte), um docker compose ohne sudo aufzurufen.
  3. Python 3 installieren (Standardbibliothek genuegt, keine weiteren Pakete noetig) - mail_fds.py im selben Repo setzt das ohnehin schon voraus.
  4. .env anlegen aus .env.example, insbesondere MONITOR_ADMIN_API_KEY, MONITOR_API_BASE und die neuen Variablen MONITOR_DEPLOY_WEBHOOK_SECRET, MONITOR_DEPLOY_WEBHOOK_PORT, MONITOR_DEPLOY_WEBHOOK_BRANCH (Details siehe dort). Das Secret z.B. mit openssl rand -hex 32 erzeugen.
  5. systemd-Unit einrichten:
    sudo cp deploy/monitor-deploy-webhook.service /etc/systemd/system/
    sudo $EDITOR /etc/systemd/system/monitor-deploy-webhook.service   # Pfade/User/Group anpassen
    sudo systemctl daemon-reload
    sudo systemctl enable --now monitor-deploy-webhook
    sudo systemctl status monitor-deploy-webhook
    
  6. Port/Proxy freischalten. deploy-webhook.py lauscht auf MONITOR_DEPLOY_WEBHOOK_PORT (Default 9099) auf allen Interfaces. Analog zum bestehenden Codeberg-Sync-Webhook muss Proxy/Firewall eingehende Anfragen von Codeberg an diesen Port (bzw. an einen dahinter liegenden Reverse-Proxy-Pfad) durchlassen - alle anderen Dienste (api, web, sync) brauchen dafuer keine Aenderung.
  7. Webhook in Codeberg einrichten (macht der Repo-Besitzer manuell, siehe Issue #36): Repo-Einstellungen -> Webhooks -> Forgejo, Ziel-URL auf deploy-webhook.py (Port aus Schritt 6, ggf. per Proxy auf https://... gemappt), Content-Type application/json, Secret wie in .env (MONITOR_DEPLOY_WEBHOOK_SECRET), Ereignis nur "Push". Ein Merge erzeugt immer einen Push auf den Ziel-Branch, ein eigenes "Pull Request merged"-Event ist daher nicht noetig.
  8. Fallback bei verpasstem Webhook (automatisch, keine Einrichtung): Sinkt im sync-Container die Zahl offener PRs (Merge oder Schliessen), legt er api/data/deploy-requested an. deploy-webhook.py bemerkt die Datei, holt origin/<Branch> und startet update.sh nur, wenn der Stand abweicht. Pfad aenderbar ueber MONITOR_DEPLOY_TRIGGER_FILE. Greift spaetestens beim naechsten Sync (MONITOR_SYNC_INTERVAL), keine zusaetzliche Codeberg-Verbindung. Trifft ein Ausloeser waehrend eines laufenden Updates ein, laeuft danach ein Folgelauf.

Testen

Zustellung testen (Codeberg schickt beim Anlegen automatisch ein ping-Event, sichtbar unter "Letzte Zustellungen" im Webhook selbst). Manuell mit korrekter Signatur:

SECRET=<MONITOR_DEPLOY_WEBHOOK_SECRET aus .env>
BODY='{"ref":"refs/heads/main"}'
SIG=$(python3 -c "import hmac,hashlib,sys; print(hmac.new(sys.argv[1].encode(), sys.argv[2].encode(), hashlib.sha256).hexdigest())" "$SECRET" "$BODY")
curl -i -X POST "http://<server>:9099/" \
  -H "X-Forgejo-Event: push" \
  -H "X-Forgejo-Signature: $SIG" \
  -d "$BODY"

Antwort 202 {"status": "update gestartet"} bedeutet, dass update.sh im Hintergrund laeuft. Der Verlauf landet in MONITOR_DEPLOY_LOG_FILE (Default: deploy-webhook.log neben deploy-webhook.py) sowie im systemd-Journal (journalctl -u monitor-deploy-webhook -f).

Sicherheit

Der Endpunkt ist wie POST /api/v1/webhooks/codeberg ohne Secret grundsaetzlich geschlossen (401) und akzeptiert nur Anfragen mit gueltiger HMAC-Signatur. Er loest im Erfolgsfall lediglich denselben git pull --ff-only + Rebuild aus, den ein Server-Betreiber auch manuell per ./update.sh anstossen wuerde - er bringt also keinen Code auf den Server, der nicht bereits reviewt und manuell nach main gemergt wurde. Diese manuelle Merge-Hürde ist laut Repo-Besitzer (Issue #36) als alleinige Sicherheitsmassnahme ausreichend; zusaetzliche Branch-Protection-Einstellungen im Codeberg-Repo (z.B. kein direkter Push nach main) bleiben trotzdem empfehlenswert, sind aber eine manuelle Repo-Einstellung und nicht Teil dieses Skripts.