# ============================================================================= # tOS Production Docker Compose # ============================================================================= # Vollstaendiger Produktions-Stack mit optionalem SSL via Caddy. # # Ohne SSL (externer Reverse Proxy): # docker compose -f docker-compose.prod.yml up -d # # Mit Let's Encrypt SSL (Caddy): # docker compose -f docker-compose.prod.yml --profile ssl up -d # # Voraussetzungen: # - docker/.env mit allen Secrets (erstellt durch install.sh) # - Docker Images gebaut (api + web) # ============================================================================= name: tos-prod services: # --------------------------------------------------------------------------- # PostgreSQL Database # --------------------------------------------------------------------------- postgres: image: postgres:16-alpine container_name: tos-postgres restart: unless-stopped environment: POSTGRES_USER: ${POSTGRES_USER:-tos_user} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_DB: ${POSTGRES_DB:-tos_db} POSTGRES_INITDB_ARGS: "--encoding=UTF8 --locale=C" volumes: - postgres_data:/var/lib/postgresql/data - ./postgres/init.sql:/docker-entrypoint-initdb.d/init.sql:ro healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-tos_user} -d ${POSTGRES_DB:-tos_db}"] interval: 10s timeout: 5s retries: 5 start_period: 10s networks: - tos-network # --------------------------------------------------------------------------- # Redis Cache & Queue # --------------------------------------------------------------------------- redis: image: redis:7-alpine container_name: tos-redis restart: unless-stopped command: > redis-server --appendonly yes --maxmemory 256mb --maxmemory-policy allkeys-lru volumes: - redis_data:/data healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s retries: 5 networks: - tos-network # --------------------------------------------------------------------------- # Keycloak Identity & Access Management (Production Mode) # --------------------------------------------------------------------------- keycloak: image: quay.io/keycloak/keycloak:24.0 container_name: tos-keycloak restart: unless-stopped # "start" statt "start-dev" fuer Production (aktiviert Caching, deaktiviert Dev-Features) command: - start - --import-realm environment: KEYCLOAK_ADMIN: ${KEYCLOAK_ADMIN:-admin} KEYCLOAK_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD} KC_DB: postgres KC_DB_URL: jdbc:postgresql://postgres:5432/${POSTGRES_DB:-tos_db} KC_DB_USERNAME: ${POSTGRES_USER:-tos_user} KC_DB_PASSWORD: ${POSTGRES_PASSWORD} # Hostname-Konfiguration fuer Production hinter Reverse Proxy KC_HOSTNAME: auth.${APP_DOMAIN} KC_HOSTNAME_STRICT: "true" KC_HOSTNAME_STRICT_HTTPS: "true" KC_HTTP_ENABLED: "true" KC_HEALTH_ENABLED: "true" KC_PROXY: edge volumes: - ./keycloak/realm-export.json:/opt/keycloak/data/import/realm-export.json:ro healthcheck: # Keycloak 24+ (UBI9) hat kein curl - nutze bash TCP redirect test: > bash -c 'exec 3<>/dev/tcp/localhost/8080 && echo -e "GET /health/ready HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n" >&3 && timeout 2 cat <&3 | grep -q "200 OK"' interval: 30s timeout: 15s retries: 5 start_period: 120s depends_on: postgres: condition: service_healthy networks: - tos-network # --------------------------------------------------------------------------- # tOS API (NestJS Backend) # --------------------------------------------------------------------------- api: build: context: .. dockerfile: apps/api/Dockerfile container_name: tos-api restart: unless-stopped environment: NODE_ENV: production PORT: "3001" API_PREFIX: api DATABASE_URL: postgresql://${POSTGRES_USER:-tos_user}:${POSTGRES_PASSWORD}@postgres:5432/tos_app JWT_SECRET: ${JWT_SECRET} ENCRYPTION_KEY: ${ENCRYPTION_KEY} KEYCLOAK_URL: http://keycloak:8080 KEYCLOAK_REALM: ${KEYCLOAK_REALM:-tOS} KEYCLOAK_CLIENT_ID: ${KEYCLOAK_CLIENT_ID:-tos-backend} KEYCLOAK_CLIENT_SECRET: ${KEYCLOAK_CLIENT_SECRET:-} KEYCLOAK_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD} REDIS_HOST: redis REDIS_PORT: "6379" SETUP_TOKEN: ${SETUP_TOKEN} depends_on: postgres: condition: service_healthy redis: condition: service_healthy keycloak: condition: service_healthy healthcheck: test: ["CMD-SHELL", "wget -qO- http://localhost:3001/api/v1/health/liveness || exit 1"] interval: 30s timeout: 10s retries: 3 start_period: 60s networks: - tos-network # --------------------------------------------------------------------------- # tOS Web Frontend (Next.js) # --------------------------------------------------------------------------- web: build: context: .. dockerfile: apps/web/Dockerfile container_name: tos-web restart: unless-stopped environment: NEXT_PUBLIC_APP_URL: https://${APP_DOMAIN} NEXT_PUBLIC_API_URL: https://${APP_DOMAIN}/api/v1 NEXTAUTH_URL: https://${APP_DOMAIN} NEXTAUTH_SECRET: ${NEXTAUTH_SECRET} KEYCLOAK_CLIENT_ID: ${NEXTAUTH_KEYCLOAK_CLIENT_ID:-tos-nextauth} KEYCLOAK_CLIENT_SECRET: ${NEXTAUTH_KEYCLOAK_CLIENT_SECRET:-} # Browser-seitige Redirects: oeffentliche URL KEYCLOAK_ISSUER: https://auth.${APP_DOMAIN}/realms/${KEYCLOAK_REALM:-tOS} depends_on: api: condition: service_healthy networks: - tos-network # --------------------------------------------------------------------------- # Caddy Reverse Proxy (optional, nur mit --profile ssl) # --------------------------------------------------------------------------- caddy: profiles: ["ssl"] image: caddy:2-alpine container_name: tos-caddy restart: unless-stopped ports: - "80:80" - "443:443" - "443:443/udp" volumes: - ./Caddyfile:/etc/caddy/Caddyfile:ro - caddy_data:/data - caddy_config:/config environment: APP_DOMAIN: ${APP_DOMAIN} LETSENCRYPT_EMAIL: ${LETSENCRYPT_EMAIL:-} depends_on: - web - api - keycloak networks: - tos-network # ============================================================================= # Volumes # ============================================================================= volumes: postgres_data: name: tos-postgres-data redis_data: name: tos-redis-data caddy_data: name: tos-caddy-data caddy_config: name: tos-caddy-config # ============================================================================= # Networks # ============================================================================= networks: tos-network: name: tos-network driver: bridge