# Internet-facing production overlay (Traefik + Let's Encrypt, no host DB ports). # Usage: # docker compose -f deploy/compose/compose.yaml -f deploy/compose/compose.prod.yaml \ # --env-file .env.prod up -d --build # # Requires: DOMAIN (public DNS), ACME_EMAIL, PUBLIC_URL=https://$DOMAIN, strong secrets. services: postgres: # No host ports — only reachable on the compose network. deploy: resources: limits: memory: 1G redis: deploy: resources: limits: memory: 512M rustfs: environment: RUSTFS_CONSOLE_ENABLE: "false" deploy: resources: limits: memory: 1G backend: environment: DEV_MODE: "false" SEED_CURRICULUM: "false" labels: - traefik.http.routers.pargar-api.tls.certresolver=le - traefik.http.routers.pargar-cert-api.tls.certresolver=le deploy: resources: limits: memory: 1G reservations: memory: 256M frontend: labels: - traefik.http.routers.pargar-web.tls.certresolver=le - traefik.http.routers.pargar-cert-web.tls.certresolver=le deploy: resources: limits: memory: 1G reservations: memory: 256M traefik: # v3.6.1+ required for Docker Engine 29+ API negotiation image: traefik@sha256:24841fe2de7304c149343d877d2923b4c8800a38ba015dea9174c23b20e344a0 restart: unless-stopped security_opt: - no-new-privileges:true command: - --providers.docker=true - --providers.docker.exposedbydefault=false - --providers.docker.network=pargar_pargar - --providers.file.directory=/etc/traefik/dynamic - --providers.file.watch=true - --entrypoints.web.address=:80 - --entrypoints.websecure.address=:443 - --entrypoints.web.http.redirections.entrypoint.to=websecure - --entrypoints.web.http.redirections.entrypoint.scheme=https - --entrypoints.web.http.redirections.entrypoint.permanent=true - --entrypoints.web.http.aliasHeadersStrategy=delete - --entrypoints.websecure.http.aliasHeadersStrategy=delete # Allow slow, large uploads (admin video ≤ 200MB); default is 60s. - --entrypoints.web.transport.respondingTimeouts.readTimeout=3600 - --entrypoints.websecure.transport.respondingTimeouts.readTimeout=3600 - --certificatesresolvers.le.acme.email=${ACME_EMAIL:?ACME_EMAIL must be set} - --certificatesresolvers.le.acme.storage=/data/acme.json - --certificatesresolvers.le.acme.httpchallenge=true - --certificatesresolvers.le.acme.httpchallenge.entrypoint=web - --api.dashboard=false - --log.level=WARN - --accesslog=true - --ping=true - --global.checkNewVersion=false - --serversTransport.forwardingTimeouts.dialTimeout=10s - --serversTransport.forwardingTimeouts.responseHeaderTimeout=60s ports: - "80:80" - "[::]:80:80" - "443:443" - "[::]:443:443" volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - ../traefik/dynamic:/etc/traefik/dynamic:ro - traefik_data:/data depends_on: backend: condition: service_healthy frontend: condition: service_healthy healthcheck: test: ["CMD", "traefik", "healthcheck", "--ping"] interval: 10s timeout: 3s retries: 10 deploy: resources: limits: memory: 256M networks: - pargar volumes: traefik_data: