Files
HamHam/docs/DEPLOYMENT.md
T

80 lines
6.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Betrieb, Updates und Datensicherung
## Voraussetzungen und Erststart
Docker Engine und Compose v2+, empfohlen mindestens 2 CPU-Kerne und 2 GB RAM (Builds benötigen zeitweise mehr). Unterstützt werden die von Node 24 und PostgreSQL 17 angebotenen Linux-Architekturen; der konkrete ARM64-Test ist im Prüfbericht vermerkt.
```sh
cp .env.example .env
openssl rand -hex 32
# Ergebnis als POSTGRES_PASSWORD in .env eintragen.
docker compose up -d --build
docker compose ps
docker compose logs --tail=100 app
docker compose exec app npm run admin:create -- deinname
```
Passwort wird interaktiv verborgen abgefragt. Der Benutzername besteht aus 3–80 Zeichen (`a-z`, `0-9`, `.`, `_`, `-`); das Passwort hat 12–200 Zeichen. Doppelte Benutzernamen werden abgewiesen. Weitere Administratoren werden ebenfalls über dieses CLI angelegt. Über die CLI kann der Serverbetreiber neue Zugänge erstellen, wenn ein Passwort verloren geht.
App läuft als unprivilegierter Benutzer `node`, PID-1-Verwaltung über `tini`. PostgreSQL ist nur intern erreichbar. `database` und `images` sind persistente Named Volumes. Startup-Migrationen laufen in einer Transaktion unter einem PostgreSQL-Advisory-Lock. HTTP-Healthcheck prüft auch die Datenbankverbindung. Logs gehen nach stdout/stderr. `docker compose down` behält Daten; **`down -v` löscht sie**.
`DATABASE_URL` aus `.env` wird für lokale CLI/Entwicklung verwendet; Compose setzt die interne URL aus `POSTGRES_PASSWORD` zusammen. Deshalb ein URL-sicheres Passwort wählen (z. B. Hex). Der Wert `CHANGE_ME` muss ersetzt werden.
## Adresse und Reverse Proxy
- `HOST_PORT=3000` konfiguriert den Host-Port.
- `APP_ORIGIN` ist exakt die Browseradresse inklusive Scheme und ggf. Port, ohne Pfad; z. B. `https://rezepte.example.org`. Diese Einstellung ist für die Origin-basierte CSRF-Prüfung erforderlich.
- `COOKIE_SECURE=true` hinter HTTPS. Für ausschließlich lokales HTTP `false`.
- Proxy muss `Host` und `X-Forwarded-Proto` korrekt setzen; WebSocket-Unterstützung wird in Produktion nicht benötigt.
- `TRUST_PROXY=true` nur, wenn ausschließlich der vertrauenswürdige Proxy auf den App-Port zugreifen kann und `X-Forwarded-For` **überschreibt**, statt einen beliebigen Clientwert zu übernehmen. Ansonsten werden direkte Zugriffe in einem gemeinsamen IP-Limit zusammengefasst. Zusätzlich gilt immer ein benutzerbezogenes Limit.
- Uploadlimit am Proxy mindestens 10 MB, Importanfragen maximal 2 MB nach JSON-Verpackung; sinnvoller Proxy-Gesamtgrenzwert 11 MB. App prüft die gelesenen Bytes selbst.
- Kein öffentliches Caching für `/admin`, `/api`, dynamische HTML- oder RSC-Antworten. Bilder sind content-addressed-artig per zufälligem Dateinamen versioniert und dürfen langfristig gecacht werden.
- HSTS nach erfolgreicher HTTPS-Einrichtung am vorhandenen Proxy setzen. Keine spezielle Proxysoftware erforderlich.
Session-Cookie: HTTP-only, SameSite Strict, 7 Tage absolute Gültigkeit, optional Secure. Datenbank enthält ausschließlich den SHA-256-Hash des zufälligen 256-Bit-Tokens. Passwortwechsel widerruft alle bisherigen Sessions. Origin-Prüfung gilt auch für Login und Uploads.
## Backup
Ein konsistentes Backup umfasst Datenbank **und** Bilder. Für ein kleines Haushaltskochbuch ist eine kurze Schreibpause am einfachsten:
```sh
mkdir -p backups
docker compose stop app
docker compose exec -T db pg_dump -U hamham -d hamham -Fc > backups/hamham.dump
docker compose run --rm --no-deps --entrypoint tar app -C /app/uploads -czf - . > backups/images.tar.gz
docker compose start app
```
Zusätzlich `.env` sicher und separat sichern. Dumps enthalten Passwort-Hashes und aktive Session-Hashes und sind vertraulich. Backups verschlüsselt außerhalb des Hosts aufbewahren, regelmäßig rotieren und Restore testen. JSON-Export ist ein portables Rezeptformat, aber ersetzt kein vollständiges Backup (keine Bildbytes oder Authentifizierungsdaten).
## Restore
Auf einem Host mit kompatiblem Release und korrekter `.env`:
```sh
docker compose up -d db
docker compose stop app
docker compose exec -T db pg_restore -U hamham -d hamham --clean --if-exists < backups/hamham.dump
docker compose run --rm -T --no-deps --entrypoint tar app -C /app/uploads -xzf - < backups/images.tar.gz
docker compose exec -T db psql -U hamham -d hamham -c 'DELETE FROM sessions;'
docker compose up -d app
```
Vor dem Restore auf bereits benutzten Volumes alte Bilddateien bei Bedarf in ein separates Archiv verschieben. Keine nicht zugeordneten fremden Daten löschen. Anschließend Anmeldung, Bilder, Rezeptzahl und `/api/health` kontrollieren.
## Update und Migrationen
1. Releasehinweise lesen, Backup erstellen.
2. `git pull --ff-only` auf dem gewünschten Release-Branch.
3. `docker compose build --pull app`.
4. `docker compose up -d`.
5. `docker compose logs --tail=100 app` und Healthchecks prüfen.
Migrationen sind nummerierte, unveränderliche SQL-Dateien in `migrations/`. Bereits angewendete Namen stehen in `migrations`. Neue Migrationen müssen vor Auslieferung auf leerer Datenbank und einer Kopie vorhandener Daten getestet werden. Schemaänderungen möglichst additiv und abwärtskompatibel. Kein automatisches destruktives Downgrade: für inkompatible Rückkehr vorheriges Image plus dazugehöriges Datenbank-/Bildbackup wiederherstellen.
## Offline und Timer
Die PWA cached lokale statische Ressourcen und online geöffnete, veröffentlichte Rezept-/Kochseiten. Auch nach clientseitiger Navigation wird eine vollständige Dokumentfassung für die Offline-Nutzung gespeichert. Bereits besuchte öffentliche Listenansichten werden ebenfalls gesichert. Nicht besuchte Seiten zeigen eine klare Offline-Ansicht. Admin- und API-Antworten werden vom Service Worker nicht gecacht. Browser können Cachedateien aus Platzgründen entfernen; offline ist deshalb eine Komfortfunktion, kein Verfügbarkeitsversprechen. Für einen zuverlässigen Kochabend die benötigte Kochseite vorab online öffnen.
Timer speichern absolute Endzeiten und korrigieren ihren Stand nach Navigation, Schlafmodus und Reload. Signalton benötigt eine Nutzeraktion („Ton an“); Betriebssysteme können Hintergrundseiten und Audio pausieren. Für zeitkritische Vorgänge zusätzlich einen Geräte-/Küchentimer verwenden. Wake Lock ist eine progressive Browserfunktion und wird im UI mit seinem tatsächlichen Status angezeigt.