# 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 # die separat betriebene Traefik-Instanz am Netz "${TRAEFIK_NETWORK}" (Default: # frontend). Dieses Netz muss bereits existieren: # docker network create frontend # # 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: docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d services: app: build: context: . dockerfile: Dockerfile depends_on: postgres: condition: service_healthy environment: NODE_ENV: production DATABASE_URL: postgresql://${POSTGRES_USER:-floriannetz}:${POSTGRES_PASSWORD:-floriannetz}@postgres:5432/${POSTGRES_DB:-floriannetz} # Forwarded-Header + sichere Cookies hinter Traefik. AUTH_TRUST_HOST: "true" AUTH_URL: https://${APP_HOST} AUTH_SECRET: ${AUTH_SECRET} 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: - frontend - internal healthcheck: test: - CMD-SHELL - "wget -q -O - http://127.0.0.1:3000/api/health | grep -q ok" interval: 30s timeout: 5s retries: 5 start_period: 40s restart: unless-stopped labels: - "traefik.enable=true" - "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" - "traefik.http.middlewares.floriannetz-sechdrs.headers.stsSeconds=63072000" - "traefik.http.middlewares.floriannetz-sechdrs.headers.stsIncludeSubdomains=true" - "traefik.http.middlewares.floriannetz-sechdrs.headers.contentTypeNosniff=true" - "traefik.http.middlewares.floriannetz-sechdrs.headers.frameDeny=true" postgres: image: postgres:16-alpine environment: POSTGRES_USER: ${POSTGRES_USER:-floriannetz} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-floriannetz} POSTGRES_DB: ${POSTGRES_DB:-floriannetz} volumes: - postgres-data:/var/lib/postgresql/data networks: - internal healthcheck: test: - CMD-SHELL - "pg_isready -U ${POSTGRES_USER:-floriannetz} -d ${POSTGRES_DB:-floriannetz}" interval: 10s timeout: 5s retries: 5 start_period: 30s restart: unless-stopped osrm: build: context: . dockerfile: docker/osrm/Dockerfile command: osrm-routed --algorithm mld /data/austria-latest.osrm volumes: - osrm-data:/data networks: - internal expose: - "5000" healthcheck: test: - CMD-SHELL - >- wget -q -O - 'http://localhost:5000/table/v1/driving/15.6229,48.2079;16.3738,48.2082?sources=0' | grep -q '"code":"Ok"' interval: 30s timeout: 5s retries: 5 start_period: 60s restart: unless-stopped nominatim: image: mediagis/nominatim:4.4 environment: PBF_URL: https://download.geofabrik.de/europe/austria-latest.osm.pbf REPLICATION_URL: https://download.geofabrik.de/europe/austria-updates/ IMPORT_STYLE: address NOMINATIM_PASSWORD: ${NOMINATIM_PASSWORD:-nominatim} volumes: - nominatim-data:/var/lib/postgresql/14/main shm_size: 1g networks: - internal expose: - "8080" healthcheck: test: - CMD-SHELL - "wget -q -O - 'http://localhost:8080/status' | grep -q OK" interval: 30s timeout: 5s retries: 5 start_period: 120s restart: unless-stopped volumes: postgres-data: osrm-data: nominatim-data: networks: # 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:-frontend} # Internes Bridge-Netz: Postgres/Geo ohne veröffentlichte Ports (nicht # öffentlich), zugleich Egress für den App-Container (Authentik-OIDC). internal: driver: bridge