# Example docker-compose for running the Spanglish API as multiple replicas # behind nginx, with Redis for shared state and Postgres as the database. # # This is a starting point, not a turnkey production setup. It expects a # Dockerfile at backend/Dockerfile that builds the API and runs it on PORT. # # Bring it up with N API replicas: # docker compose -f deploy/docker-compose.scale.yml up --build --scale api=3 # # No em dashes are used in this file by design. services: postgres: image: postgres:16-alpine environment: POSTGRES_USER: spanglish POSTGRES_PASSWORD: spanglish POSTGRES_DB: spanglish # Raise max_connections if DB_POOL_MAX * replicas approaches the default 100. command: ["postgres", "-c", "max_connections=200"] volumes: - pgdata:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U spanglish"] interval: 5s timeout: 3s retries: 10 redis: image: redis:7-alpine # noeviction is deliberate: rate-limit, lock, and lockout keys must never # be evicted for correctness. The cache workload is a single short-TTL key, # so memory pressure is negligible; if caching ever grows, revisit this or # move the cache to its own DB index. command: [ "redis-server", "--appendonly", "yes", "--requirepass", "${REDIS_PASSWORD:-change-me-redis-password}", "--maxmemory", "256mb", "--maxmemory-policy", "noeviction", ] environment: REDISCLI_AUTH: "${REDIS_PASSWORD:-change-me-redis-password}" volumes: - redisdata:/data healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 5s timeout: 3s retries: 10 api: build: context: ../backend environment: NODE_ENV: production PORT: "3001" DB_TYPE: postgres DATABASE_URL: postgresql://spanglish:spanglish@postgres:5432/spanglish DB_POOL_MAX: "15" REDIS_URL: "redis://:${REDIS_PASSWORD:-change-me-redis-password}@redis:6379" JWT_SECRET: change-me-to-a-strong-secret FRONTEND_URL: http://localhost:8080 # Optional S3-compatible storage so uploads are shared across replicas. # If you omit these, mount a shared volume at /app/uploads on every replica. # S3_ENDPOINT: http://garage:3900 # S3_REGION: garage # S3_BUCKET: spanglish-media # S3_ACCESS_KEY_ID: "" # S3_SECRET_ACCESS_KEY: "" # S3_PUBLIC_URL: http://localhost:8080/media expose: - "3001" depends_on: postgres: condition: service_healthy redis: condition: service_healthy # Load balancer across the scaled api replicas. nginx resolves the "api" # service name via Docker's embedded DNS, which round-robins across replicas. lb: image: nginx:alpine ports: - "8080:80" volumes: - ./nginx.scale.conf:/etc/nginx/conf.d/default.conf:ro depends_on: - api volumes: pgdata: redisdata: