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

@@ -1,18 +1,22 @@
# FlorianNetz — Basis-Compose hinter EXTERNEM Traefik.
#
# Ausgerichtet auf das bestehende Setup von feuerwehr_dashboard:
# - externes, von Traefik verwaltetes Netz heißt "frontend" (external: true)
# - Router: entrypoints=websecure, tls + certresolver=letsencrypt
# - explizite Router->Service-Bindung, loadbalancer.server.port=3000
# - traefik.docker.network = das externe "frontend"-Netz
#
# Es gibt bewusst KEINEN eigenen Proxy-/Traefik-Service: Routing/TLS übernimmt
# eine separat betriebene Traefik-Instanz, die am externen Netz "${TRAEFIK_NETWORK}"
# (Default: traefik) lauscht. Dieses Netz muss bereits existieren:
# docker network create traefik
# die separat betriebene Traefik-Instanz am Netz "${TRAEFIK_NETWORK}" (Default:
# frontend). Dieses Netz muss bereits existieren:
# docker network create frontend
#
# Geo-Dienste (osrm, nominatim) sind hier mit ihren Laufzeit-Verträgen definiert;
# das schwergewichtige Daten-Preprocessing/Volume kommt aus docker-compose.geo.yml
# (siehe scripts/prepare-osm-data.sh / infra/geo).
# Postgres/Geo liegen am internen Bridge-Netz (keine veröffentlichten Ports,
# also nicht öffentlich erreichbar) — der App-Container hat über dieses Netz
# zugleich Egress (z. B. für den Authentik-OIDC-Token-Austausch).
#
# Start:
# docker compose --env-file .env up -d
# Lokal ohne Traefik/TLS:
# docker compose -f docker-compose.yml -f docker-compose.override.yml up -d
# Start: docker compose --env-file .env up -d
# Lokal: docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d
services:
app:
@@ -32,13 +36,14 @@ services:
AUTHENTIK_ISSUER: ${AUTHENTIK_ISSUER}
AUTHENTIK_CLIENT_ID: ${AUTHENTIK_CLIENT_ID}
AUTHENTIK_CLIENT_SECRET: ${AUTHENTIK_CLIENT_SECRET}
AUTHENTIK_ADMIN_GROUP: ${AUTHENTIK_ADMIN_GROUP:-floriannetz-admins}
OSRM_URL: http://osrm:5000
NOMINATIM_URL: http://nominatim:8080
GEO_HTTP_TIMEOUT_MS: ${GEO_HTTP_TIMEOUT_MS:-4000}
HAVERSINE_KMH: ${HAVERSINE_KMH:-50}
RUN_SEED: ${RUN_SEED:-false}
networks:
- traefik
- frontend
- internal
healthcheck:
test:
@@ -51,11 +56,12 @@ services:
restart: unless-stopped
labels:
- "traefik.enable=true"
- "traefik.docker.network=${TRAEFIK_NETWORK:-traefik}"
- "traefik.http.routers.floriannetz.rule=Host(`${APP_HOST}`)"
- "traefik.docker.network=${TRAEFIK_NETWORK:-frontend}"
- "traefik.http.routers.floriannetz.entrypoints=websecure"
- "traefik.http.routers.floriannetz.rule=Host(`${APP_HOST}`)"
- "traefik.http.routers.floriannetz.tls=true"
- "traefik.http.routers.floriannetz.tls.certresolver=${TRAEFIK_CERTRESOLVER:-letsencrypt}"
- "traefik.http.routers.floriannetz.service=floriannetz"
- "traefik.http.services.floriannetz.loadbalancer.server.port=3000"
# Security-Header-Middleware (zusätzlich zu next.config.ts; defense-in-depth).
- "traefik.http.routers.floriannetz.middlewares=floriannetz-sechdrs"
@@ -137,10 +143,12 @@ volumes:
nominatim-data:
networks:
# Externes, von der separaten Traefik-Instanz verwaltetes Netz.
traefik:
# Externes, von der separaten Traefik-Instanz verwaltetes Netz (wie im
# feuerwehr_dashboard "frontend"). Muss existieren: docker network create frontend
frontend:
external: true
name: ${TRAEFIK_NETWORK:-traefik}
# Internes Netz: Postgres/Geo sind nur app-intern erreichbar, nicht öffentlich.
name: ${TRAEFIK_NETWORK:-frontend}
# Internes Bridge-Netz: Postgres/Geo ohne veröffentlichte Ports (nicht
# öffentlich), zugleich Egress für den App-Container (Authentik-OIDC).
internal:
internal: true
driver: bridge