CI/CD: Forgejo-Pipeline für automatisierten Build + Deploy auf den VPS #14

Open
opened 2026-07-07 10:05:49 +02:00 by kreativmonkey · 2 comments

Die Hugo-Site (MT-R/poc-hugo-sveltia) soll bei jedem Push auf main automatisch gebaut und auf den VPS deployed werden.

Ziel

  • Forgejo-Actions-Workflow (.forgejo/workflows/deploy.yml) im Repo poc-hugo-sveltia: Hugo (extended, gepinnte Version) baut public/, danach Deploy auf den VPS (NixOS, CX33).
  • Vor dem Build: just import-comments bzw. Datenschritte, soweit sie im CI reproduzierbar sind (Kommentare liegen als committetes data/comments.json vor → kein DB-Zugriff im CI nötig).
  • Deploy-Ziel = statisches Verzeichnis, das der NixOS-nginx-vhost für mt-rad.de ausliefert (siehe #15). Transport z. B. rsync/scp über deploy-key oder Forgejo-Runner mit Zugriff, oder Pull-Deploy.

Rahmen / Vorsicht

  • Die produktive Seite (mta-r.de, ProcessWire bei All-Inkl) bleibt unangetastet.
  • Hängt zusammen mit #15 (Deploy-Ziel/vhost) und #16 (Forgejo/Sveltia).
  • Secrets (deploy key etc.) als Forgejo-Actions-Secrets, nicht committen.

Ergebnis in diesem Issue festhalten: gewählter Deploy-Weg + Begründung, Workflow-Datei(en), was noch manuell einzurichten ist (Runner, Secrets).

Bearbeitung: Subagent (Deploy-Epic 1–3, Modell Opus), zunächst nur Entwurf/Plan — kein Live-Deploy ohne Review.

Die Hugo-Site (`MT-R/poc-hugo-sveltia`) soll bei jedem Push auf `main` automatisch gebaut und auf den VPS deployed werden. **Ziel** - Forgejo-Actions-Workflow (`.forgejo/workflows/deploy.yml`) im Repo `poc-hugo-sveltia`: Hugo (extended, gepinnte Version) baut `public/`, danach Deploy auf den VPS (NixOS, CX33). - Vor dem Build: `just import-comments` bzw. Datenschritte, soweit sie im CI reproduzierbar sind (Kommentare liegen als committetes `data/comments.json` vor → kein DB-Zugriff im CI nötig). - Deploy-Ziel = statisches Verzeichnis, das der NixOS-nginx-vhost für mt-rad.de ausliefert (siehe #15). Transport z. B. rsync/scp über deploy-key oder Forgejo-Runner mit Zugriff, oder Pull-Deploy. **Rahmen / Vorsicht** - **Die produktive Seite (mta-r.de, ProcessWire bei All-Inkl) bleibt unangetastet.** - Hängt zusammen mit #15 (Deploy-Ziel/vhost) und #16 (Forgejo/Sveltia). - Secrets (deploy key etc.) als Forgejo-Actions-Secrets, nicht committen. **Ergebnis in diesem Issue festhalten:** gewählter Deploy-Weg + Begründung, Workflow-Datei(en), was noch manuell einzurichten ist (Runner, Secrets). _Bearbeitung: Subagent (Deploy-Epic 1–3, Modell Opus), zunächst nur Entwurf/Plan — kein Live-Deploy ohne Review._
Author
Owner

Entwurf fertig (nur Workflow + Plan, kein Live-Deploy)

Gewählter Deploy-Weg + Begründung

Push-Deploy: Hugo-Build im CI → rsync über SSH auf das VPS-Zielverzeichnis /docker/mt-rad.de/site (das der nginx-Container aus #15 ausliefert). Einfach, keine zusätzliche Infrastruktur (kein Pull-Agent/Webhook auf dem VPS).

  • Build-Tool = die Repo-eigene Nix-Dev-Shell (nix develop --command hugo --minify). Damit ist die CI-Hugo-Version exakt an local gepinnt — Single Source of Truth ist flake.lock (nixpkgs-25.05 → Hugo v0.147.3 extended, lokal verifiziert). Kein separater Versions-Pin, der divergieren kann. rsync/ssh kommen ebenfalls aus nixpkgs (nix shell) → keine Annahmen übers Runner-Image.
  • Kein DB-Zugriff im CI: data/comments.json ist committet → import-comments entfällt in der Pipeline.
  • Dedizierter Deploy-User mtrad-deploy (deklarativ im NixOS-Modul, nur SSH-Key) statt root — least privilege, Schreibrecht nur auf das Site-Verzeichnis.

Artefakte

  • Repo MT-R/poc-hugo-sveltia, Branch feat/ci-deploy (Worktree, nicht gemergt):
    • .forgejo/workflows/deploy.yml (neu) — Trigger push: main + workflow_dispatch, concurrency-Guard.
    • hugo.toml: baseURLhttps://mt-rad.de/.
    • static/admin/config.yml: site_urlhttps://mt-rad.de (gehört fachlich zu #16).
    • Build lokal grün (21 Pages).

Manuell einzurichten (nur benennen — nichts angelegt)

Forgejo-Actions-Secrets (Repo MT-R/poc-hugo-sveltia oder Org MT-R):

  • VPS_DEPLOY_SSH_KEY — privater ed25519-Key. Erzeugen: ssh-keygen -t ed25519 -C mtrad-ci -f mtrad-ci. Public-Teil → ins NixOS-Modul mt-rad-site.nix (User mtrad-deploy, ersetzt Platzhalter), Private-Teil → dieses Secret.
  • VPS_SSH_KNOWN_HOSTS — Host-Key-Pinning gegen MITM: ssh-keyscan 91.99.145.19.

Runner: poc-hugo-sveltia hat Actions aktiviert (has_actions: true). Es gibt Runner-Aktivität auf der Instanz, aber ob ein Runner mit Label ubuntu-latest für die Org MT-R verfügbar/registriert ist, muss verifiziert werden — ggf. per Org-Runner registrieren (get_runner_registration_token). Der Runner muss nix installieren dürfen (root im Container; catthehacker-Images können das). Alternative, falls nix-in-CI unerwünscht: gepinnte Hugo-extended-Binary direkt laden — habe ich zugunsten der flake.lock-Single-Source verworfen, ist aber ein 3-Zeilen-Swap.

Reihenfolge

Secrets + Runner + Deploy-User (#15) müssen stehen, bevor der erste Push deployt. rsync braucht kein DNS (direkt auf die IP) → CI kann vor dem DNS-Cutover deployen (Reihenfolge siehe #15).

Risiken

  • Deploy-User existiert erst nach colmena apply von #15 → CI-Deploy schlägt vorher fehl (erwartbar).
  • --delete bei rsync: räumt Fremd-Dateien im Zielverzeichnis weg — gewollt, aber das Verzeichnis darf nur der CI gehören (ist so).
## Entwurf fertig (nur Workflow + Plan, kein Live-Deploy) ### Gewählter Deploy-Weg + Begründung **Push-Deploy: Hugo-Build im CI → `rsync` über SSH auf das VPS-Zielverzeichnis** `/docker/mt-rad.de/site` (das der nginx-Container aus #15 ausliefert). Einfach, keine zusätzliche Infrastruktur (kein Pull-Agent/Webhook auf dem VPS). - **Build-Tool = die Repo-eigene Nix-Dev-Shell** (`nix develop --command hugo --minify`). Damit ist die CI-Hugo-Version exakt an local gepinnt — **Single Source of Truth ist `flake.lock`** (nixpkgs-25.05 → Hugo **v0.147.3 extended**, lokal verifiziert). Kein separater Versions-Pin, der divergieren kann. `rsync`/`ssh` kommen ebenfalls aus nixpkgs (`nix shell`) → keine Annahmen übers Runner-Image. - **Kein DB-Zugriff im CI:** `data/comments.json` ist committet → `import-comments` entfällt in der Pipeline. - **Dedizierter Deploy-User** `mtrad-deploy` (deklarativ im NixOS-Modul, nur SSH-Key) statt root — least privilege, Schreibrecht nur auf das Site-Verzeichnis. ### Artefakte - Repo `MT-R/poc-hugo-sveltia`, Branch **`feat/ci-deploy`** (Worktree, nicht gemergt): - `.forgejo/workflows/deploy.yml` (neu) — Trigger `push: main` + `workflow_dispatch`, `concurrency`-Guard. - `hugo.toml`: `baseURL` → `https://mt-rad.de/`. - `static/admin/config.yml`: `site_url` → `https://mt-rad.de` (gehört fachlich zu #16). - Build lokal grün (21 Pages). ### Manuell einzurichten (nur benennen — nichts angelegt) **Forgejo-Actions-Secrets** (Repo `MT-R/poc-hugo-sveltia` oder Org `MT-R`): - `VPS_DEPLOY_SSH_KEY` — privater ed25519-Key. Erzeugen: `ssh-keygen -t ed25519 -C mtrad-ci -f mtrad-ci`. **Public-Teil** → ins NixOS-Modul `mt-rad-site.nix` (User `mtrad-deploy`, ersetzt Platzhalter), **Private-Teil** → dieses Secret. - `VPS_SSH_KNOWN_HOSTS` — Host-Key-Pinning gegen MITM: `ssh-keyscan 91.99.145.19`. **Runner:** poc-hugo-sveltia hat Actions aktiviert (`has_actions: true`). Es gibt Runner-Aktivität auf der Instanz, aber **ob ein Runner mit Label `ubuntu-latest` für die Org `MT-R` verfügbar/registriert ist, muss verifiziert werden** — ggf. per Org-Runner registrieren (`get_runner_registration_token`). Der Runner muss **`nix` installieren dürfen** (root im Container; catthehacker-Images können das). Alternative, falls nix-in-CI unerwünscht: gepinnte Hugo-extended-Binary direkt laden — habe ich zugunsten der `flake.lock`-Single-Source verworfen, ist aber ein 3-Zeilen-Swap. ### Reihenfolge Secrets + Runner + Deploy-User (#15) müssen stehen, **bevor** der erste Push deployt. rsync braucht kein DNS (direkt auf die IP) → CI kann vor dem DNS-Cutover deployen (Reihenfolge siehe #15). ### Risiken - Deploy-User existiert erst nach `colmena apply` von #15 → CI-Deploy schlägt vorher fehl (erwartbar). - `--delete` bei rsync: räumt Fremd-Dateien im Zielverzeichnis weg — gewollt, aber das Verzeichnis darf nur der CI gehören (ist so).
Author
Owner

Stand: Workflows liegen bereit (Branch feat/ci-deploy in poc-hugo-sveltia)

Zwei Forgejo-Actions-Workflows unter .forgejo/workflows/:

deploy.yml — Build & Deploy (Push auf main, täglich per Cron, manuell)

  • Hugo baut aus der gepinnten Nix-Dev-Shell (flake.lock, Single Source of Truth für die Hugo-Version), danach rsync --delete --checksum über SSH nach /docker/mt-rad.de/site (VPS, siehe #15).
  • Täglicher Cron (04:15 UTC): Der Deploy-Build läuft bewusst ohne --buildFuture. Die Republish-Artikel tragen Zukunfts-Daten (Redaktionsplan, Start Ende August, ~1,5/Woche); der nächtliche Rebuild veröffentlicht jeden Artikel an dem Tag, an dem sein Datum erreicht ist — ohne dass jemand committen muss. Ein reiner Push-Trigger täte das nicht.

ci.yml — MR-Check (bei jedem Pull Request gegen main)

  • Reiner Build mit --buildFuture --panicOnWarning, kein Deploy, keine Secrets → läuft auch für Fork-Beiträge gefahrlos und blockiert kaputte Merges. Baut bewusst alles inkl. noch nicht fälliger Artikel, damit Fehler vor dem Merge auffallen. Lokal gegen beide Branches verifiziert (grün).

Noch manuell einzurichten (Voraussetzung, damit es scharf wird)

  1. Forgejo-Runner mit Label ubuntu-latest für die Org MT-R registrieren, der die Nix-Installation ausführen darf (root im Container).
  2. Secrets (Repo- oder Org-Ebene): VPS_DEPLOY_SSH_KEY (privater ed25519-Deploy-Key; öffentlicher Teil im NixOS-Modul, User mtrad-deploy) und VPS_SSH_KNOWN_HOSTS (ssh-keyscan -p 22 91.99.145.19).

Der MR-Check läuft schon ohne Secrets — sobald der Runner steht. Der Deploy wird erst nach Punkt 2 scharf. Gewählter Deploy-Weg = Push-Deploy per rsync über Deploy-Key (kein Pull-Agent auf dem VPS nötig, kein DB-Zugriff im CI, da data/comments.json committet ist).

## Stand: Workflows liegen bereit (Branch `feat/ci-deploy` in `poc-hugo-sveltia`) Zwei Forgejo-Actions-Workflows unter `.forgejo/workflows/`: **`deploy.yml` — Build & Deploy** (Push auf `main`, täglich per Cron, manuell) - Hugo baut aus der gepinnten Nix-Dev-Shell (`flake.lock`, Single Source of Truth für die Hugo-Version), danach `rsync --delete --checksum` über SSH nach `/docker/mt-rad.de/site` (VPS, siehe #15). - **Täglicher Cron (04:15 UTC):** Der Deploy-Build läuft bewusst **ohne** `--buildFuture`. Die Republish-Artikel tragen Zukunfts-Daten (Redaktionsplan, Start Ende August, ~1,5/Woche); der nächtliche Rebuild veröffentlicht jeden Artikel an dem Tag, an dem sein Datum erreicht ist — ohne dass jemand committen muss. Ein reiner Push-Trigger täte das nicht. **`ci.yml` — MR-Check** (bei jedem Pull Request gegen `main`) - Reiner Build mit `--buildFuture --panicOnWarning`, **kein Deploy, keine Secrets** → läuft auch für Fork-Beiträge gefahrlos und blockiert kaputte Merges. Baut bewusst *alles* inkl. noch nicht fälliger Artikel, damit Fehler vor dem Merge auffallen. Lokal gegen beide Branches verifiziert (grün). ### Noch manuell einzurichten (Voraussetzung, damit es scharf wird) 1. **Forgejo-Runner** mit Label `ubuntu-latest` für die Org MT-R registrieren, der die Nix-Installation ausführen darf (root im Container). 2. **Secrets** (Repo- oder Org-Ebene): `VPS_DEPLOY_SSH_KEY` (privater ed25519-Deploy-Key; öffentlicher Teil im NixOS-Modul, User `mtrad-deploy`) und `VPS_SSH_KNOWN_HOSTS` (`ssh-keyscan -p 22 91.99.145.19`). Der **MR-Check läuft schon ohne Secrets** — sobald der Runner steht. Der **Deploy** wird erst nach Punkt 2 scharf. Gewählter Deploy-Weg = Push-Deploy per rsync über Deploy-Key (kein Pull-Agent auf dem VPS nötig, kein DB-Zugriff im CI, da `data/comments.json` committet ist).
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
MT-R/PoC-mt-r#14
No description provided.