Docker Networking#
Dify's Docker Compose stack uses Docker's embedded DNS resolver for inter-service communication: containers address each other by service name (e.g., api, plugin_daemon, redis), and Docker resolves those names to container IPs on a shared bridge network. All authoritative network definitions live in docker/docker-compose-template.yaml β the generated docker-compose.yaml must not be edited directly.
Network Topology#
The stack defines six named bridge networks :
| Network | internal | Purpose |
|---|---|---|
default | no | General inter-service traffic; has external access |
ssrf_proxy_network | yes | Restricted; sandbox egress must traverse the Squid proxy |
agent_sandbox_network | yes | Shellctl control channel between agent_backend and local_sandbox |
local_sandbox_proxy_network | yes | Forces all local_sandbox egress through agent_ssrf_proxy |
milvus | no | Isolated Milvus cluster |
opensearch-net | yes | Isolated OpenSearch cluster |
Service β network membership :
| Service(s) | Networks |
|---|---|
api, api_websocket, worker, worker_beat | ssrf_proxy_network + default |
plugin_daemon | ssrf_proxy_network + default |
ssrf_proxy | ssrf_proxy_network + default |
sandbox | ssrf_proxy_network only β no external egress |
agent_backend | default + agent_sandbox_network |
agent_ssrf_proxy | default + local_sandbox_proxy_network |
local_sandbox | agent_sandbox_network + local_sandbox_proxy_network only |
web, nginx, redis, db_postgres, db_mysql | default only |
ββ default (external access) ββββββββββββββββββββββββββββββββββββββββββββ
β nginx β api / api_websocket / worker / plugin_daemon / web β
β redis db_postgres agent_backend agent_ssrf_proxy β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β ssrf_proxy_network (internal: true)
βββ api, worker, worker_beat, api_websocket
βββ plugin_daemon
βββ ssrf_proxy (Squid :3128)
βββ sandbox β only here
agent_sandbox_network (internal: true)
βββ agent_backend (also on default)
βββ local_sandbox β shellctl :5004
local_sandbox_proxy_network (internal: true)
βββ agent_ssrf_proxy (also on default)
βββ local_sandbox β proxy egress :3128
Key Inter-Service DNS Names and Ports#
All inter-service URLs use Docker DNS service names. Never use localhost for cross-container URLs β it resolves to the container itself, not a peer. The most common misconfiguration is PLUGIN_DAEMON_URL=http://localhost:5002 in a Docker deployment.
| Connection | DNS address | Port | Config variable |
|---|---|---|---|
| API β Plugin Daemon | http://plugin_daemon | 5002 | PLUGIN_DAEMON_URL |
| Plugin Daemon β API | http://api | 5001 | DIFY_INNER_API_URL / PLUGIN_DIFY_INNER_API_URL |
| API β Agent Backend | http://agent_backend | 5050 | AGENT_BACKEND_BASE_URL |
| Agent Backend β Plugin Daemon | http://plugin_daemon | 5002 | DIFY_AGENT_PLUGIN_DAEMON_URL |
| Agent Backend β API | http://api | 5001 | DIFY_AGENT_INNER_API_URL |
| Agent Backend β Local Sandbox | http://local_sandbox | 5004 | DIFY_AGENT_SHELLCTL_ENTRYPOINT |
| Web (SSR) β API | http://api | 5001 | SERVER_CONSOLE_API_URL |
| API/Worker β Sandbox | http://sandbox | 8194 | CODE_EXECUTION_ENDPOINT |
| API/Worker β Redis | redis | 6379 | REDIS_HOST |
| API/Worker β DB | db_postgres / db_mysql | 5432 / 3306 | DB_HOST |
Key variables with defaults are set in docker/envs/core-services/shared.env.example β e.g., SSRF_PROXY_HTTP_URL=http://ssrf_proxy:3128 , CODE_EXECUTION_ENDPOINT=http://sandbox:8194 , CELERY_BROKER_URL=redis://:difyai123456@redis:6379/1 .
Plugin Daemon Connectivity#
The plugin daemon requires two bidirectional HTTP paths :
- API β Daemon (
http://plugin_daemon:5002): all plugin invocations. Authenticated viaPLUGIN_DAEMON_KEY(X-Api-Keyheader). - Daemon β API (
http://api:5001): inner-API callbacks from the daemon. Authenticated viaPLUGIN_DIFY_INNER_API_KEY.
Port 5002 is internal-only β not published to the Docker host. Port 5003 (debug/remote install) is the only plugin daemon port published externally by default . See also api/configs/feature/__init__.py for application-layer defaults.
In source/dev mode (daemon in Docker, API on host), set PLUGIN_DIFY_INNER_API_URL=http://host.docker.internal:5001 on macOS/Windows, or the host bridge IP on Linux.
web Service SSR Routing#
The Next.js web container's server-side rendering fetches data from the API over the internal network. SERVER_CONSOLE_API_URL defaults to http://api:5001. If you override CONSOLE_API_URL with a public hostname for browser access, you must also explicitly set SERVER_CONSOLE_API_URL to the internal DNS name. Leaving it as a public hostname that doesn't resolve inside the container causes silent SSR failures.
Startup Ordering and Health Checks#
The web service has no depends_on entries β it starts immediately and may encounter ECONNREFUSED if the API container is not yet ready . The api service waits for init_permissions to complete, databases to become healthy, and redis / agent_backend to start . The api service exposes a healthcheck at http://localhost:5001/health (interval: 30s, start_period: 30s) . Transient ECONNREFUSED errors from the web container after a stack restart are expected until the api healthcheck passes; Docker's built-in restart policy (restart: always) recovers these automatically.
Key Source Files#
| File | Purpose |
|---|---|
docker/docker-compose-template.yaml | Authoritative network/service/port definitions |
docker/envs/core-services/shared.env.example | Shared env defaults for API/worker services |
api/configs/feature/__init__.py | Application-layer defaults (PLUGIN_DAEMON_URL, etc.) |
| Sandbox Network Isolation KB | ssrf_proxy_network deny-by-default policy |