networks: traefik: external: true taiga: driver: bridge volumes: taiga-static: taiga-async-rabbitmq-data: taiga-events-rabbitmq-data: # Shared environment for taiga-back and taiga-async (Celery worker) x-environment: &default-back-environment POSTGRES_DB: ${POSTGRES_DB} POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_HOST: taiga-db TAIGA_SECRET_KEY: ${SECRET_KEY} TAIGA_SITES_SCHEME: ${TAIGA_SCHEME} TAIGA_SITES_DOMAIN: ${DOMAIN} TAIGA_SUBPATH: ${SUBPATH} DEFAULT_FROM_EMAIL: ${EMAIL_HOST_USER} EMAIL_BACKEND: "django.core.mail.backends.${EMAIL_BACKEND}.EmailBackend" EMAIL_USE_TLS: ${EMAIL_USE_TLS} EMAIL_USE_SSL: ${EMAIL_USE_SSL} EMAIL_HOST: ${EMAIL_HOST} EMAIL_PORT: ${EMAIL_PORT} EMAIL_HOST_USER: ${EMAIL_HOST_USER} EMAIL_HOST_PASSWORD: ${EMAIL_HOST_PASSWORD} CELERY_ENABLED: "True" RABBITMQ_USER: ${TAIGA_ASYNC_RABBITMQ_USER} RABBITMQ_PASS: ${TAIGA_ASYNC_RABBITMQ_PASSWORD} RABBITMQ_VHOST: ${TAIGA_ASYNC_RABBITMQ_VHOST} RABBITMQ_HOST: taiga-async-rabbitmq ENABLE_TELEMETRY: ${ENABLE_TELEMETRY} services: # ── Database ──────────────────────────────────────────────────────────────── taiga-db: image: postgres:13 container_name: taiga-db restart: always networks: - taiga environment: POSTGRES_DB: ${POSTGRES_DB} POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} volumes: - /pwspool/software/taiga/db:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"] interval: 5s timeout: 5s retries: 5 # ── Backend ───────────────────────────────────────────────────────────────── taiga-back: image: taigaio/taiga-back:latest container_name: taiga-back restart: always environment: <<: *default-back-environment networks: - taiga depends_on: taiga-db: condition: service_healthy taiga-async-rabbitmq: condition: service_healthy volumes: - taiga-static:/taiga-back/static-root - /pwspool/software/taiga/back/media:/taiga-back/media taiga-async: image: taigaio/taiga-back:latest container_name: taiga-async entrypoint: ["/taiga-back/docker/async_entrypoint.sh"] restart: always environment: <<: *default-back-environment networks: - taiga depends_on: taiga-db: condition: service_healthy taiga-async-rabbitmq: condition: service_healthy taiga-back: condition: service_started volumes: - taiga-static:/taiga-back/static-root - /pwspool/software/taiga/back/media:/taiga-back/media # ── Async RabbitMQ (Celery tasks) ─────────────────────────────────────────── taiga-async-rabbitmq: image: rabbitmq:3.8-management-alpine container_name: taiga-async-rabbitmq restart: always networks: - taiga environment: RABBITMQ_DEFAULT_USER: ${TAIGA_ASYNC_RABBITMQ_USER} RABBITMQ_DEFAULT_PASS: ${TAIGA_ASYNC_RABBITMQ_PASSWORD} RABBITMQ_DEFAULT_VHOST: ${TAIGA_ASYNC_RABBITMQ_VHOST} RABBITMQ_ERLANG_COOKIE: ${RABBITMQ_ERLANG_COOKIE} volumes: - taiga-async-rabbitmq-data:/var/lib/rabbitmq healthcheck: test: ["CMD", "rabbitmq-diagnostics", "check_running", "-q"] interval: 30s timeout: 10s retries: 5 # ── Frontend ───────────────────────────────────────────────────────────────── taiga-front: image: taigaio/taiga-front:latest container_name: taiga-front restart: always environment: TAIGA_URL: "${TAIGA_SCHEME}://${DOMAIN}" TAIGA_WEBSOCKETS_URL: "${WEBSOCKETS_SCHEME}://${DOMAIN}" TAIGA_SUBPATH: "${SUBPATH}" networks: - taiga depends_on: - taiga-back # ── Events (WebSocket) ─────────────────────────────────────────────────────── taiga-events: image: taigaio/taiga-events:latest container_name: taiga-events restart: always environment: RABBITMQ_URL: "amqp://${TAIGA_EVENTS_RABBITMQ_USER}:${TAIGA_EVENTS_RABBITMQ_PASSWORD}@taiga-events-rabbitmq:5672/${TAIGA_EVENTS_RABBITMQ_VHOST}" TAIGA_SECRET_KEY: ${SECRET_KEY} networks: - taiga depends_on: taiga-events-rabbitmq: condition: service_healthy taiga-events-rabbitmq: image: rabbitmq:3.8-management-alpine container_name: taiga-events-rabbitmq restart: always networks: - taiga environment: RABBITMQ_DEFAULT_USER: ${TAIGA_EVENTS_RABBITMQ_USER} RABBITMQ_DEFAULT_PASS: ${TAIGA_EVENTS_RABBITMQ_PASSWORD} RABBITMQ_DEFAULT_VHOST: ${TAIGA_EVENTS_RABBITMQ_VHOST} RABBITMQ_ERLANG_COOKIE: ${RABBITMQ_ERLANG_COOKIE} volumes: - taiga-events-rabbitmq-data:/var/lib/rabbitmq healthcheck: test: ["CMD", "rabbitmq-diagnostics", "check_running", "-q"] interval: 30s timeout: 10s retries: 5 # ── Protected media service ────────────────────────────────────────────────── taiga-protected: image: taigaio/taiga-protected:latest container_name: taiga-protected restart: always environment: SECRET_KEY: ${SECRET_KEY} MAX_AGE: 360 networks: - taiga volumes: - /pwspool/software/taiga/back/media:/taiga-back/media # ── Gateway (nginx, the only service exposed to Traefik) ──────────────────── taiga-gateway: image: nginx:alpine container_name: taiga-gateway restart: always networks: - taiga - traefik depends_on: - taiga-front - taiga-back - taiga-events - taiga-protected volumes: - taiga-static:/taiga/static:ro - /pwspool/software/taiga/back/media:/taiga/media:ro - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro labels: - traefik.enable=true - traefik.http.routers.taiga.rule=Host(`${DOMAIN}`) - traefik.http.routers.taiga.tls=true - traefik.http.routers.taiga.tls.certresolver=lets-encrypt - traefik.http.services.taiga.loadbalancer.server.port=80