Docker Deployment and Upgrades#
Dify's primary self-hosted deployment is a Docker Compose stack under the docker/ directory. The stack is managed via docker/docker-compose.yaml, which is auto-generated from docker-compose-template.yaml β never edit it directly . All operator customization goes into docker/.env, copied from docker/.env.example.
As of v1.17.x, the stack includes seven core application services (api, api_websocket, worker, worker_beat, web, plugin_daemon, agent_backend) plus supporting infrastructure (db_postgres, redis, nginx, ssrf_proxy, agent_ssrf_proxy, sandbox, local_sandbox, init_permissions). Optional vector store backends and the WebSocket collaboration service are activated via COMPOSE_PROFILES in .env .
Prerequisites: CPU β₯ 2 cores, RAM β₯ 4 GiB, Docker β₯ 19.03, Docker Compose β₯ 2.24.0.
Initial Deployment#
git clone --branch <TAG> https://github.com/langgenius/dify.git
cd dify/docker
cp .env.example .env
# Edit .env β at minimum set SECRET_KEY
docker compose up -d
Navigate to http://localhost/install to complete setup. See the official quick-start guide for full details.
Environment Variable Management#
Variables resolve with this precedence (later wins) :
docker/.envβ primary operator configdocker/envs/**/*.envβ optional per-service overrides (seedocker/envs/)- Hardcoded
environment:defaults insidedocker-compose.yaml
docker/.env.example is the canonical variable reference β diff it against your .env after every upgrade to catch newly required variables.
Key variables to verify on every deployment or upgrade:
| Variable | Notes |
|---|---|
SECRET_KEY | Must be set explicitly and identically across api + api_websocket. Leaving it blank causes each service to generate a different key, breaking JWT auth |
COMPOSE_PROFILES | Controls vector stores, database type, and collaboration service. Default: weaviate,postgresql,collaboration |
PLUGIN_DAEMON_KEY | Shared secret for API β plugin daemon; rotate from default in production |
PLUGIN_DAEMON_URL | Must use Docker service name: http://plugin_daemon:5002 β not localhost |
DB_TYPE | Required since 1.15.0; set to postgresql when upgrading from older versions |
Standard Upgrade Procedure#
The canonical sequence for any version bump :
cd docker
git pull
docker compose pull
docker compose up -d
Then run these post-start commands in order:
-
Apply schema migrations (auto-runs on startup when
MIGRATION_ENABLED=true; run explicitly to confirm):docker compose exec api flask upgrade-dbImplementation:
api/commands/system.py -
Backfill plugin auto-upgrade strategies β mandatory after 1.15.0+; must run after
upgrade-dbbecause it depends on thecategorycolumn that migration adds :docker compose exec api flask backfill-plugin-auto-upgradeImplementation:
api/commands/plugin.py -
Verify plugin daemon image tag matches the Dify release (see Plugin Daemon Synchronization below).
-
Clean stale plugin directories β remove subdirectories in
./volumes/plugin_daemon/plugin/that logrecord not foundin the daemon, after confirming plugins work in the UI .
Version-Specific Breaking Changes#
Standard docker compose up + flask upgrade-db is not sufficient for the following upgrades. The Release Breaking Changes KB has the full catalog .
1.9.0 β Datasource Credential Migration#
After upgrading, run :
docker compose exec api flask transform-datasource-credentials
Users on v2.0.0-beta.1/beta.2 face a destructive migration that deletes all existing Knowledge Pipelines and Dataset Credentials.
1.13.0 β New Celery Queue#
A new workflow_based_app_execution Celery queue is required for Human-in-the-Loop workflows and workflow-based streaming . If you use a custom CELERY_QUEUES, explicitly add workflow_based_app_execution (and api_token if ENABLE_API_TOKEN_LAST_USED_UPDATE_TASK=true). New PubSub env vars (PUBSUB_REDIS_URL, PUBSUB_REDIS_CHANNEL_TYPE) were also introduced in this release.
1.14.x β model_type Enum Rename#
Three enum values were renamed without an automatic data migration :
| Old value | New value |
|---|---|
text-generation | llm |
embeddings | text-embedding |
reranking | rerank |
Symptom: UI shows "Credentials unavailable"; HTTP 400 "Credential with id β¦ not found" in the browser console. Inference still works; management operations (view, edit, delete) are broken.
Fix: Run the CLI migration :
docker compose exec api flask data-migrate legacy-model-types # dry-run
docker compose exec api flask data-migrate legacy-model-types --apply
Implementation: api/commands/data_migrate.py and api/services/legacy_model_type_migration.py (five affected tables: provider_models, provider_model_credentials, tenant_default_models, provider_model_settings, load_balancing_model_configs).
Note: From Alembic migration 2026_08_27_1200-5578e028b2f2 (PR #41326) onward, flask upgrade-db applies this automatically .
1.14.x β Duplicate plugin_unique_identifier#
When upgrading from 1.13.x, the daemon may restart in a loop (SQLSTATE 23505) because a unique index creation fails on dify_plugin.plugins. Diagnose with:
SELECT plugin_unique_identifier, COUNT(*) AS cnt
FROM plugins
GROUP BY plugin_unique_identifier
HAVING COUNT(*) > 1;
Remove extra rows (keep the most recent), then restart the daemon. See Issue #38276 .
1.15.0 β Multiple Breaking Changes#
-
DB_TYPEnow required β addDB_TYPE=postgresqlto.env. -
SSRF proxy deny-by-default β blocks all RFC-1918 private IPs and all destinations except
.marketplace.dify.ai. Workflow HTTP-request nodes calling internal endpoints will return403 Forbidden. Fix by adding to.envand restarting:SSRF_PROXY_ALLOW_PRIVATE_DOMAINS=internal.mycompany.com,ollama SSRF_PROXY_ALLOW_PRIVATE_IPS=10.10.5.42,192.168.1.0/24docker compose restart ssrf_proxyConfig template:
docker/ssrf_proxy/squid.conf.template. The entrypointdocker/ssrf_proxy/docker-entrypoint.shinjects these as Squid ACL fragments at startup. -
Legacy model type migration β
flask upgrade-dbalone is not sufficient; also runflask data-migrate legacy-model-types --applyfor pre-1.15.0 databases . -
Plugin backfill β
flask backfill-plugin-auto-upgradeis now mandatory after every upgrade.
1.17.0 β EDITION β DEPLOYMENT_EDITION Rename#
Rename this variable in .env before starting services . Removed variables include AGENT_BACKEND_RUN_TIMEOUT_SECONDS, ENTERPRISE_ENABLED, and DIFY_AGENT_SHELLCTL_*. Timeout defaults for APP_MAX_EXECUTION_TIME and WORKFLOW_MAX_EXECUTION_TIME changed from 1200 s to 3600 s.
Plugin Daemon Synchronization#
The plugin daemon is a separate Go-based service that must stay in version lockstep with the Dify API. Protocol mismatches cause complete communication failure β the daemon logs "failed to find the version of the plugin sdk" and the API returns connection errors .
| Dify API | Plugin Daemon image tag |
|---|---|
| 1.13.x | 0.5.x |
| 1.14.x | 0.6.x |
| 1.15.0β1.17.x | 0.6.10-local (or matching release tag) |
The daemon communicates with the API at http://plugin_daemon:5002 β always use the Docker service name, not localhost . It maintains a separate PostgreSQL database (dify_plugin, configurable via DB_PLUGIN_DATABASE) that must exist before the daemon starts .
Plugin storage bind-mounts ./volumes/plugin_daemon β /app/storage. Back up this directory to preserve installed plugins across host restarts.
For plugin DB integrity issues (version reconciliation, duplicate identifiers, daemon schema init failures), see the Plugin Database Integrity KB and Plugin Daemon Architecture KB .
Key Files and References#
| Resource | Purpose |
|---|---|
docker/docker-compose.yaml | Auto-generated stack; do not edit directly |
docker/docker-compose-template.yaml | Source template for the generated compose file |
docker/.env.example | Canonical variable reference; copy to .env |
docker/envs/ | Optional per-service env overrides |
docker/ssrf_proxy/squid.conf.template | Full Squid ACL rules (deny-by-default list) |
api/commands/system.py | flask upgrade-db |
api/commands/plugin.py | flask backfill-plugin-auto-upgrade |
api/commands/data_migrate.py | flask data-migrate legacy-model-types |
api/services/legacy_model_type_migration.py | Online migration logic for model_type rename |
| Official quick-start guide | Step-by-step deployment and upgrade docs |
| Release Breaking Changes KB | Full per-version breaking change catalog |
| Plugin Database Integrity KB | Diagnostic queries and SQL recovery scripts |
| Plugin Daemon Architecture KB | Version pairings, communication protocol, troubleshooting |