Files
GerbilManager/docs/web-deploy.md
Gulum c0ecf2022d WEB-2: Self-hosted public site (publicsite-nginx + POST /api/publish, atomic swap)
POST /api/publish: rendert SiteSnapshot->HTML in _staging_new/, atomic swap ->
live/ (rename, ein Syscall). publicsite-nginx:alpine serviert live/ read-only
auf Port 8081. Shared Volume api(rw)/publicsite(ro). Manager bleibt LAN-only.
5 neue Tests (atomic swap, UTF-8, mehrfach), 184/184 gruen. compose config OK.
Vhost-Snippet + web-deploy.md (Deutsch) beigelegt; <DOMAIN> wartet auf Julian.
2026-06-07 01:44:28 +02:00

4.2 KiB

GerbilManager — Oeffentliche Webseite (Self-Hosted, TrueNAS)

Zielgruppe: Julian. Die oeffentliche Seite (Jimdo-Ersatz) laeuft self-hosted auf der TrueNAS neben dem Manager. Strato-Domain → DynDNS → IP → Julians nginx-Proxy → publicsite-Container (Port 8081).


Architektur

Internet
    |  HTTPS/HTTP
    v
Julians nginx-Reverse-Proxy (laeuft schon auf NAS)
    |  proxy_pass http://127.0.0.1:8081
    v
publicsite (nginx:alpine, Port 8081)  ← liest nur: /usr/share/nginx/html/live/
    |                                             (Shared Volume, read-only)
    | [POST /api/publish im Manager schreibt in dasselbe Volume]
    v
api (.NET, Port 8080 intern)          → schreibt: /data/publicsite/live/
    |                                             (Shared Volume, read-write)
    v
Manager (frontend-nginx, Port 80)     ← LAN-only, NIE internet-exponiert

SICHERHEIT — harte Bedingung:

  • Nur publicsite (Port 8081) wird ins Internet weitergeleitet.
  • Der Manager (API + Frontend, Port 80) hat KEINE Authentifizierung → LAN-only.
  • Der publicsite-nginx proxied NICHT auf die API — er serviert nur statisches HTML.

Erstinstallation

1. Verzeichnis anlegen

mkdir -p /mnt/JailStorage/DockerVolumes/gerbilmanager/publicsite

Das Verzeichnis wird von der API beschrieben (laeuft als root im Container) — keine ACL-Aenderung noetig. Beim ersten POST /api/publish legt die API automatisch live/ und _staging_new/ darunter an.

2. .env erganzen

In deploy/truenas/.env hinzufuegen (oder aus .env.example uebernehmen):

PUBLICSITE_PATH=/mnt/JailStorage/DockerVolumes/gerbilmanager/publicsite
PUBLICSITE_PORT=8081

3. Compose-Stack neu starten

cd /opt/gerbilmanager
docker compose -f deploy/truenas/compose.yaml up -d

Der neue publicsite-Container startet und serviert Port 8081. Solange noch nicht veroeffentlicht wurde, zeigt er einen 404 (live/-Verzeichnis leer).

4. Julians externen nginx konfigurieren

Inhalt von deploy/truenas/vhost-snippet.conf in den bestehenden nginx-Proxy einfuegen (als eigenen server-Block oder per include):

# Auf der NAS, nginx-Konfigverzeichnis (z.B. /etc/nginx/conf.d/ oder sites-available):
nano /etc/nginx/conf.d/gerbilmanager-public.conf
# <DOMAIN> durch den tatsaechlichen Hostnamen ersetzen
nginx -t && nginx -s reload

Seite veroeffentlichen (Publish-Ablauf)

  1. Im Manager einloggen (http://<NAS-IP>/)
  2. Navigiere zu Webseite → Inhalte bearbeiten → Veroeffentlichen
  3. Klick auf "Veroeffentlichen" loest POST /api/publish aus.

Was passiert intern:

POST /api/publish
  → API baut SiteSnapshot aus DB (alle Published-Seiten)
  → SiteRenderer rendert Snapshot → HTML-Dateien (path → content Map)
  → Schreibt Dateien nach /data/publicsite/_staging_new/
  → Atomic Swap: _staging_new/ → live/   (rename = ein Syscall, nie halb-geschrieben)
  → publicsite-nginx serviert beim naechsten Request sofort den neuen Stand
  → Kein Container-Restart, kein Image-Rebuild, kein CI
Response: { "filesPublished": N }

Endergebnis: publicsite-nginx liest sofort den neuen Stand aus live/.


Verifikation

# publicsite-Container laeuft?
docker compose -f deploy/truenas/compose.yaml ps publicsite

# Seite lokal abrufbar?
curl -s http://localhost:8081/ | head -5

# live/-Verzeichnis gefuellt?
ls /mnt/JailStorage/DockerVolumes/gerbilmanager/publicsite/live/

# Oeffentlich erreichbar (nach DNS-Propagation)?
curl -s http://<DOMAIN>/ | grep "Kleine Chaoten"

Sicherheitstrennung (Pflichtcheck)

Was Port Internet-exponiert?
Manager (api + frontend) 80 NEIN — LAN-only
Oeffentliche Seite (publicsite) 8081 Ja, via Julians nginx-Proxy
API-Doku (Scalar) 80/scalar NEIN — LAN-only

Der Manager-nginx (gerbilmanager-frontend, Port 80) und die API (Port 8080 intern) sind NICHT in vhost-snippet.conf eingetragen und NICHT in Julians externem Proxy konfiguriert. Sie sind ausschliesslich im Heimnetz erreichbar.


Hostname noch ausstehend

<DOMAIN> in deploy/truenas/vhost-snippet.conf ist ein Platzhalter. Julian nennt den Hostnamen/Subdomain → ersetzen und nginx neu laden.