deploy: Traefik-Setup an feuerwehr_dashboard angleichen

Abgeglichen mit ~/work/feuerwehr_dashboard/docker-compose.yml:
- externes Traefik-Netz heißt 'frontend' (external: true), nicht 'traefik'
- explizite Router->Service-Bindung (routers.floriannetz.service=floriannetz)
- entrypoints=websecure, tls + certresolver=letsencrypt, port 3000
- traefik.docker.network -> frontend; AUTHENTIK_ADMIN_GROUP an App durchgereicht
- internes Netz als Bridge (statt internal:true): Postgres/Geo ohne Host-Ports,
  aber App hat Egress für Authentik-OIDC
- APP_HOST-Default florian.feuerwehr-rems.at; TRAEFIK_NETWORK-Default frontend
- Doku (deployment-traefik.md) + Makefile-Kommentare angepasst

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude
2026-06-10 12:39:42 +02:00
parent f2578cedab
commit f71cf51eb4
4 changed files with 50 additions and 32 deletions

View File

@@ -18,17 +18,20 @@ Der Stack besteht aus genau vier Services (kein Proxy):
Netze:
- **`traefik`** — externes, von Traefik verwaltetes Netz (`external: true`,
Name aus `TRAEFIK_NETWORK`, Default `traefik`). Nur `app` hängt daran.
- **`internal`** — internes Netz (`internal: true`); Postgres und die Geo-Dienste
sind ausschließlich für die App erreichbar, nie öffentlich.
- **`frontend`** — externes, von Traefik verwaltetes Netz (`external: true`,
Name aus `TRAEFIK_NETWORK`, Default `frontend` — wie im feuerwehr_dashboard).
Nur `app` hängt daran (Proxy↔App).
- **`internal`** — internes Bridge-Netz; Postgres und die Geo-Dienste haben
**keine veröffentlichten Ports** (nicht öffentlich erreichbar). Über dieses
Netz hat der App-Container zugleich **Egress** (z. B. für den
Authentik-OIDC-Token-Austausch).
## Voraussetzungen
Das externe Traefik-Netz muss existieren, bevor der Stack startet:
```bash
docker network create traefik
docker network create frontend
```
Die externe Traefik-Instanz muss:
@@ -36,7 +39,7 @@ Die externe Traefik-Instanz muss:
- einen Entrypoint `websecure` (Port 443) bereitstellen,
- einen Zertifikatsauflöser anbieten, dessen Name `TRAEFIK_CERTRESOLVER`
entspricht (Default `letsencrypt`),
- am Netz `traefik` lauschen (`providers.docker` mit `exposedByDefault=false`).
- am Netz `frontend` lauschen (`providers.docker` mit `exposedByDefault=false`).
Die App-Labels in `docker-compose.yml` setzen Router (`Host(\`${APP_HOST}\`)`,
`entrypoints=websecure`, `tls.certresolver`), Service-Port `3000` und eine
@@ -48,16 +51,17 @@ Vollständiger Vertrag in `.env.example`. Für den Betrieb hinter Traefik zwinge
| Variable | Beispiel / Hinweis |
| ------------------------- | ---------------------------------------------------- |
| `APP_HOST` | öffentlicher Hostname, z. B. `floriannetz.example.at` |
| `APP_HOST` | öffentlicher Hostname, z. B. `florian.feuerwehr-rems.at` |
| `AUTH_URL` | `https://${APP_HOST}` — Basis für Callback + Cookies |
| `AUTH_TRUST_HOST` | `true` — Auth.js vertraut den Forwarded-Headern |
| `AUTH_SECRET` | >= 32 Zeichen (`openssl rand -base64 32`) |
| `AUTHENTIK_ISSUER` | OIDC-Issuer-URL der Authentik-Anwendung |
| `AUTHENTIK_CLIENT_ID` | Client-ID der Authentik-Anwendung |
| `AUTHENTIK_CLIENT_SECRET` | Client-Secret der Authentik-Anwendung |
| `AUTHENTIK_ADMIN_GROUP` | Authentik-Gruppe → platform_admin (Default `floriannetz-admins`; s. authentik-setup.md) |
| `DATABASE_URL` | wird in Compose aus `POSTGRES_*` zusammengesetzt |
| `TRAEFIK_CERTRESOLVER` | Name des Traefik-Zertifikatsauflösers |
| `TRAEFIK_NETWORK` | Name des externen Traefik-Netzes (Default `traefik`) |
| `TRAEFIK_NETWORK` | Name des externen Traefik-Netzes (Default `frontend`) |
## Forwarded-Header & sichere Cookies
@@ -86,6 +90,10 @@ https://${APP_HOST}/api/auth/callback/authentik
Der Pfad `callback/authentik` entspricht dem NextAuth-Provider-Namen. Bei lokaler
Entwicklung zusätzlich `http://localhost:3000/api/auth/callback/authentik`.
**Admin-Zugang über Gruppe:** Dem Provider muss das `groups`-Scope-Mapping
zugewiesen sein, und es muss die Gruppe aus `AUTHENTIK_ADMIN_GROUP` existieren —
nur deren Mitglieder werden `platform_admin`. Details: `authentik-setup.md`.
## Health-Check & Middleware-Allowlist
`GET /api/health` ist **öffentlich** (anonym `200`, nur Liveness, keine
@@ -107,7 +115,7 @@ App-Healthcheck pingen `http://127.0.0.1:3000/api/health`.
```bash
cp .env.example .env # Werte setzen (APP_HOST, AUTH_*, AUTHENTIK_*, POSTGRES_*)
docker network create traefik # einmalig, falls nicht vorhanden
docker network create frontend # einmalig, falls nicht vorhanden
make data # einmalig: OSRM-Geodaten vorbereiten (groß, dauert)
make deploy # build + up
```