docker-compose.src.yml
Rama master · réplica de lectura del repositorio original.
name: pneumatic
services:
postgres:
image: postgres:15-bookworm
container_name: pneumatic-postgres
environment:
PGDATA: ${PGDATA:-var/lib/postgresql/data}
POSTGRES_HOST: ${POSTGRES_HOST:-postgres}
POSTGRES_USER: ${POSTGRES_USER:-postgres_user}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres_password}
POSTGRES_DB: ${POSTGRES_DB:-postgres_db}
POSTGRES_REPLICA_HOST: ${POSTGRES_REPLICA_HOST:-postgres}
POSTGRES_REPLICA_USER: ${POSTGRES_REPLICA_USER:-postgres_user}
POSTGRES_REPLICA_PASSWORD: ${POSTGRES_REPLICA_PASSWORD:-postgres_password}
POSTGRES_REPLICA_DB: ${POSTGRES_REPLICA_DB:-postgres_db}
FILE_POSTGRES_USER: ${FILE_POSTGRES_USER:-pneumatic}
FILE_POSTGRES_PASSWORD: ${FILE_POSTGRES_PASSWORD:-pneumatic}
FILE_POSTGRES_DB: ${FILE_POSTGRES_DB:-pneumatic}
volumes:
- ./postgres/data:/var/lib/postgresql/data:rw
- ./postgres/backups:/backups:rw
- ./scripts/postgres-init:/docker-entrypoint-initdb.d:ro
expose:
- 5432
healthcheck:
test: ["CMD", "pg_isready", "-h", "localhost"]
interval: 5s
start_period: 60s
networks:
- pneumatic
restart: always
redis:
image: redis:8.10.2-trixie
container_name: pneumatic-redis
mem_limit: 512m
memswap_limit: 512m # swap disabled
command: >
--loglevel warning
--databases 16
--dbfilename dump.rdb
--dir /data
--requirepass ${REDIS_PASSWORD:-redis_password}
--save "20 1 300 100 60 10000"
--stop-writes-on-bgsave-error yes
--maxmemory 256mb
--maxmemory-policy volatile-lru
--maxmemory-samples 10
--maxmemory-clients 10%
--lazyfree-lazy-eviction yes
--lazyfree-lazy-expire yes
--lazyfree-lazy-server-del yes
--activedefrag yes
--timeout 300
--tcp-keepalive 300
volumes:
- ./redis/data:/data
expose:
- 6379
networks:
- pneumatic
restart: always
rabbitmq:
container_name: pneumatic-rabbitmq
image: rabbitmq:3.13-management
expose:
- 5672 # broker url
ports:
- 15672:15672 # admin panel
volumes:
- ./rabbitmq/data/:/var/lib/rabbitmq/
- ./rabbitmq/log/:/var/log/rabbitmq
environment:
RABBITMQ_DEFAULT_USER: ${RABBITMQ_USER:-rabbitmq_user}
RABBITMQ_DEFAULT_PASS: ${RABBITMQ_PASSWORD:-rabbitmq_password}
networks:
- pneumatic
backend:
build:
context: ./backend
image: pneumaticworkflow/pneumatic-backend:${TAG:-src}
container_name: pneumatic-backend
command: >
sh -c "python manage.py migrate &&
python manage.py collectstatic --no-input &&
python manage.py init_periodic_tasks &&
python manage.py compilemessages &&
gunicorn src.asgi:application --workers ${WORKERS_COUNT:-2} -k uvicorn.workers.UvicornWorker --worker-tmp-dir /dev/shm --bind unix:/tmp/gunicorn/pneumatic-backend.sock --timeout 200"
environment:
BACKEND_URL: ${BACKEND_URL:-http://localhost:8001}
FRONTEND_URL: ${FRONTEND_URL:-http://localhost}
FORMS_URL: ${FORMS_URL:-http://localhost/forms}
ENVIRONMENT: ${ENVIRONMENT:-Production}
RELEASE: ${RELEASE:-1.0.0}
LANGUAGE_CODE: ${LANGUAGE_CODE:-en} # Allowed values: en, fr, de, es, ru
CAPTCHA: ${CAPTCHA:-no}
RECAPTCHA_SITE_KEY: ${RECAPTCHA_SITE_KEY:-}
RECAPTCHA_SECRET_KEY: ${RECAPTCHA_SECRET_KEY:-}
RECAPTCHA_TESTING: ${RECAPTCHA_TESTING:-no}
ANALYTICS: ${ANALYTICS:-no}
ANALYTICS_DEBUG: ${ANALYTICS_DEBUG:-no}
ANALYTICS_WRITE_KEY: ${ANALYTICS_WRITE_KEY:-}
BILLING: ${BILLING:-no}
STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}
STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}
STRIPE_WEBHOOK_IP_WHITELIST: ${STRIPE_WEBHOOK_IP_WHITELIST:-}
SIGNUP: ${SIGNUP:-yes}
MS_AUTH: ${MS_AUTH:-no}
MS_CLIENT_ID: ${MS_CLIENT_ID:-}
MS_CLIENT_SECRET: ${MS_CLIENT_SECRET:-}
MS_AUTHORITY: ${MS_AUTHORITY:-}
GOOGLE_AUTH: ${GOOGLE_AUTH:-no}
GOOGLE_OAUTH2_CLIENT_ID: ${GOOGLE_OAUTH2_CLIENT_ID:-}
GOOGLE_OAUTH2_CLIENT_SECRET: ${GOOGLE_OAUTH2_CLIENT_SECRET:-}
GOOGLE_OAUTH2_REDIRECT_URI: ${GOOGLE_OAUTH2_REDIRECT_URI:-}
SSO_AUTH: ${SSO_AUTH:-no}
SSO_PROVIDER: ${SSO_PROVIDER:-} # Allowed values: okta, auth0
OKTA_DOMAIN: ${OKTA_DOMAIN:-}
OKTA_CLIENT_ID: ${OKTA_CLIENT_ID:-}
OKTA_CLIENT_SECRET: ${OKTA_CLIENT_SECRET:-}
OKTA_REDIRECT_URI: ${OKTA_REDIRECT_URI:-}
AUTH0_CLIENT_ID: ${AUTH0_CLIENT_ID:-}
AUTH0_CLIENT_SECRET: ${AUTH0_CLIENT_SECRET:-}
AUTH0_DOMAIN: ${AUTH0_DOMAIN:-}
AUTH0_REDIRECT_URI: ${AUTH0_REDIRECT_URI:-}
EMAIL: ${EMAIL:-no} # Disable send emails
EMAIL_PROVIDER: ${EMAIL_PROVIDER:-}
CIO_WEBHOOK_API_VERSION: ${CIO_WEBHOOK_API_VERSION:-}
CIO_WEBHOOK_API_KEY: ${CIO_WEBHOOK_API_KEY:-}
CIO_TRANSACTIONAL_API_KEY: ${CIO_TRANSACTIONAL_API_KEY:-}
CIO_TEMPLATE__RESET_PASSWORD: ${CIO_TEMPLATE__RESET_PASSWORD:-}
CIO_TEMPLATE__INVITE: ${CIO_TEMPLATE__INVITE:-}
CIO_TEMPLATE__USER_DEACTIVATED: ${CIO_TEMPLATE__USER_DEACTIVATED:-}
CIO_TEMPLATE__NEW_TASK: ${CIO_TEMPLATE__NEW_TASK:-}
CIO_TEMPLATE__TASK_RETURNED: ${CIO_TEMPLATE__TASK_RETURNED:-}
CIO_TEMPLATE__ACCOUNT_VERIFICATION: ${CIO_TEMPLATE__ACCOUNT_VERIFICATION:-}
CIO_TEMPLATE__WORKFLOWS_DIGEST: ${CIO_TEMPLATE__WORKFLOWS_DIGEST:-}
CIO_TEMPLATE__TASKS_DIGEST: ${CIO_TEMPLATE__TASKS_DIGEST:-}
CIO_TEMPLATE__USER_TRANSFER: ${CIO_TEMPLATE__USER_TRANSFER:-}
CIO_TEMPLATE__UNREAD_NOTIFICATIONS: ${CIO_TEMPLATE__UNREAD_NOTIFICATIONS:-}
CIO_TEMPLATE__GUEST_NEW_TASK: ${CIO_TEMPLATE__GUEST_NEW_TASK:-}
CIO_TEMPLATE__OVERDUE_TASK: ${CIO_TEMPLATE__OVERDUE_TASK:-}
CIO_TEMPLATE__MENTION: ${CIO_TEMPLATE__MENTION:-}
CIO_TEMPLATE__TASK_REMINDER: ${CIO_TEMPLATE__TASK_REMINDER:-}
CIO_TEMPLATE__COMPLETE_WORKFLOW: ${CIO_TEMPLATE__COMPLETE_WORKFLOW:-}
CIO_TEMPLATE__VACATION_DELEGATION: ${CIO_TEMPLATE__VACATION_DELEGATION:-}
EMAIL_HOST: ${EMAIL_HOST:-}
EMAIL_PORT: ${EMAIL_PORT:-}
EMAIL_HOST_USER: ${EMAIL_HOST_USER:-}
EMAIL_HOST_PASSWORD: ${EMAIL_HOST_PASSWORD:-}
EMAIL_USE_TLS: ${EMAIL_USE_TLS:-}
EMAIL_USE_SSL: ${EMAIL_USE_SSL:-}
EMAIL_TIMEOUT: ${EMAIL_TIMEOUT:-}
AI: ${AI:-no}
AI_PROVIDER: ${AI_PROVIDER:-}
OPENAI_API_KEY: ${OPENAI_API_KEY:-}
OPENAI_API_ORG: ${OPENAI_API_ORG:-}
AI_HTTP_PROXY: ${AI_HTTP_PROXY:-}
AI_HTTPS_PROXY: ${AI_HTTPS_PROXY:-}
PUSH: ${PUSH:-no}
PUSH_PROVIDER: ${PUSH_PROVIDER:-}
FIREBASE_PUSH_APPLICATION_CREDENTIALS: ${FIREBASE_PUSH_APPLICATION_CREDENTIALS:-/pneumatic_backend/firebase-push.json}
SENTRY_DSN: ${SENTRY_DSN:-}
POSTGRES_HOST: ${POSTGRES_HOST:-postgres}
POSTGRES_USER: ${POSTGRES_USER:-postgres_user}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres_password}
POSTGRES_DB: ${POSTGRES_DB:-postgres_db}
POSTGRES_REPLICA_HOST: ${POSTGRES_REPLICA_HOST:-postgres}
POSTGRES_REPLICA_USER: ${POSTGRES_REPLICA_USER:-postgres_user}
POSTGRES_REPLICA_PASSWORD: ${POSTGRES_REPLICA_PASSWORD:-postgres_password}
POSTGRES_REPLICA_DB: ${POSTGRES_REPLICA_DB:-postgres_db}
DJANGO_DEBUG: ${DJANGO_DEBUG:-no}
ADMIN_PATH: ${ADMIN_PATH:-admin}
DJANGO_SECRET_KEY: ${DJANGO_SECRET_KEY:-django_secret_django_secret_django_secret}
DJANGO_SETTINGS_MODULE: src.settings
AUTH_REDIS_URL: "redis://:${REDIS_PASSWORD:-redis_password}@redis:6379/1"
CACHE_REDIS_URL: "redis://:${REDIS_PASSWORD:-redis_password}@redis:6379/0"
CHANNELS_REDIS_URL: "redis://:${REDIS_PASSWORD:-redis_password}@redis:6379/2"
SESSION_REDIS_URL: "redis://:${REDIS_PASSWORD:-redis_password}@redis:6379/3"
CELERY_BROKER_URL: "amqp://${RABBITMQ_USER:-rabbitmq_user}:${RABBITMQ_PASSWORD:-rabbitmq_password}@rabbitmq:5672"
ALLOWED_HOSTS: "pneumatic-nginx"
VERIFICATION_CHECK: no
CORS_ORIGIN_ALLOW_ALL: no
CORS_ALLOW_CREDENTIALS: yes
CORS_ORIGIN_WHITELIST: "http://localhost:8000"
ENABLE_LOGGING: ${ENABLE_LOGGING:-no}
FILE_SERVICE_URL: ${FILE_SERVICE_URL:-http://localhost/files}
# Migration only: direct DB access for sync_files_to_file_service / run_file_migration.
# Can be removed after all accounts are migrated to file-service.
FILE_POSTGRES_USER: ${FILE_POSTGRES_USER:-pneumatic}
FILE_POSTGRES_PASSWORD: ${FILE_POSTGRES_PASSWORD:-pneumatic}
FILE_POSTGRES_DB: ${FILE_POSTGRES_DB:-pneumatic}
FILE_POSTGRES_HOST: ${FILE_POSTGRES_HOST:-postgres}
FILE_POSTGRES_PORT: ${FILE_POSTGRES_PORT:-5432}
LOGS_BACKEND: ${LOGS_BACKEND:-}
LOGS_REDIS_URL: "redis://:${REDIS_PASSWORD:-redis_password}@redis:6379/4"
LOGS_OTLP_ENDPOINT: ${LOGS_OTLP_ENDPOINT:-http://otel-collector:4318}
LOGS_STREAM_MAXLEN: ${LOGS_STREAM_MAXLEN:-250000}
LOGS_CONSUMER_BATCH_SIZE: ${LOGS_CONSUMER_BATCH_SIZE:-1000}
expose:
- 8000
volumes:
- ./backend:/pneumatic_backend
- backend-socket:/tmp/gunicorn
- backend-staticfiles:/pneumatic_backend/staticfiles
depends_on:
- postgres
- rabbitmq
- redis
healthcheck:
test: ["CMD", "pg_isready", "-h", postgres]
interval: 5s
timeout: 5s
retries: 10
networks:
- pneumatic
restart: always
celery:
build:
context: ./backend
image: pneumaticworkflow/pneumatic-celery:${TAG:-src}
container_name: pneumatic-celery
environment:
BACKEND_URL: ${BACKEND_URL:-http://localhost:8001}
FRONTEND_URL: ${FRONTEND_URL:-http://localhost}
FORMS_URL: ${FORMS_URL:-http://localhost/forms}
ENVIRONMENT: ${ENVIRONMENT:-Production}
RELEASE: ${RELEASE:-1.0.0}
LANGUAGE_CODE: ${LANGUAGE_CODE:-en} # Allowed values: en, fr, de, es, ru
CAPTCHA: ${CAPTCHA:-no}
RECAPTCHA_SITE_KEY: ${RECAPTCHA_SITE_KEY:-}
RECAPTCHA_SECRET_KEY: ${RECAPTCHA_SECRET_KEY:-}
RECAPTCHA_TESTING: ${RECAPTCHA_TESTING:-no}
ANALYTICS: ${ANALYTICS:-no}
ANALYTICS_DEBUG: ${ANALYTICS_DEBUG:-no}
ANALYTICS_WRITE_KEY: ${ANALYTICS_WRITE_KEY:-}
BILLING: ${BILLING:-no}
STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}
STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}
STRIPE_WEBHOOK_IP_WHITELIST: ${STRIPE_WEBHOOK_IP_WHITELIST:-}
SIGNUP: ${SIGNUP:-yes}
MS_AUTH: ${MS_AUTH:-no}
MS_CLIENT_ID: ${MS_CLIENT_ID:-}
MS_CLIENT_SECRET: ${MS_CLIENT_SECRET:-}
MS_AUTHORITY: ${MS_AUTHORITY:-}
GOOGLE_AUTH: ${GOOGLE_AUTH:-no}
GOOGLE_OAUTH2_CLIENT_ID: ${GOOGLE_OAUTH2_CLIENT_ID:-}
GOOGLE_OAUTH2_CLIENT_SECRET: ${GOOGLE_OAUTH2_CLIENT_SECRET:-}
GOOGLE_OAUTH2_REDIRECT_URI: ${GOOGLE_OAUTH2_REDIRECT_URI:-}
SSO_AUTH: ${SSO_AUTH:-no}
SSO_PROVIDER: ${SSO_PROVIDER:-} # Allowed values: okta, auth0
OKTA_DOMAIN: ${OKTA_DOMAIN:-}
OKTA_CLIENT_ID: ${OKTA_CLIENT_ID:-}
OKTA_CLIENT_SECRET: ${OKTA_CLIENT_SECRET:-}
OKTA_REDIRECT_URI: ${OKTA_REDIRECT_URI:-}
AUTH0_CLIENT_ID: ${AUTH0_CLIENT_ID:-}
AUTH0_CLIENT_SECRET: ${AUTH0_CLIENT_SECRET:-}
AUTH0_DOMAIN: ${AUTH0_DOMAIN:-}
AUTH0_REDIRECT_URI: ${AUTH0_REDIRECT_URI:-}
EMAIL: ${EMAIL:-no} # Disable send emails
EMAIL_PROVIDER: ${EMAIL_PROVIDER:-}
CIO_WEBHOOK_API_VERSION: ${CIO_WEBHOOK_API_VERSION:-}
CIO_WEBHOOK_API_KEY: ${CIO_WEBHOOK_API_KEY:-}
CIO_TRANSACTIONAL_API_KEY: ${CIO_TRANSACTIONAL_API_KEY:-}
CIO_TEMPLATE__RESET_PASSWORD: ${CIO_TEMPLATE__RESET_PASSWORD:-}
CIO_TEMPLATE__INVITE: ${CIO_TEMPLATE__INVITE:-}
CIO_TEMPLATE__USER_DEACTIVATED: ${CIO_TEMPLATE__USER_DEACTIVATED:-}
CIO_TEMPLATE__NEW_TASK: ${CIO_TEMPLATE__NEW_TASK:-}
CIO_TEMPLATE__TASK_RETURNED: ${CIO_TEMPLATE__TASK_RETURNED:-}
CIO_TEMPLATE__ACCOUNT_VERIFICATION: ${CIO_TEMPLATE__ACCOUNT_VERIFICATION:-}
CIO_TEMPLATE__WORKFLOWS_DIGEST: ${CIO_TEMPLATE__WORKFLOWS_DIGEST:-}
CIO_TEMPLATE__TASKS_DIGEST: ${CIO_TEMPLATE__TASKS_DIGEST:-}
CIO_TEMPLATE__USER_TRANSFER: ${CIO_TEMPLATE__USER_TRANSFER:-}
CIO_TEMPLATE__UNREAD_NOTIFICATIONS: ${CIO_TEMPLATE__UNREAD_NOTIFICATIONS:-}
CIO_TEMPLATE__GUEST_NEW_TASK: ${CIO_TEMPLATE__GUEST_NEW_TASK:-}
CIO_TEMPLATE__OVERDUE_TASK: ${CIO_TEMPLATE__OVERDUE_TASK:-}
CIO_TEMPLATE__MENTION: ${CIO_TEMPLATE__MENTION:-}
CIO_TEMPLATE__TASK_REMINDER: ${CIO_TEMPLATE__TASK_REMINDER:-}
CIO_TEMPLATE__COMPLETE_WORKFLOW: ${CIO_TEMPLATE__COMPLETE_WORKFLOW:-}
CIO_TEMPLATE__VACATION_DELEGATION: ${CIO_TEMPLATE__VACATION_DELEGATION:-}
EMAIL_HOST: ${EMAIL_HOST:-}
EMAIL_PORT: ${EMAIL_PORT:-}
EMAIL_HOST_USER: ${EMAIL_HOST_USER:-}
EMAIL_HOST_PASSWORD: ${EMAIL_HOST_PASSWORD:-}
EMAIL_USE_TLS: ${EMAIL_USE_TLS:-}
EMAIL_USE_SSL: ${EMAIL_USE_SSL:-}
EMAIL_TIMEOUT: ${EMAIL_TIMEOUT:-}
AI: ${AI:-no}
AI_PROVIDER: ${AI_PROVIDER:-}
OPENAI_API_KEY: ${OPENAI_API_KEY:-}
OPENAI_API_ORG: ${OPENAI_API_ORG:-}
AI_HTTP_PROXY: ${AI_HTTP_PROXY:-}
AI_HTTPS_PROXY: ${AI_HTTPS_PROXY:-}
PUSH: ${PUSH:-no}
PUSH_PROVIDER: ${PUSH_PROVIDER:-}
FIREBASE_PUSH_APPLICATION_CREDENTIALS: ${FIREBASE_PUSH_APPLICATION_CREDENTIALS:-/pneumatic_backend/firebase-push.json}
SENTRY_DSN: ${SENTRY_DSN:-}
POSTGRES_HOST: ${POSTGRES_HOST:-postgres}
POSTGRES_USER: ${POSTGRES_USER:-postgres_user}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres_password}
POSTGRES_DB: ${POSTGRES_DB:-postgres_db}
POSTGRES_REPLICA_HOST: ${POSTGRES_REPLICA_HOST:-postgres}
POSTGRES_REPLICA_USER: ${POSTGRES_REPLICA_USER:-postgres_user}
POSTGRES_REPLICA_PASSWORD: ${POSTGRES_REPLICA_PASSWORD:-postgres_password}
POSTGRES_REPLICA_DB: ${POSTGRES_REPLICA_DB:-postgres_db}
DJANGO_DEBUG: ${DJANGO_DEBUG:-no}
ADMIN_PATH: ${ADMIN_PATH:-admin}
DJANGO_SECRET_KEY: ${DJANGO_SECRET_KEY:-django_secret_django_secret_django_secret}
DJANGO_SETTINGS_MODULE: src.settings
AUTH_REDIS_URL: "redis://:${REDIS_PASSWORD:-redis_password}@redis:6379/1"
CACHE_REDIS_URL: "redis://:${REDIS_PASSWORD:-redis_password}@redis:6379/0"
CHANNELS_REDIS_URL: "redis://:${REDIS_PASSWORD:-redis_password}@redis:6379/2"
SESSION_REDIS_URL: "redis://:${REDIS_PASSWORD:-redis_password}@redis:6379/3"
CELERY_BROKER_URL: "amqp://${RABBITMQ_USER:-rabbitmq_user}:${RABBITMQ_PASSWORD:-rabbitmq_password}@rabbitmq:5672"
ALLOWED_HOSTS: "pneumatic-nginx"
VERIFICATION_CHECK: no
CORS_ORIGIN_ALLOW_ALL: no
CORS_ALLOW_CREDENTIALS: yes
CORS_ORIGIN_WHITELIST: "http://localhost:8000"
ENABLE_LOGGING: ${ENABLE_LOGGING:-no}
FILE_SERVICE_URL: ${FILE_SERVICE_URL:-http://localhost/files}
# Migration only: direct DB access for sync_files_to_file_service / run_file_migration.
# Can be removed after all accounts are migrated to file-service.
FILE_POSTGRES_USER: ${FILE_POSTGRES_USER:-pneumatic}
FILE_POSTGRES_PASSWORD: ${FILE_POSTGRES_PASSWORD:-pneumatic}
FILE_POSTGRES_DB: ${FILE_POSTGRES_DB:-pneumatic}
FILE_POSTGRES_HOST: ${FILE_POSTGRES_HOST:-postgres}
FILE_POSTGRES_PORT: ${FILE_POSTGRES_PORT:-5432}
LOGS_BACKEND: ${LOGS_BACKEND:-}
LOGS_REDIS_URL: "redis://:${REDIS_PASSWORD:-redis_password}@redis:6379/4"
LOGS_OTLP_ENDPOINT: ${LOGS_OTLP_ENDPOINT:-http://otel-collector:4318}
LOGS_STREAM_MAXLEN: ${LOGS_STREAM_MAXLEN:-250000}
LOGS_CONSUMER_BATCH_SIZE: ${LOGS_CONSUMER_BATCH_SIZE:-1000}
volumes:
- ./backend:/pneumatic_backend
command: >
sh -c "celery --app src.celery_app:app worker -l warning"
depends_on:
- postgres
- rabbitmq
- redis
networks:
- pneumatic
restart: always
celery-beat:
build:
context: ./backend
image: pneumaticworkflow/pneumatic-celery-beat:${TAG:-src}
container_name: pneumatic-celery-beat
environment:
BACKEND_URL: ${BACKEND_URL:-http://localhost:8001}
FRONTEND_URL: ${FRONTEND_URL:-http://localhost}
FORMS_URL: ${FORMS_URL:-http://localhost/forms}
ENVIRONMENT: ${ENVIRONMENT:-Production}
RELEASE: ${RELEASE:-1.0.0}
LANGUAGE_CODE: ${LANGUAGE_CODE:-en} # Allowed values: en, fr, de, es, ru
CAPTCHA: ${CAPTCHA:-no}
RECAPTCHA_SITE_KEY: ${RECAPTCHA_SITE_KEY:-}
RECAPTCHA_SECRET_KEY: ${RECAPTCHA_SECRET_KEY:-}
RECAPTCHA_TESTING: ${RECAPTCHA_TESTING:-no}
ANALYTICS: ${ANALYTICS:-no}
ANALYTICS_DEBUG: ${ANALYTICS_DEBUG:-no}
ANALYTICS_WRITE_KEY: ${ANALYTICS_WRITE_KEY:-}
BILLING: ${BILLING:-no}
STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}
STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}
STRIPE_WEBHOOK_IP_WHITELIST: ${STRIPE_WEBHOOK_IP_WHITELIST:-}
SIGNUP: ${SIGNUP:-yes}
MS_AUTH: ${MS_AUTH:-no}
MS_CLIENT_ID: ${MS_CLIENT_ID:-}
MS_CLIENT_SECRET: ${MS_CLIENT_SECRET:-}
MS_AUTHORITY: ${MS_AUTHORITY:-}
GOOGLE_AUTH: ${GOOGLE_AUTH:-no}
GOOGLE_OAUTH2_CLIENT_ID: ${GOOGLE_OAUTH2_CLIENT_ID:-}
GOOGLE_OAUTH2_CLIENT_SECRET: ${GOOGLE_OAUTH2_CLIENT_SECRET:-}
GOOGLE_OAUTH2_REDIRECT_URI: ${GOOGLE_OAUTH2_REDIRECT_URI:-}
SSO_AUTH: ${SSO_AUTH:-no}
SSO_PROVIDER: ${SSO_PROVIDER:-} # Allowed values: okta, auth0
OKTA_DOMAIN: ${OKTA_DOMAIN:-}
OKTA_CLIENT_ID: ${OKTA_CLIENT_ID:-}
OKTA_CLIENT_SECRET: ${OKTA_CLIENT_SECRET:-}
OKTA_REDIRECT_URI: ${OKTA_REDIRECT_URI:-}
AUTH0_CLIENT_ID: ${AUTH0_CLIENT_ID:-}
AUTH0_CLIENT_SECRET: ${AUTH0_CLIENT_SECRET:-}
AUTH0_DOMAIN: ${AUTH0_DOMAIN:-}
AUTH0_REDIRECT_URI: ${AUTH0_REDIRECT_URI:-}
EMAIL: ${EMAIL:-no} # Disable send emails
EMAIL_PROVIDER: ${EMAIL_PROVIDER:-}
CIO_WEBHOOK_API_VERSION: ${CIO_WEBHOOK_API_VERSION:-}
CIO_WEBHOOK_API_KEY: ${CIO_WEBHOOK_API_KEY:-}
CIO_TRANSACTIONAL_API_KEY: ${CIO_TRANSACTIONAL_API_KEY:-}
CIO_TEMPLATE__RESET_PASSWORD: ${CIO_TEMPLATE__RESET_PASSWORD:-}
CIO_TEMPLATE__INVITE: ${CIO_TEMPLATE__INVITE:-}
CIO_TEMPLATE__USER_DEACTIVATED: ${CIO_TEMPLATE__USER_DEACTIVATED:-}
CIO_TEMPLATE__NEW_TASK: ${CIO_TEMPLATE__NEW_TASK:-}
CIO_TEMPLATE__TASK_RETURNED: ${CIO_TEMPLATE__TASK_RETURNED:-}
CIO_TEMPLATE__ACCOUNT_VERIFICATION: ${CIO_TEMPLATE__ACCOUNT_VERIFICATION:-}
CIO_TEMPLATE__WORKFLOWS_DIGEST: ${CIO_TEMPLATE__WORKFLOWS_DIGEST:-}
CIO_TEMPLATE__TASKS_DIGEST: ${CIO_TEMPLATE__TASKS_DIGEST:-}
CIO_TEMPLATE__USER_TRANSFER: ${CIO_TEMPLATE__USER_TRANSFER:-}
CIO_TEMPLATE__UNREAD_NOTIFICATIONS: ${CIO_TEMPLATE__UNREAD_NOTIFICATIONS:-}
CIO_TEMPLATE__GUEST_NEW_TASK: ${CIO_TEMPLATE__GUEST_NEW_TASK:-}
CIO_TEMPLATE__OVERDUE_TASK: ${CIO_TEMPLATE__OVERDUE_TASK:-}
CIO_TEMPLATE__MENTION: ${CIO_TEMPLATE__MENTION:-}
CIO_TEMPLATE__TASK_REMINDER: ${CIO_TEMPLATE__TASK_REMINDER:-}
CIO_TEMPLATE__COMPLETE_WORKFLOW: ${CIO_TEMPLATE__COMPLETE_WORKFLOW:-}
CIO_TEMPLATE__VACATION_DELEGATION: ${CIO_TEMPLATE__VACATION_DELEGATION:-}
EMAIL_HOST: ${EMAIL_HOST:-}
EMAIL_PORT: ${EMAIL_PORT:-}
EMAIL_HOST_USER: ${EMAIL_HOST_USER:-}
EMAIL_HOST_PASSWORD: ${EMAIL_HOST_PASSWORD:-}
EMAIL_USE_TLS: ${EMAIL_USE_TLS:-}
EMAIL_USE_SSL: ${EMAIL_USE_SSL:-}
EMAIL_TIMEOUT: ${EMAIL_TIMEOUT:-}
AI: ${AI:-no}
AI_PROVIDER: ${AI_PROVIDER:-}
OPENAI_API_KEY: ${OPENAI_API_KEY:-}
OPENAI_API_ORG: ${OPENAI_API_ORG:-}
AI_HTTP_PROXY: ${AI_HTTP_PROXY:-}
AI_HTTPS_PROXY: ${AI_HTTPS_PROXY:-}
PUSH: ${PUSH:-no}
PUSH_PROVIDER: ${PUSH_PROVIDER:-}
FIREBASE_PUSH_APPLICATION_CREDENTIALS: ${FIREBASE_PUSH_APPLICATION_CREDENTIALS:-/pneumatic_backend/firebase-push.json}
SENTRY_DSN: ${SENTRY_DSN:-}
POSTGRES_HOST: ${POSTGRES_HOST:-postgres}
POSTGRES_USER: ${POSTGRES_USER:-postgres_user}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres_password}
POSTGRES_DB: ${POSTGRES_DB:-postgres_db}
POSTGRES_REPLICA_HOST: ${POSTGRES_REPLICA_HOST:-postgres}
POSTGRES_REPLICA_USER: ${POSTGRES_REPLICA_USER:-postgres_user}
POSTGRES_REPLICA_PASSWORD: ${POSTGRES_REPLICA_PASSWORD:-postgres_password}
POSTGRES_REPLICA_DB: ${POSTGRES_REPLICA_DB:-postgres_db}
DJANGO_DEBUG: ${DJANGO_DEBUG:-no}
ADMIN_PATH: ${ADMIN_PATH:-admin}
DJANGO_SECRET_KEY: ${DJANGO_SECRET_KEY:-django_secret_django_secret_django_secret}
DJANGO_SETTINGS_MODULE: src.settings
AUTH_REDIS_URL: "redis://:${REDIS_PASSWORD:-redis_password}@redis:6379/1"
CACHE_REDIS_URL: "redis://:${REDIS_PASSWORD:-redis_password}@redis:6379/0"
CHANNELS_REDIS_URL: "redis://:${REDIS_PASSWORD:-redis_password}@redis:6379/2"
SESSION_REDIS_URL: "redis://:${REDIS_PASSWORD:-redis_password}@redis:6379/3"
CELERY_BROKER_URL: "amqp://${RABBITMQ_USER:-rabbitmq_user}:${RABBITMQ_PASSWORD:-rabbitmq_password}@rabbitmq:5672"
ALLOWED_HOSTS: "pneumatic-nginx"
VERIFICATION_CHECK: no
CORS_ORIGIN_ALLOW_ALL: no
CORS_ALLOW_CREDENTIALS: yes
CORS_ORIGIN_WHITELIST: "http://localhost:8000"
ENABLE_LOGGING: ${ENABLE_LOGGING:-no}
FILE_SERVICE_URL: ${FILE_SERVICE_URL:-http://localhost/files}
# Migration only: direct DB access for sync_files_to_file_service / run_file_migration.
# Can be removed after all accounts are migrated to file-service.
FILE_POSTGRES_USER: ${FILE_POSTGRES_USER:-pneumatic}
FILE_POSTGRES_PASSWORD: ${FILE_POSTGRES_PASSWORD:-pneumatic}
FILE_POSTGRES_DB: ${FILE_POSTGRES_DB:-pneumatic}
FILE_POSTGRES_HOST: ${FILE_POSTGRES_HOST:-postgres}
FILE_POSTGRES_PORT: ${FILE_POSTGRES_PORT:-5432}
LOGS_BACKEND: ${LOGS_BACKEND:-}
LOGS_REDIS_URL: "redis://:${REDIS_PASSWORD:-redis_password}@redis:6379/4"
LOGS_OTLP_ENDPOINT: ${LOGS_OTLP_ENDPOINT:-http://otel-collector:4318}
LOGS_STREAM_MAXLEN: ${LOGS_STREAM_MAXLEN:-250000}
LOGS_CONSUMER_BATCH_SIZE: ${LOGS_CONSUMER_BATCH_SIZE:-1000}
volumes:
- ./backend:/pneumatic_backend
command: celery --app src.celery_app:app beat -l warning -S django
depends_on:
- postgres
- rabbitmq
- redis
networks:
- pneumatic
restart: always
frontend:
build:
context: ./frontend
image: pneumaticworkflow/pneumatic-frontend:${TAG:-src}
container_name: pneumatic-frontend
environment:
BACKEND_PRIVATE_URL: ${BACKEND_PRIVATE_URL:-http://pneumatic-nginx/}
BACKEND_URL: ${BACKEND_URL:-http://localhost:8001}
FRONTEND_URL: ${FRONTEND_URL:-http://localhost}
WSS_URL: ${WSS_URL:-ws://localhost:8001/}
FORM_DOMAIN: ${FORM_DOMAIN:-}
MCS_RUN_ENV: ${MCS_RUN_ENV:-prod}
NODE_OPTIONS: ${NODE_OPTIONS:---max-old-space-size=3072}
LANGUAGE_CODE: ${LANGUAGE_CODE:-en} # Allowed values: en, fr, de, es, ru
CAPTCHA: ${CAPTCHA:-no}
ANALYTICS: ${ANALYTICS:-no}
ANALYTICS_WRITE_KEY: ${ANALYTICS_WRITE_KEY:-}
BILLING: ${BILLING:-no}
SIGNUP: ${SIGNUP:-yes}
MS_AUTH: ${MS_AUTH:-no}
GOOGLE_AUTH: ${GOOGLE_AUTH:-no}
SSO_AUTH: ${SSO_AUTH:-no}
SSO_PROVIDER: ${SSO_PROVIDER:-} # Allowed values: okta, auth0
AI: ${AI:-no}
PUSH: ${PUSH:-no}
FILE_SERVICE_URL: ${FILE_SERVICE_URL:-http://localhost/files}
RELEASE: ${RELEASE:-1.0.0}
SENTRY_DSN: ${SENTRY_FRONTEND_DSN:-}
SENTRY_RELEASE: ${RELEASE:-1.0.0}
FIREBASE_VAPID_KEY: ${FIREBASE_VAPID_KEY:-}
FIREBASE_API_KEY: ${FIREBASE_API_KEY:-}
FIREBASE_AUTH_DOMAIN: ${FIREBASE_AUTH_DOMAIN:-}
FIREBASE_PROJECT_ID: ${FIREBASE_PROJECT_ID:-}
FIREBASE_STORAGE_BUCKET: ${FIREBASE_STORAGE_BUCKET:-}
FIREBASE_SENDER_ID: ${FIREBASE_SENDER_ID:-}
FIREBASE_APP_ID: ${FIREBASE_APP_ID:-}
FIREBASE_MEASUREMENT_ID: ${FIREBASE_MEASUREMENT_ID:-}
RECAPTCHA_SITE_KEY: ${RECAPTCHA_SITE_KEY:-}
command: pm2-runtime start pm2.json
expose:
- 8000
networks:
- pneumatic
restart: always
nginx:
image: nginx:1.25.4
container_name: pneumatic-nginx
environment:
SSL: ${SSL:-no}
SERVER_ADDRESS: ${SERVER_ADDRESS:-localhost}
FORM_DOMAIN: ${FORM_DOMAIN:-}
NGINX_ENVSUBST_OUTPUT_DIR: /etc/nginx/
NGINX_ENVSUBST_TEMPLATE_DIR: /etc/nginx/templates
volumes:
- ./nginx/logs/:/var/log/nginx/
- ./nginx/keys/:/etc/keys/:ro
- ./nginx/www/:/var/www/:ro
- ${NGINX_CONF_TEMPLATE:-./nginx/templates/}:/etc/nginx/templates
- ./nginx/includes/:/etc/nginx/includes/:ro
- backend-socket:/tmp/gunicorn/
- backend-staticfiles:/tmp/backend-staticfiles/
ports:
- 80:80
- 443:443
- 8001:8001
networks:
- pneumatic
depends_on:
- backend
- frontend
- file-service
restart: always
file-service:
build:
context: ./storage
image: pneumaticworkflow/pneumatic-file-service:${TAG:-src}
container_name: pneumatic-file-service
environment:
DEBUG: ${FILE_DEBUG:-false}
CONFIG: ${FILE_CONFIG:-Production}
WORKERS: ${FILE_WORKERS:-1}
PORT: ${FILE_PORT:-8000}
FRONTEND_URL: ${FRONTEND_URL:-http://localhost}
FORMS_URL: ${FORMS_URL:-http://localhost/forms}
POSTGRES_USER: ${FILE_POSTGRES_USER:-pneumatic}
POSTGRES_PASSWORD: ${FILE_POSTGRES_PASSWORD:-pneumatic}
POSTGRES_DB: ${FILE_POSTGRES_DB:-pneumatic}
POSTGRES_HOST: ${FILE_POSTGRES_HOST:-postgres}
POSTGRES_PORT: ${FILE_POSTGRES_PORT:-5432}
STORAGE_TYPE: ${FILE_STORAGE_TYPE:-local}
SEAWEEDFS_S3_ENDPOINT: ${FILE_SEAWEEDFS_S3_ENDPOINT:-http://seaweedfs-filer:8333}
SEAWEEDFS_S3_ACCESS_KEY: ${FILE_SEAWEEDFS_S3_ACCESS_KEY:-any-secret-key-will-work}
SEAWEEDFS_S3_SECRET_KEY: ${FILE_SEAWEEDFS_S3_SECRET_KEY:-any-secret-key-will-work}
SEAWEEDFS_S3_REGION: ${FILE_SEAWEEDFS_S3_REGION:-us-central1}
SEAWEEDFS_S3_USE_SSL: ${FILE_SEAWEEDFS_S3_USE_SSL:-false}
GCS_S3_ENDPOINT: ${FILE_GCS_S3_ENDPOINT:-}
GCS_S3_ACCESS_KEY: ${FILE_GCS_S3_ACCESS_KEY:-}
GCS_S3_SECRET_KEY: ${FILE_GCS_S3_SECRET_KEY:-}
GCS_S3_REGION: ${FILE_GCS_S3_REGION:-}
FASTAPI_BASE_URL: ${FILE_FASTAPI_BASE_URL:-http://localhost/files}
BUCKET_PREFIX: ${FILE_BUCKET_PREFIX:-pneumatic-dev-test}
MAX_FILE_SIZE: ${FILE_MAX_FILE_SIZE:-104857600}
CHUNK_SIZE: ${FILE_CHUNK_SIZE:-1048576}
AUTH_REDIS_URL: "redis://:${REDIS_PASSWORD:-redis_password}@redis:6379/1"
KEY_PREFIX_REDIS: ${FILE_KEY_PREFIX_REDIS:-:1:}
DJANGO_SECRET_KEY: ${DJANGO_SECRET_KEY:-django_secret_django_secret_django_secret}
AUTH_TOKEN_ITERATIONS: ${FILE_AUTH_TOKEN_ITERATIONS:-1}
BACKEND_PRIVATE_URL: ${BACKEND_PRIVATE_URL:-http://pneumatic-nginx/}
SENTRY_DSN: ${SENTRY_FILE_DSN:-}
SENTRY_ENVIRONMENT: ${ENVIRONMENT:-Production}
LOGS_BACKEND: ${LOGS_BACKEND:-}
LOGS_REDIS_URL: "redis://:${REDIS_PASSWORD:-redis_password}@redis:6379/4"
LOGS_STREAM_MAXLEN: ${LOGS_STREAM_MAXLEN:-250000}
command: >
sh -c "poetry run alembic -c src/shared_kernel/database/alembic.ini upgrade head &&
poetry run uvicorn src.main:app --host 0.0.0.0 --port ${FILE_PORT:-8000} --workers ${FILE_WORKERS:-1}"
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_started
expose:
- 8000
networks:
- pneumatic
restart: always
seaweedfs-master:
image: chrislusf/seaweedfs:3.95
container_name: pneumatic-seaweedfs-master
command: master -ip=seaweedfs-master -port=9333
expose:
- 9333
volumes:
- ./seaweedfs/master/data:/data:rw
networks:
- pneumatic
seaweedfs-volume:
image: chrislusf/seaweedfs:3.95
container_name: pneumatic-seaweedfs-volume
command:
- volume
- -mserver=seaweedfs-master:9333
- -port=8080
- -ip=seaweedfs-volume
- -publicUrl=localhost:8080
expose:
- 8080
depends_on:
- seaweedfs-master
volumes:
- ./seaweedfs/volume/data:/data:rw
networks:
- pneumatic
seaweedfs-filer:
image: chrislusf/seaweedfs:3.95
container_name: pneumatic-seaweedfs-filer
command: filer -master="seaweedfs-master:9333" -s3 -s3.port=8333 -s3.config=/etc/seaweedfs/s3.json
expose:
- 8333
depends_on:
- seaweedfs-master
- seaweedfs-volume
volumes:
- ./storage/seaweedfs/filer.toml:/etc/seaweedfs/filer.toml
- ./storage/seaweedfs/s3.json:/etc/seaweedfs/s3.json:ro
- ./seaweedfs/filer/data:/data:rw
networks:
- pneumatic
# The collector of the audit journal. Off by default: it starts only
# with the profile named after LOGS_BACKEND, which start.sh passes on
# its own (by hand: COMPOSE_PROFILES, see default.env). The store it
# writes into lives on a machine of its own - logging/grafana for Loki
# and Grafana, logging/elasticsearch for Elasticsearch and Kibana.
otel-collector:
image: otel/opentelemetry-collector-contrib:0.160.0
container_name: pneumatic-otel-collector
profiles: ["logs-otlp", "logs-elasticsearch"]
command:
- --config=/etc/otel/base.yaml
- --config=/etc/otel/backend-${LOGS_BACKEND:-}.yaml
environment:
LOGS_OTLP_EXPORT_ENDPOINT: ${LOGS_OTLP_EXPORT_ENDPOINT:-}
LOGS_OTLP_EXPORT_AUTH: ${LOGS_OTLP_EXPORT_AUTH:-}
LOGS_ELASTICSEARCH_URL: ${LOGS_ELASTICSEARCH_URL:-}
LOGS_ELASTICSEARCH_API_KEY: ${LOGS_ELASTICSEARCH_API_KEY:-}
LOGS_ELASTICSEARCH_USER: ${LOGS_ELASTICSEARCH_USER:-}
LOGS_ELASTICSEARCH_PASSWORD: ${LOGS_ELASTICSEARCH_PASSWORD:-}
LOGS_ELASTICSEARCH_CA_FILE: ${LOGS_ELASTICSEARCH_CA_FILE:-/etc/otel/es-ca.crt}
LOGS_ELASTICSEARCH_QUEUE_DIR: ${LOGS_ELASTICSEARCH_QUEUE_DIR:-/var/lib/otelcol/queue}
LOGS_ELASTICSEARCH_INDEX: ${LOGS_ELASTICSEARCH_INDEX:-logs-pneumatic.events.otel-default}
volumes:
- ./otel-collector:/etc/otel:ro
# The disk queue of LOGS_BACKEND=elasticsearch, see default.env
- otel-queue:/var/lib/otelcol
expose:
- 4318 # OTLP/HTTP receiver
- 13133 # health_check extension
networks:
- pneumatic
restart: always
networks:
pneumatic:
volumes:
backend-staticfiles:
backend-socket:
otel-queue: