Files
minecraft-atm10-stats/deploy/docker-compose.yml
T
lucashahmannandClaude Opus 5.5 8ad5d00805 fix(deploy): Datenbank-Passwort per PGPASSWORD statt in der Verbindungs-URL
Passwörter mit / + = @ (z. B. aus openssl rand -base64) machten DATABASE_URL ungültig
("TypeError: Invalid URL", api und worker im Neustart-Loop). Lokal mit Passwort "Ab/cd+ef=gh9" geprüft.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 11:37:44 +02:00

135 lines
4.5 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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: