300 lines
9.8 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

networks:
traefik:
external: true
plane:
driver: bridge
# Shared environment for all plane-backend services
x-backend-env:
&backend-env
SECRET_KEY: ${SECRET_KEY}
DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@plane-db/${POSTGRES_DB}
REDIS_URL: redis://plane-redis:6379/
AMQP_URL: amqp://${RABBITMQ_USER}:${RABBITMQ_PASSWORD}@plane-mq:5672/
WEB_URL: https://${DOMAIN}
CORS_ALLOWED_ORIGINS: https://${DOMAIN}
DOCKERIZED: 1
GUNICORN_WORKERS: ${GUNICORN_WORKERS:-2}
USE_MINIO: 1
AWS_REGION: us-east-1
AWS_ACCESS_KEY_ID: ${MINIO_ROOT_USER}
AWS_SECRET_ACCESS_KEY: ${MINIO_ROOT_PASSWORD}
AWS_S3_ENDPOINT_URL: http://plane-minio:9000
AWS_S3_BUCKET_NAME: ${MINIO_BUCKET_NAME:-uploads}
FILE_SIZE_LIMIT: ${FILE_SIZE_LIMIT:-5242880}
services:
# ── Database ─────────────────────────────────────────────────────────────────
plane-db:
image: postgres:15.7-alpine
container_name: plane-db
restart: always
networks:
- plane
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
PGDATA: /var/lib/postgresql/data
volumes:
- /pwspool/software/plane/db:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
interval: 5s
timeout: 5s
retries: 5
# ── Cache ─────────────────────────────────────────────────────────────────────
plane-redis:
image: valkey/valkey:7.2.11-alpine
container_name: plane-redis
restart: always
networks:
- plane
volumes:
- /pwspool/software/plane/redis:/data
healthcheck:
test: ["CMD-SHELL", "redis-cli ping"]
interval: 5s
timeout: 5s
retries: 5
# ── Message Queue ─────────────────────────────────────────────────────────────
plane-mq:
image: rabbitmq:3.13.6-management-alpine
container_name: plane-mq
restart: always
networks:
- plane
environment:
RABBITMQ_DEFAULT_USER: ${RABBITMQ_USER}
RABBITMQ_DEFAULT_PASS: ${RABBITMQ_PASSWORD}
RABBITMQ_DEFAULT_VHOST: /
volumes:
- /pwspool/software/plane/rabbitmq:/var/lib/rabbitmq
healthcheck:
test: ["CMD", "rabbitmq-diagnostics", "check_running", "-q"]
interval: 30s
timeout: 10s
retries: 5
# ── Object Storage (MinIO) ────────────────────────────────────────────────────
plane-minio:
image: minio/minio:latest
container_name: plane-minio
restart: always
networks:
- plane
command: server /export --console-address ":9090"
environment:
MINIO_ROOT_USER: ${MINIO_ROOT_USER}
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}
volumes:
- /pwspool/software/plane/minio:/export
healthcheck:
test: ["CMD", "mc", "ready", "local"]
interval: 30s
timeout: 20s
retries: 3
plane-createbuckets:
image: minio/mc:latest
container_name: plane-createbuckets
restart: "no"
networks:
- plane
environment:
MINIO_ROOT_USER: ${MINIO_ROOT_USER}
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}
MINIO_BUCKET_NAME: ${MINIO_BUCKET_NAME:-uploads}
depends_on:
plane-minio:
condition: service_healthy
entrypoint: >
/bin/sh -c "
mc alias set myminio http://plane-minio:9000 $$MINIO_ROOT_USER $$MINIO_ROOT_PASSWORD &&
mc mb myminio/$$MINIO_BUCKET_NAME --ignore-existing"
# ── Migrations (one-shot) ─────────────────────────────────────────────────────
migrator:
image: makeplane/plane-backend:${APP_RELEASE:-stable}
container_name: plane-migrator
restart: "no"
networks:
- plane
command: ./bin/docker-entrypoint-migrator.sh
environment:
<<: *backend-env
depends_on:
plane-db:
condition: service_healthy
plane-redis:
condition: service_healthy
# ── API ───────────────────────────────────────────────────────────────────────
api:
image: makeplane/plane-backend:${APP_RELEASE:-stable}
container_name: plane-api
restart: always
networks:
- plane
command: ./bin/docker-entrypoint-api.sh
environment:
<<: *backend-env
volumes:
- /pwspool/software/plane/logs/api:/logs
depends_on:
plane-db:
condition: service_healthy
plane-redis:
condition: service_healthy
plane-mq:
condition: service_healthy
migrator:
condition: service_completed_successfully
# ── Celery Worker ─────────────────────────────────────────────────────────────
worker:
image: makeplane/plane-backend:${APP_RELEASE:-stable}
container_name: plane-worker
restart: always
networks:
- plane
command: ./bin/docker-entrypoint-worker.sh
environment:
<<: *backend-env
volumes:
- /pwspool/software/plane/logs/worker:/logs
depends_on:
plane-db:
condition: service_healthy
plane-redis:
condition: service_healthy
plane-mq:
condition: service_healthy
migrator:
condition: service_completed_successfully
# ── Celery Beat ───────────────────────────────────────────────────────────────
beat-worker:
image: makeplane/plane-backend:${APP_RELEASE:-stable}
container_name: plane-beat-worker
restart: always
networks:
- plane
command: ./bin/docker-entrypoint-beat.sh
environment:
<<: *backend-env
volumes:
- /pwspool/software/plane/logs/beat:/logs
depends_on:
plane-db:
condition: service_healthy
plane-redis:
condition: service_healthy
plane-mq:
condition: service_healthy
migrator:
condition: service_completed_successfully
# ── Frontend ──────────────────────────────────────────────────────────────────
web:
image: makeplane/plane-frontend:${APP_RELEASE:-stable}
container_name: plane-web
restart: always
networks:
- plane
environment:
NEXT_PUBLIC_API_BASE_URL: https://${DOMAIN}
NEXT_PUBLIC_SPACE_BASE_URL: https://${DOMAIN}/spaces
NEXT_PUBLIC_ADMIN_BASE_URL: https://${DOMAIN}/god-mode
NEXT_PUBLIC_LIVE_BASE_URL: https://${DOMAIN}/live
depends_on:
- api
# ── Admin Dashboard ───────────────────────────────────────────────────────────
admin:
image: makeplane/plane-admin:${APP_RELEASE:-stable}
container_name: plane-admin
restart: always
networks:
- plane
environment:
NEXT_PUBLIC_API_BASE_URL: https://${DOMAIN}
NEXT_PUBLIC_ADMIN_BASE_URL: https://${DOMAIN}/god-mode
depends_on:
- api
# ── Public Space ──────────────────────────────────────────────────────────────
space:
image: makeplane/plane-space:${APP_RELEASE:-stable}
container_name: plane-space
restart: always
networks:
- plane
environment:
NEXT_PUBLIC_API_BASE_URL: https://${DOMAIN}
NEXT_PUBLIC_SPACE_BASE_URL: https://${DOMAIN}/spaces
depends_on:
- api
# ── Live (real-time collaboration) ────────────────────────────────────────────
live:
image: makeplane/plane-live:${APP_RELEASE:-stable}
container_name: plane-live
restart: always
networks:
- plane
environment:
LIVE_BASE_PATH: /live
SECRET_KEY: ${SECRET_KEY}
API_BASE_URL: http://api:8000
depends_on:
- api
# ── Proxy (gateway only service on the Traefik network) ─────────────────────
proxy:
image: makeplane/plane-proxy:${APP_RELEASE:-stable}
container_name: plane-proxy
restart: always
networks:
- plane
- traefik
environment:
# plane-proxy is Caddy — it needs SITE_ADDRESS (listen spec),
# BUCKET_NAME, and FILE_SIZE_LIMIT. Traefik terminates TLS in front
# of it, so Caddy listens plain-HTTP on :80 and issues no certs.
SITE_ADDRESS: ":80"
BUCKET_NAME: ${MINIO_BUCKET_NAME:-uploads}
FILE_SIZE_LIMIT: ${FILE_SIZE_LIMIT:-5242880}
CERT_EMAIL: ""
CERT_ACME_DNS: ""
TRUSTED_PROXIES: "0.0.0.0/0"
depends_on:
- web
- api
- admin
- space
- live
labels:
- traefik.enable=true
- traefik.http.routers.plane.rule=Host(`${DOMAIN}`)
- traefik.http.routers.plane.tls=true
- traefik.http.routers.plane.tls.certresolver=lets-encrypt
- traefik.http.services.plane.loadbalancer.server.port=80
- traefik.docker.network=traefik