# ATM10 Stats – Produktion hinter Traefik (DMZ-Server). # cp deploy/.env.example deploy/.env # Werte eintragen # docker compose -f deploy/docker-compose.yml --env-file deploy/.env up -d --build # # Traefik muss am externen Netz ${TRAEFIK_NETWORK} hängen. Nur web und api sind dort angebunden; # die Datenbank ist ausschließlich im internen Netz erreichbar. name: atm10-stats # Outbound proxy (e.g. Squid in the DMZ). The Docker daemon's own proxy setting only covers image pulls; # RUN steps in the build (npm, Google Fonts) and the running API need it passed explicitly. x-proxy-build-args: &proxy-build-args HTTP_PROXY: ${HTTP_PROXY:-} HTTPS_PROXY: ${HTTPS_PROXY:-} NO_PROXY: ${NO_PROXY:-} http_proxy: ${HTTP_PROXY:-} https_proxy: ${HTTPS_PROXY:-} no_proxy: ${NO_PROXY:-} x-backend: &backend build: context: .. dockerfile: backend/Dockerfile args: *proxy-build-args image: atm10-stats/backend:latest restart: unless-stopped env_file: ${ENV_FILE:-.env} environment: # Password via PGPASSWORD (read by the PostgreSQL driver): any character works; in the URL "/", "+" or "@" break it. DATABASE_URL: postgres://atm@db:5432/atm PGPASSWORD: ${POSTGRES_PASSWORD} # Player heads (mc-heads.net) go through the proxy; Compose-internal names and the database never do. # SFTP to the game server is a direct SSH connection and does not use these variables. HTTP_PROXY: ${HTTP_PROXY:-} HTTPS_PROXY: ${HTTPS_PROXY:-} NO_PROXY: ${NO_PROXY:-localhost,127.0.0.1},api,db,web depends_on: db: condition: service_healthy services: db: image: postgres:16-alpine restart: unless-stopped environment: POSTGRES_DB: atm POSTGRES_USER: atm POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD fehlt} volumes: - db-data:/var/lib/postgresql/data networks: [internal] healthcheck: test: ["CMD-SHELL", "pg_isready -U atm -d atm"] interval: 10s timeout: 5s retries: 10 api: <<: *backend command: ["node", "dist/server.js"] networks: [internal, traefik] labels: - traefik.enable=true - traefik.docker.network=${TRAEFIK_NETWORK} # Public API and SSE - traefik.http.routers.atm-api.rule=Host(`${DOMAIN}`) && PathPrefix(`/api`) - traefik.http.routers.atm-api.priority=100 - traefik.http.routers.atm-api.entrypoints=${TRAEFIK_ENTRYPOINT} - traefik.http.routers.atm-api.tls.certresolver=${TRAEFIK_CERTRESOLVER} - traefik.http.routers.atm-api.service=atm-api # Ingest from the game server only (IP allow list, Traefik v3 "ipallowlist") - traefik.http.routers.atm-ingest.rule=Host(`${DOMAIN}`) && PathPrefix(`/api/ingest`) - traefik.http.routers.atm-ingest.priority=200 - traefik.http.routers.atm-ingest.entrypoints=${TRAEFIK_ENTRYPOINT} - traefik.http.routers.atm-ingest.tls.certresolver=${TRAEFIK_CERTRESOLVER} - traefik.http.routers.atm-ingest.middlewares=atm-ingest-allow - traefik.http.routers.atm-ingest.service=atm-api - traefik.http.middlewares.atm-ingest-allow.ipallowlist.sourcerange=${INGEST_ALLOWED_IPS} - traefik.http.services.atm-api.loadbalancer.server.port=3001 worker: <<: *backend command: ["node", "dist/worker.js"] networks: [internal] healthcheck: disable: true web: build: context: .. dockerfile: web/Dockerfile args: *proxy-build-args image: atm10-stats/web:latest restart: unless-stopped environment: API_INTERNAL_URL: http://api:3001 depends_on: [api] networks: [internal, traefik] labels: - traefik.enable=true - traefik.docker.network=${TRAEFIK_NETWORK} - traefik.http.routers.atm-web.rule=Host(`${DOMAIN}`) - traefik.http.routers.atm-web.priority=10 - traefik.http.routers.atm-web.entrypoints=${TRAEFIK_ENTRYPOINT} - traefik.http.routers.atm-web.tls.certresolver=${TRAEFIK_CERTRESOLVER} - traefik.http.services.atm-web.loadbalancer.server.port=3000 backup: image: postgres:16-alpine restart: unless-stopped environment: PGHOST: db PGUSER: atm PGDATABASE: atm PGPASSWORD: ${POSTGRES_PASSWORD} BACKUP_KEEP_DAYS: ${BACKUP_KEEP_DAYS:-14} volumes: - ./backup.sh:/backup.sh:ro - backups:/backups entrypoint: ["/bin/sh", "/backup.sh", "loop"] depends_on: db: condition: service_healthy networks: [internal] networks: internal: traefik: external: true name: ${TRAEFIK_NETWORK:?TRAEFIK_NETWORK fehlt} volumes: db-data: backups: