services: database: image: postgres:16-alpine container_name: thoughts-db restart: unless-stopped environment: POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_DB: ${POSTGRES_DB} volumes: - postgres_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"] interval: 10s timeout: 5s retries: 5 networks: - internal api: container_name: thoughts-api image: registry.gabrielkaszewski.dev/thoughts:latest restart: unless-stopped environment: RUST_LOG: info RUST_ENV: production DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@database/${POSTGRES_DB} HOST: 0.0.0.0 PORT: 8000 JWT_SECRET: ${JWT_SECRET} BASE_URL: ${BASE_URL} NATS_URL: ${NATS_URL} CORS_ORIGINS: ${CORS_ORIGINS:-*} ALLOW_REGISTRATION: ${ALLOW_REGISTRATION:-false} depends_on: database: condition: service_healthy healthcheck: test: ["CMD", "wget", "-q", "--spider", "http://localhost:8000/health"] interval: 10s timeout: 5s retries: 5 networks: - internal - nats worker: container_name: thoughts-worker image: registry.gabrielkaszewski.dev/thoughts:latest entrypoint: ["./thoughts-worker"] restart: unless-stopped environment: RUST_LOG: info DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@database/${POSTGRES_DB} BASE_URL: ${BASE_URL} NATS_URL: ${NATS_URL} depends_on: database: condition: service_healthy networks: - internal - nats frontend: container_name: thoughts-frontend image: registry.gabrielkaszewski.dev/thoughts-frontend:latest restart: unless-stopped environment: NEXT_PUBLIC_SERVER_SIDE_API_URL: http://api:8000 PORT: 3000 HOSTNAME: 0.0.0.0 depends_on: api: condition: service_healthy healthcheck: test: ["CMD", "curl", "-f", "http://localhost:3000"] interval: 10s timeout: 5s retries: 5 networks: - internal proxy: container_name: thoughts-proxy image: custom-proxy:latest restart: unless-stopped depends_on: frontend: condition: service_healthy api: condition: service_healthy networks: - internal - traefik labels: - "traefik.enable=true" - "traefik.docker.network=traefik" - "traefik.http.routers.thoughts.rule=Host(`thoughts.gabrielkaszewski.dev`)" - "traefik.http.routers.thoughts.entrypoints=web,websecure" - "traefik.http.routers.thoughts.tls.certresolver=letsencrypt" - "traefik.http.routers.thoughts.service=thoughts" - "traefik.http.services.thoughts.loadbalancer.server.port=80" volumes: postgres_data: driver: local networks: # Shared NATS network — must already exist on the host (external: true). # Set NATS_NETWORK env var to match your shared network name (default: nats). nats: name: ${NATS_NETWORK:-nats} external: true traefik: name: traefik external: true internal: driver: bridge