# Production Docker Compose for Golf Card Game # # Usage: # # Set required environment variables first # export DB_PASSWORD=your-secure-password # export SECRET_KEY=your-secret-key # export ACME_EMAIL=your-email@example.com # # # Start services # docker-compose -f docker-compose.prod.yml up -d # # # View logs # docker-compose -f docker-compose.prod.yml logs -f app # # # Scale app instances # docker-compose -f docker-compose.prod.yml up -d --scale app=2 services: app: build: context: . dockerfile: Dockerfile environment: - POSTGRES_URL=postgresql://golf:${DB_PASSWORD}@postgres:5432/golf - DATABASE_URL=postgresql://golf:${DB_PASSWORD}@postgres:5432/golf - REDIS_URL=redis://redis:6379 - SECRET_KEY=${SECRET_KEY} - RESEND_API_KEY=${RESEND_API_KEY:-} - EMAIL_FROM=${EMAIL_FROM:-Golf Cards } - SENTRY_DSN=${SENTRY_DSN:-} - ENVIRONMENT=${ENVIRONMENT:-production} - LOG_LEVEL=${LOG_LEVEL:-INFO} - LOG_LEVEL_GAME=${LOG_LEVEL_GAME:-} - LOG_LEVEL_AI=${LOG_LEVEL_AI:-} - LOG_LEVEL_HANDLERS=${LOG_LEVEL_HANDLERS:-} - LOG_LEVEL_ROOM=${LOG_LEVEL_ROOM:-} - LOG_LEVEL_AUTH=${LOG_LEVEL_AUTH:-} - LOG_LEVEL_STORES=${LOG_LEVEL_STORES:-} - BASE_URL=${BASE_URL:-https://golf.example.com} - RATE_LIMIT_ENABLED=true - INVITE_ONLY=true - BOOTSTRAP_ADMIN_USERNAME=${BOOTSTRAP_ADMIN_USERNAME:-} - BOOTSTRAP_ADMIN_PASSWORD=${BOOTSTRAP_ADMIN_PASSWORD:-} - MATCHMAKING_ENABLED=true depends_on: postgres: condition: service_healthy redis: condition: service_healthy deploy: replicas: 1 restart_policy: condition: on-failure max_attempts: 3 resources: limits: memory: 256M reservations: memory: 64M networks: - internal - web labels: - "traefik.enable=true" - "traefik.docker.network=golfgame_web" - "traefik.http.routers.golf.rule=Host(`${DOMAIN:-golf.example.com}`)" - "traefik.http.routers.golf.entrypoints=websecure" - "traefik.http.routers.golf.tls=true" - "traefik.http.routers.golf.tls.certresolver=letsencrypt" # www -> bare domain redirect - "traefik.http.routers.golf-www.rule=Host(`www.${DOMAIN:-golf.example.com}`)" - "traefik.http.routers.golf-www.entrypoints=websecure" - "traefik.http.routers.golf-www.tls=true" - "traefik.http.routers.golf-www.tls.certresolver=letsencrypt" - "traefik.http.routers.golf-www.middlewares=www-redirect" - "traefik.http.middlewares.www-redirect.redirectregex.regex=^https://www\\.(.+)" - "traefik.http.middlewares.www-redirect.redirectregex.replacement=https://$${1}" - "traefik.http.middlewares.www-redirect.redirectregex.permanent=true" - "traefik.http.services.golf.loadbalancer.server.port=8000" # WebSocket sticky sessions - "traefik.http.services.golf.loadbalancer.sticky.cookie=true" - "traefik.http.services.golf.loadbalancer.sticky.cookie.name=golf_server" postgres: image: postgres:16-alpine environment: POSTGRES_DB: golf POSTGRES_USER: golf POSTGRES_PASSWORD: ${DB_PASSWORD} volumes: - postgres_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U golf -d golf"] interval: 10s timeout: 5s retries: 5 networks: - internal deploy: resources: limits: memory: 192M reservations: memory: 64M redis: image: redis:7-alpine command: redis-server --appendonly yes --maxmemory 32mb --maxmemory-policy allkeys-lru volumes: - redis_data:/data healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s retries: 5 networks: - internal deploy: resources: limits: memory: 64M reservations: memory: 16M traefik: image: traefik:v3.6 environment: - DOCKER_API_VERSION=1.44 command: - "--api.dashboard=true" - "--api.insecure=true" - "--accesslog=true" - "--log.level=WARN" - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" - "--entrypoints.web.address=:80" - "--entrypoints.web.http.redirections.entryPoint.to=websecure" - "--entrypoints.web.http.redirections.entryPoint.scheme=https" - "--entrypoints.websecure.address=:443" - "--certificatesresolvers.letsencrypt.acme.httpchallenge=true" - "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web" - "--certificatesresolvers.letsencrypt.acme.email=${ACME_EMAIL}" - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json" ports: - "80:80" - "443:443" volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - letsencrypt:/letsencrypt networks: - web deploy: resources: limits: memory: 64M volumes: postgres_data: redis_data: letsencrypt: networks: internal: driver: bridge web: driver: bridge