Files
templates/blueprints/dify/docker-compose.yml
Mauricio Siu 1c2dea39c3 feat: add Dify template
Dify 1.15.0 (open-source LLM app development platform): api + worker +
worker_beat + web + pgvector PostgreSQL (also used as the vector store) +
redis + sandbox + ssrf_proxy (squid) + plugin_daemon, fronted by an
internal nginx gateway that mirrors the upstream path routing.

Closes #88

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 12:29:15 -06:00

257 lines
7.4 KiB
YAML

# Dify - open-source LLM app development platform
# Adapted from the official docker/docker-compose.yaml (tag 1.15.0).
# Minimal functional stack: api + worker + worker_beat + web + postgres
# (pgvector, reused as the vector store) + redis + sandbox + ssrf_proxy
# + plugin_daemon, fronted by a lightweight internal nginx gateway that
# mirrors the upstream path routing (TLS terminates at Traefik).
x-shared-api-env: &shared-api-env
LOG_LEVEL: INFO
DEPLOY_ENV: PRODUCTION
SECRET_KEY: ${SECRET_KEY}
MIGRATION_ENABLED: "true"
# Public URLs - a single domain, path-routed like the upstream nginx
CONSOLE_API_URL: https://${DIFY_DOMAIN}
CONSOLE_WEB_URL: https://${DIFY_DOMAIN}
SERVICE_API_URL: https://${DIFY_DOMAIN}
APP_API_URL: https://${DIFY_DOMAIN}
APP_WEB_URL: https://${DIFY_DOMAIN}
FILES_URL: https://${DIFY_DOMAIN}
INTERNAL_FILES_URL: http://api:5001
TRIGGER_URL: https://${DIFY_DOMAIN}
ENDPOINT_URL_TEMPLATE: https://${DIFY_DOMAIN}/e/{hook_id}
# The dedicated api_websocket collaboration service is not deployed
ENABLE_COLLABORATION_MODE: "false"
WEB_API_CORS_ALLOW_ORIGINS: "*"
CONSOLE_CORS_ALLOW_ORIGINS: "*"
# PostgreSQL
DB_USERNAME: postgres
DB_PASSWORD: ${POSTGRES_PASSWORD}
DB_HOST: db
DB_PORT: "5432"
DB_DATABASE: dify
# Redis / Celery
REDIS_HOST: redis
REDIS_PORT: "6379"
REDIS_PASSWORD: ${REDIS_PASSWORD}
REDIS_DB: "0"
CELERY_BROKER_URL: redis://:${REDIS_PASSWORD}@redis:6379/1
# File storage on a local volume
STORAGE_TYPE: opendal
OPENDAL_SCHEME: fs
OPENDAL_FS_ROOT: storage
# Vector store: pgvector, reusing the same PostgreSQL instance
VECTOR_STORE: pgvector
PGVECTOR_HOST: db
PGVECTOR_PORT: "5432"
PGVECTOR_USER: postgres
PGVECTOR_PASSWORD: ${POSTGRES_PASSWORD}
PGVECTOR_DATABASE: dify
PGVECTOR_MIN_CONNECTION: "1"
PGVECTOR_MAX_CONNECTION: "5"
# Code execution sandbox
CODE_EXECUTION_ENDPOINT: http://sandbox:8194
CODE_EXECUTION_API_KEY: ${SANDBOX_API_KEY}
# SSRF proxy (squid) for user-triggered outbound requests
SSRF_PROXY_HTTP_URL: http://ssrf_proxy:3128
SSRF_PROXY_HTTPS_URL: http://ssrf_proxy:3128
# Plugin daemon (model providers / tools are plugins since Dify 1.0)
PLUGIN_DAEMON_URL: http://plugin_daemon:5002
PLUGIN_DAEMON_KEY: ${PLUGIN_DAEMON_KEY}
INNER_API_KEY_FOR_PLUGIN: ${PLUGIN_INNER_API_KEY}
PLUGIN_MAX_PACKAGE_SIZE: "52428800"
PLUGIN_REMOTE_INSTALL_HOST: localhost
PLUGIN_REMOTE_INSTALL_PORT: "5003"
MARKETPLACE_ENABLED: "true"
MARKETPLACE_API_URL: https://marketplace.dify.ai
services:
nginx:
image: nginx:1.27-alpine
restart: always
volumes:
- ../files/dify-nginx.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
api:
condition: service_healthy
web:
condition: service_started
plugin_daemon:
condition: service_started
# The dify-api image runs as the non-root user 1001, so the shared
# storage volume has to be handed over to it once (same trick as the
# upstream init_permissions container).
init_permissions:
image: busybox:1.36
command:
- sh
- -c
- |
FLAG_FILE="/app/api/storage/.init_permissions"
if [ -f "$$FLAG_FILE" ]; then
echo "Permissions already initialized."
exit 0
fi
echo "Initializing permissions for /app/api/storage"
chown -R 1001:1001 /app/api/storage && touch "$$FLAG_FILE"
volumes:
- dify-app-storage:/app/api/storage
restart: "no"
api:
image: langgenius/dify-api:1.15.0
restart: always
environment:
<<: *shared-api-env
MODE: api
depends_on:
init_permissions:
condition: service_completed_successfully
db:
condition: service_healthy
redis:
condition: service_healthy
volumes:
- dify-app-storage:/app/api/storage
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5001/health"]
interval: 15s
timeout: 5s
retries: 20
start_period: 120s
worker:
image: langgenius/dify-api:1.15.0
restart: always
environment:
<<: *shared-api-env
MODE: worker
depends_on:
init_permissions:
condition: service_completed_successfully
db:
condition: service_healthy
redis:
condition: service_healthy
volumes:
- dify-app-storage:/app/api/storage
worker_beat:
image: langgenius/dify-api:1.15.0
restart: always
environment:
<<: *shared-api-env
MODE: beat
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
web:
image: langgenius/dify-web:1.15.0
restart: always
environment:
CONSOLE_API_URL: https://${DIFY_DOMAIN}
APP_API_URL: https://${DIFY_DOMAIN}
SERVER_CONSOLE_API_URL: http://api:5001
ENABLE_COLLABORATION_MODE: "false"
MARKETPLACE_API_URL: https://marketplace.dify.ai
MARKETPLACE_URL: https://marketplace.dify.ai
NEXT_TELEMETRY_DISABLED: "1"
db:
image: pgvector/pgvector:pg16
restart: always
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: dify
PGDATA: /var/lib/postgresql/data/pgdata
volumes:
- dify-db-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -d dify"]
interval: 5s
timeout: 3s
retries: 30
redis:
image: redis:6-alpine
restart: always
environment:
REDISCLI_AUTH: ${REDIS_PASSWORD}
command: redis-server --requirepass ${REDIS_PASSWORD}
volumes:
- dify-redis-data:/data
healthcheck:
test: ["CMD-SHELL", "redis-cli ping | grep -q PONG"]
interval: 5s
timeout: 3s
retries: 30
sandbox:
image: langgenius/dify-sandbox:0.2.15
restart: always
environment:
API_KEY: ${SANDBOX_API_KEY}
GIN_MODE: release
WORKER_TIMEOUT: "15"
ENABLE_NETWORK: "true"
HTTP_PROXY: http://ssrf_proxy:3128
HTTPS_PROXY: http://ssrf_proxy:3128
SANDBOX_PORT: "8194"
volumes:
- dify-sandbox-deps:/dependencies
ssrf_proxy:
image: ubuntu/squid:latest
restart: always
volumes:
- ../files/dify-squid.conf:/etc/squid/squid.conf:ro
plugin_daemon:
image: langgenius/dify-plugin-daemon:0.6.3-local
restart: always
environment:
DB_HOST: db
DB_PORT: "5432"
DB_USERNAME: postgres
DB_PASSWORD: ${POSTGRES_PASSWORD}
DB_DATABASE: dify_plugin
DB_SSL_MODE: disable
REDIS_HOST: redis
REDIS_PORT: "6379"
REDIS_PASSWORD: ${REDIS_PASSWORD}
SERVER_PORT: "5002"
SERVER_KEY: ${PLUGIN_DAEMON_KEY}
MAX_PLUGIN_PACKAGE_SIZE: "52428800"
DIFY_INNER_API_URL: http://api:5001
DIFY_INNER_API_KEY: ${PLUGIN_INNER_API_KEY}
PLUGIN_REMOTE_INSTALLING_HOST: 0.0.0.0
PLUGIN_REMOTE_INSTALLING_PORT: "5003"
PLUGIN_WORKING_PATH: /app/storage/cwd
FORCE_VERIFYING_SIGNATURE: "true"
PYTHON_ENV_INIT_TIMEOUT: "120"
PLUGIN_MAX_EXECUTION_TIMEOUT: "600"
PLUGIN_STORAGE_TYPE: local
PLUGIN_STORAGE_LOCAL_ROOT: /app/storage
PLUGIN_INSTALLED_PATH: plugin
PLUGIN_PACKAGE_CACHE_PATH: plugin_packages
PLUGIN_MEDIA_CACHE_PATH: assets
volumes:
- dify-plugin-storage:/app/storage
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
volumes:
dify-app-storage:
dify-db-data:
dify-redis-data:
dify-sandbox-deps:
dify-plugin-storage: