Deploy per Gitea Actions auf 192.168.1.5
Deploy auf den Timer-Server / deploy (push) Failing after 2s

Push auf main rollt den Stand selbst aus, statt ihn von Hand zu kopieren.
Der Runner (pve-runner) liegt im selben LAN wie der Zielhost.

Drei Dinge, die dabei nicht passieren duerfen und deshalb abgesichert sind:

- Die .env, das data-Verzeichnis und node_modules sind vom rsync-Abgleich
  ausgenommen. Das --delete raeumt zwar geloeschte Dateien weg, laesst diese
  Pfade aber in Ruhe (kein --delete-excluded).
- npm ci laeuft auf dem Zielhost, nicht im Runner-Container: bcrypt und
  sqlite3 sind native Module und muessen zur dortigen Umgebung passen.
  Aufgerufen wird es nur, wenn sich backend/package*.json geaendert hat.
- Neu gestartet wird nur bei Aenderungen unter backend/ oder deploy/.
  Eine geaenderte Frontend-Datei wird ausgeliefert, ohne den laufenden
  Dienst anzufassen.

Danach ein Health-Check gegen /health; bleibt die Antwort aus, schlaegt der
Lauf fehl und die letzten Journal-Zeilen stehen im Protokoll.

Die Einrichtung (Deploy-Benutzer, eng gefasste sudo-Regel, Variablen und
Secrets) steht in DEPLOY.md.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-04 17:56:35 +02:00
co-authored by Claude Opus 5
parent a7e77793a8
commit 1cd966a208
2 changed files with 187 additions and 0 deletions
+70
View File
@@ -475,3 +475,73 @@ CSV, Filter, Löschen, Abmelden) sowie ein Durchlauf im echten Browser.
Die App ist klein genug, um sie vollständig zu lesen: `server.js` ~470 Zeilen,
`app.js` ~460 Zeilen, beide durchgehend kommentiert und auf Deutsch beschriftet.
Im Zweifel ist das Lesen der Quelle schneller als das Raten.
---
## Automatischer Deploy per Gitea Actions
Jeder Push auf `main` in `git.handy-insel.de/kerimatilgan/timer-app` rollt den
Stand selbsttaetig auf den Server aus. Der Workflow liegt in
`.gitea/workflows/deploy.yaml` und laesst sich in der Gitea-Oberflaeche unter
"Actions" auch von Hand starten.
### Was der Workflow tut
1. Uebertraegt die versionierten Dateien per `rsync` nach `/opt/timer-app`.
**Nicht angefasst** werden `backend/.env`, `data/` und `node_modules/` —
sie sind vom Abgleich ausgenommen und ueberleben auch das `--delete`,
das geloeschte Dateien auf dem Server aufraeumt.
2. `npm ci --omit=dev` **nur**, wenn sich `backend/package*.json` geaendert hat.
Das laeuft bewusst auf dem Zielhost: `bcrypt` und `sqlite3` sind native
Module und muessen zur dortigen Architektur passen.
3. Neustart des Dienstes **nur**, wenn sich etwas unter `backend/` oder
`deploy/` geaendert hat. Reine Frontend-Aenderungen brauchen keinen.
4. Health-Check gegen `/health` (15 Versuche, 30 s). Antwortet der Dienst
nicht, schlaegt der Lauf fehl und die letzten 40 Journal-Zeilen stehen
im Protokoll.
### Einmalige Einrichtung
Auf dem Zielhost einen Deploy-Benutzer anlegen, ihm das Verzeichnis geben und
den Neustart des einen Dienstes erlauben:
```bash
useradd -r -m -s /bin/bash deploy
mkdir -p /home/deploy/.ssh && chmod 700 /home/deploy/.ssh
echo '<oeffentlicher Schluessel>' >> /home/deploy/.ssh/authorized_keys
chown -R deploy:deploy /home/deploy/.ssh && chmod 600 /home/deploy/.ssh/authorized_keys
# Schreibrecht auf das Anwendungsverzeichnis
chown -R deploy:timerapp /opt/timer-app && chmod -R g+rX /opt/timer-app
# Genau die drei Befehle ohne Passwort - nicht mehr
cat > /etc/sudoers.d/deploy-timer-app <<'EOF'
deploy ALL=(root) NOPASSWD: /bin/systemctl restart timer-app, \
/bin/journalctl -u timer-app *, \
/bin/chown -R timerapp\:timerapp /opt/timer-app
EOF
chmod 440 /etc/sudoers.d/deploy-timer-app
visudo -c
```
Im Repo unter **Settings -> Actions** hinterlegen:
| Art | Name | Wert |
|---|---|---|
| Variable | `DEPLOY_HOST` | `192.168.1.5` |
| Variable | `DEPLOY_USER` | `deploy` |
| Variable | `DEPLOY_PATH` | `/opt/timer-app` |
| Variable | `DEPLOY_SERVICE` | `timer-app` |
| Variable | `DEPLOY_OWNER` | `timerapp:timerapp` |
| Variable | `HEALTH_URL` | `http://127.0.0.1:3003/health` |
| Secret | `DEPLOY_SSH_KEY` | privater Deploy-Schluessel (ganze Datei inkl. BEGIN/END-Zeilen) |
| Secret | `DEPLOY_KNOWN_HOSTS` | `ssh-keyscan 192.168.1.5` — Zeile(n) fuer den Zielhost |
### Grenzen
- Die `.env` wird **nie** ausgerollt. Kommt eine neue Einstellung dazu, gehoert
sie von Hand in die `.env` auf dem Server (Vorlage: `backend/.env.example`),
sonst startet der Dienst nach dem Deploy womoeglich nicht.
- Es gibt keinen automatischen Rollback. Faellt der Health-Check durch, laeuft
der Dienst weiter im Fehlerzustand — der Lauf ist rot und das Journal steht
im Protokoll. Zurueck geht es mit einem Revert-Commit auf `main`.