Die rote Fahne aus #113 blieb nach dem automatischen Update aus. Code-Pfad und Daten sind in Ordnung (NC-Gantt #333 ist offen und stammt von "tinko"), aber der sync-Container bindet ./api nur als Volume ein. Bei unveraendertem Image und unveraenderter Compose-Konfiguration liess "docker compose up -d" ihn deshalb einfach weiterlaufen. Der --watch-Prozess hatte seine Klassen noch vom alten Stand geladen, uebergab also nie einen author, und countExternalOpenTickets() kam immer auf 0. update.sh erzeugt api und sync deshalb jetzt mit --force-recreate neu. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6.8 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 pergit pull --ff-only, baut die Docker-Images neu, startetapi,webundsyncneu und fuehrt (per Default) die Testsuiten aus.apiundsyncwerden dabei immer neu erzeugt (--force-recreate), weil sie den Code nur per Volume einbinden und der langlebigesync-Prozess neuen PHP-Code sonst erst nach einem manuellen Neustart sieht (Issue #115). Kann jederzeit auch manuell aufgerufen werden, siehe Kommentar am Kopf der Datei fuer die UmgebungsvariablenUPDATE_REMOTE,UPDATE_BRANCH,UPDATE_RUN_TESTS. Nach dem Neustart meldet das Skript ein Event "Monitor: Update eingespielt ()" perPOST /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 vonhttp.server. Prueft eingehende Codeberg-Webhooks per HMAC-Signatur (X-Forgejo-Signature/X-Gitea-Signature, analog zum bestehendenPOST /api/v1/webhooks/codebergaus API.md) und ruft bei einem Push auf den konfigurierten Branchupdate.shauf. Laeuft auf dem Host, nicht im Docker-Compose-Stackupdate.shselbst ruftdocker composeauf 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, umdeploy-webhook.pydauerhaft 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:
- Repo auskecken.
git clone https://codeberg.org/fds2610/monitor.git(oder per SSH, falls Push-Zugangsdaten fuergit pullals Deploy-Key/SSH-Key eingerichtet werden) nach z.B./opt/monitor, Branchmainausgecheckt. Versionierte Dateien duerfen dort nicht lokal veraendert werden -update.shbricht 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. - Docker + Docker Compose installieren (
docker compose versionmuss funktionieren). Der Benutzer, unter demdeploy-webhook.pylaeuft, braucht Mitgliedschaft in derdocker-Gruppe (oder aequivalente Rechte), umdocker composeohnesudoaufzurufen. - Python 3 installieren (Standardbibliothek genuegt, keine weiteren Pakete noetig) -
mail_fds.pyim selben Repo setzt das ohnehin schon voraus. .envanlegen aus.env.example, insbesondereMONITOR_ADMIN_API_KEY,MONITOR_API_BASEund die neuen VariablenMONITOR_DEPLOY_WEBHOOK_SECRET,MONITOR_DEPLOY_WEBHOOK_PORT,MONITOR_DEPLOY_WEBHOOK_BRANCH(Details siehe dort). Das Secret z.B. mitopenssl rand -hex 32erzeugen.- 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 - Port/Proxy freischalten.
deploy-webhook.pylauscht aufMONITOR_DEPLOY_WEBHOOK_PORT(Default9099) 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. - 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 aufhttps://...gemappt), Content-Typeapplication/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. - Fallback bei verpasstem Webhook (automatisch, keine Einrichtung): Sinkt im
sync-Container die Zahl offener PRs (Merge oder Schliessen), legt erapi/data/deploy-requestedan.deploy-webhook.pybemerkt die Datei, holtorigin/<Branch>und startetupdate.shnur, wenn der Stand abweicht. Pfad aenderbar ueberMONITOR_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.