version: '3.8' services: web: build: . command: gunicorn config.asgi:application -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000 --workers 3 restart: unless-stopped environment: REDIS_URL: redis://redis:6379/0 # Django necesita escuchar en 0.0.0.0 (ya lo hace gunicorn) volumes: - ${PROJECT_SPACE:-.}/media:/app/media - ${PROJECT_SPACE:-.}/static:/app/static networks: - controlmc_proxy - internal labels: - "controlmc.public=true" - "traefik.enable=true" - "traefik.docker.network=controlmc_proxy" - "traefik.http.routers.${ROUTER_NAME}.rule=Host(`${APP_DOMAIN}`)" - "traefik.http.routers.${ROUTER_NAME}.entrypoints=websecure" - "traefik.http.routers.${ROUTER_NAME}.tls=true" - "traefik.http.routers.${ROUTER_NAME}.tls.certresolver=le" - "traefik.http.services.${ROUTER_NAME}.loadbalancer.server.port=8000" depends_on: - redis mem_limit: 1g redis: image: redis:7-alpine restart: unless-stopped volumes: - ${PROJECT_SPACE:-.}/redis_data:/data networks: - internal mem_limit: 512m # Redis no necesita puertos públicos ni etiquetas Traefik celery: build: . command: celery -A config worker -l info --concurrency=2 restart: unless-stopped environment: REDIS_URL: redis://redis:6379/0 networks: - internal depends_on: - redis mem_limit: 512m tax-api: build: ./tax_api restart: unless-stopped networks: - internal mem_limit: 256m # Si la API de impuestos necesita ser expuesta al público por Traefik, # se deben agregar etiquetas similares a las del servicio 'web' con un ROUTER_NAME diferente. networks: controlmc_proxy: external: true internal: # Red interna para que web, redis, celery y tax-api se comuniquen sin exponerse