Documentsdify
Docker Deployment and Upgrades
Docker Deployment and Upgrades
Type
Topic
Status
Published
Created
Jul 16, 2026
Updated
Jul 16, 2026
Created by
Dosu Bot
Updated by
Dosu Bot

Docker Deployment and Upgrades#

Overview#

Dify ships a Docker Compose stack in the docker/ directory. The docker-compose.yaml is auto-generated from .env.example and docker-compose-template.yaml and must not be edited directly . All customization goes into docker/.env, which overrides the defaults baked into the compose file .

Core Services#

The stack defines these primary services :

ServiceImagePurpose
apilanggenius/dify-api:<version>Flask API server (Gunicorn)
api_websocketlanggenius/dify-api:<version>WebSocket server for collaboration
worker / worker_beatlanggenius/dify-api:<version>Celery task queue and scheduler
weblanggenius/dify-web:<version>Next.js frontend
plugin_daemonlanggenius/dify-plugin-daemon:<version>Plugin execution engine (Go, port 5002)
agent_backendlanggenius/dify-agent-backend:<version>Agent execution backend
db_postgres / db_mysqlpostgres / mysqlMain application database
redisredisCache, Celery broker, migration lock
sandbox / local_sandboxdify-sandboxCode execution isolation
nginxnginxReverse proxy

Vector store backends (Weaviate, Qdrant, Milvus, OpenSearch, PGVector, etc.) are optional and activated via COMPOSE_PROFILES .


Environment Variable Management#

Configuration Precedence#

Variables are resolved in this order (later source wins) :

  1. docker/envs/**/*.env files (optional per-service overrides; copy the matching *.env.example without the .example suffix to enable)
  2. docker/.env — the primary operator config file (always loaded last, takes precedence)
  3. Hardcoded environment: block defaults in docker-compose.yaml (fallback when a variable is absent from all env files)

Initial setup: cp docker/.env.example docker/.env, then edit docker/.env. No other files need to be touched for a standard deployment .

Key Variables by Domain#

Security :

  • SECRET_KEY — leave blank to auto-generate; must be set explicitly in production multi-instance deployments
  • PLUGIN_DAEMON_KEY — shared secret between the API and plugin daemon; defaults are insecure and must be rotated in production
  • PLUGIN_DIFY_INNER_API_KEY — inner API key for plugin-to-API callbacks

Workers :

  • SERVER_WORKER_AMOUNT=1 — Gunicorn workers for the API; each blocks for the full duration of plugin daemon calls, so increase this for concurrent agent workloads
  • CELERY_WORKER_AMOUNT=4 — async task workers

Database :

  • DB_TYPE, DB_HOST, DB_PORT, DB_DATABASE, DB_USERNAME, DB_PASSWORD
  • DB_PLUGIN_DATABASE=dify_plugin — separate database used exclusively by the plugin daemon ; must exist before the daemon starts

Plugin daemon :

  • PLUGIN_DAEMON_URL=http://plugin_daemon:5002 — use the Docker service name, not localhost
  • PLUGIN_MAX_EXECUTION_TIMEOUT=600 — per-plugin execution timeout (seconds)
  • PLUGIN_STORAGE_TYPE=local — plugin file storage backend (local, S3, Azure, Aliyun OSS, Tencent COS, Volcengine TOS)
  • PLUGIN_INSTALLED_PATH=plugin — relative subdir under PLUGIN_STORAGE_LOCAL_ROOT for installed plugins
  • FORCE_VERIFYING_SIGNATURE=true — enforce plugin signature verification

The entire plugin daemon storage tree binds to ./volumes/plugin_daemon → /app/storage inside the container .

Nginx :

  • NGINX_HTTPS_ENABLED, NGINX_PORT=80, NGINX_SSL_PORT=443, NGINX_CLIENT_MAX_BODY_SIZE=100M

Upgrade Procedure#

The canonical sequence for any major version bump:

1 — Pull and restart#

cd docker
git pull
docker compose pull
docker compose up -d

2 — Run database schema migration#

flask upgrade-db applies Alembic migrations to the main dify database using a Redis-backed distributed lock (60 s TTL, auto-renewing heartbeat) to prevent concurrent migration races :

docker compose exec api flask upgrade-db

With MIGRATION_ENABLED=true (the default), the API container also runs this automatically on startup . In multi-instance setups, only one pod acquires the lock; others skip migration silently.

3 — Run plugin backfill#

After schema migration, populate missing per-category auto-upgrade strategy rows for all tenants :

docker compose exec api flask backfill-plugin-auto-upgrade

Supports --dry-run, --tenant-id, --limit, and --batch-size flags. See api/commands/plugin.py for the implementation.

4 — Verify plugin daemon version#

The plugin daemon is versioned in lockstep with the Dify API. Protocol changes between releases cause complete communication failure if versions diverge :

Dify APIPlugin Daemon image tag
1.13.x0.5.x
1.14.x0.6.x
1.15.00.6.3-local

The image tag in the current compose file is langgenius/dify-plugin-daemon:0.6.3-local . Confirm the running daemon image matches the Dify API version before proceeding.

5 — Clean stale plugin directories#

On startup the daemon scans PLUGIN_INSTALLED_PATH and logs record not found for any directory whose version identifier lacks a matching database row. Remove stale subdirectories from ./volumes/plugin_daemon/plugin/ once plugins are confirmed working in the UI .


Known Upgrade Failure Patterns#

See Plugin Database Integrity for full diagnostic queries and SQL recovery scripts.

FailureSymptomFix
Version reconciliation (1.15.0+)record not found / Plugin table missing in daemon logsRun flask backfill-plugin-auto-upgrade; remove stale dirs from PLUGIN_INSTALLED_PATH
model_type enum mismatch (1.14.x)Models visible but uneditable; HTTP 400 "Credential with id … not found"Manual SQL UPDATE on provider_models, provider_model_credentials, and 3 related tables
Duplicate plugin_unique_identifier (1.13.x→1.14.x)Daemon restart loop, SQLSTATE 23505Deduplicate dify_plugin.plugins table, then restart daemon
Daemon schema init sequence (fresh install)dify_plugin tables not createdInstall daemon 0.5.3-local first for schema baseline, then upgrade

Key Source Files#

FilePurpose
docker/docker-compose.yamlAuto-generated compose stack — do not edit
docker/.env.exampleCanonical list of all configurable variables
api/commands/system.pyflask upgrade-db implementation
api/commands/plugin.pyflask backfill-plugin-auto-upgrade and other plugin CLI commands
api/libs/db_migration_lock.pyRedis distributed migration lock