name: investplay-prod services: traefik: image: traefik:v3.0 container_name: investplay-traefik restart: always ports: - "80:80" - "443:443" volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - ./docker/traefik/traefik.yml:/etc/traefik/traefik.yml:ro - ./docker/traefik/dynamic.yml:/etc/traefik/dynamic.yml:ro - letsencrypt:/letsencrypt - traefik-logs:/var/log labels: - "traefik.enable=true" - "traefik.http.routers.dashboard.rule=Host(`traefik.investplay.app`)" - "traefik.http.routers.dashboard.service=api@internal" - "traefik.http.routers.dashboard.middlewares=auth-basic" - "traefik.http.routers.dashboard.tls=true" - "traefik.http.routers.dashboard.tls.certresolver=letsencrypt" networks: - investplay - traefik-public depends_on: - api - web - cms postgres: image: postgres:16-alpine container_name: investplay-postgres restart: always expose: - "5432" volumes: - pgdata:/var/lib/postgresql/data environment: POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_DB: ${POSTGRES_DB:-investplay} healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB:-investplay}"] interval: 10s timeout: 5s retries: 5 start_period: 30s networks: - investplay redis: image: redis:7-alpine container_name: investplay-redis restart: always expose: - "6379" volumes: - redis-data:/data command: redis-server --appendonly yes --loglevel warning healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s retries: 5 start_period: 10s networks: - investplay minio: image: minio/minio:latest container_name: investplay-minio restart: always expose: - "9000" - "9001" volumes: - minio-data:/data environment: MINIO_ROOT_USER_FILE: /run/secrets/minio_root_user MINIO_ROOT_PASSWORD_FILE: /run/secrets/minio_root_password command: server /data --console-address :9001 healthcheck: test: ["CMD", "mc", "ready", "local"] interval: 10s timeout: 5s retries: 5 start_period: 15s secrets: - minio_root_user - minio_root_password networks: - investplay api: build: context: . dockerfile: apps/api/Dockerfile container_name: investplay-api restart: always expose: - "3001" environment: NODE_ENV: production DATABASE_URL: ${DATABASE_URL} REDIS_URL: ${REDIS_URL} MINIO_ENDPOINT: minio MINIO_PORT: 9000 MINIO_USE_SSL: false JWT_SECRET: ${JWT_SECRET} PORT: 3001 env_file: - .env.production healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3001/health"] interval: 30s timeout: 10s start_period: 40s retries: 3 labels: - "traefik.enable=true" - "traefik.http.routers.api.rule=Host(`api.investplay.app`)" - "traefik.http.routers.api.entrypoints=websecure" - "traefik.http.routers.api.tls=true" - "traefik.http.routers.api.tls.certresolver=letsencrypt" - "traefik.http.services.api.loadbalancer.server.port=3001" - "traefik.http.routers.api.middlewares=security-headers,rate-limit,compression" depends_on: postgres: condition: service_healthy redis: condition: service_healthy minio: condition: service_healthy networks: - investplay web: build: context: . dockerfile: apps/web/Dockerfile container_name: investplay-web restart: always expose: - "80" healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:80/"] interval: 30s timeout: 10s start_period: 10s retries: 3 labels: - "traefik.enable=true" - "traefik.http.routers.web.rule=Host(`investplay.app`) || Host(`www.investplay.app`)" - "traefik.http.routers.web.entrypoints=websecure" - "traefik.http.routers.web.tls=true" - "traefik.http.routers.web.tls.certresolver=letsencrypt" - "traefik.http.services.web.loadbalancer.server.port=80" - "traefik.http.routers.web.middlewares=security-headers,compression" depends_on: - api networks: - investplay cms: build: context: . dockerfile: apps/cms/Dockerfile container_name: investplay-cms restart: always expose: - "3000" environment: NODE_ENV: production DATABASE_URL: ${CMS_DATABASE_URL} PAYLOAD_SECRET: ${PAYLOAD_SECRET} PORT: 3000 env_file: - .env.production healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/health"] interval: 30s timeout: 10s start_period: 30s retries: 3 labels: - "traefik.enable=true" - "traefik.http.routers.cms.rule=Host(`cms.investplay.app`)" - "traefik.http.routers.cms.entrypoints=websecure" - "traefik.http.routers.cms.tls=true" - "traefik.http.routers.cms.tls.certresolver=letsencrypt" - "traefik.http.services.cms.loadbalancer.server.port=3000" - "traefik.http.routers.cms.middlewares=security-headers,rate-limit,compression" depends_on: postgres: condition: service_healthy networks: - investplay portainer-agent: image: portainer/agent:latest container_name: investplay-portainer-agent restart: always ports: - "9001:9001" volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - portainer-agent-data:/data networks: - traefik-public secrets: minio_root_user: file: ./secrets/minio_root_user.txt minio_root_password: file: ./secrets/minio_root_password.txt volumes: pgdata: name: investplay-pgdata redis-data: name: investplay-redis-data minio-data: name: investplay-minio-data letsencrypt: name: investplay-letsencrypt traefik-logs: name: investplay-traefik-logs portainer-agent-data: name: investplay-portainer-agent-data networks: investplay: name: investplay driver: bridge internal: true traefik-public: name: traefik-public external: true