Server Deployment Configuration#
Dify's API server (api/) runs in one of two modes, selected at container startup by the DEBUG environment variable. The switch lives in api/docker/entrypoint.sh.
DEBUG vs. Production Mode#
DEBUG value | Server used | Entry point |
|---|---|---|
true | gevent pywsgi (single process) | python -m app |
false (default) | Gunicorn (multi-worker) | gunicorn β¦ app:socketio_app |
Debug mode (DEBUG=true) runs python -m app, which boots a gevent.pywsgi.WSGIServer directly. Because the process runs as __main__, it also applies gevent monkey-patching and patches gRPC/psycopg before any other import . This path is not suitable for production.
Production mode (DEBUG=false) launches Gunicorn with a GeventWebSocketWorker worker class, which supports WebSocket connections needed by Dify's streaming responses.
Gunicorn Startup Command#
The full command used in production :
gunicorn \
--no-control-socket \
--bind "${DIFY_BIND_ADDRESS:-0.0.0.0}:${DIFY_PORT:-5001}" \
--workers ${SERVER_WORKER_AMOUNT:-1} \
--worker-class ${SERVER_WORKER_CLASS:-geventwebsocket.gunicorn.workers.GeventWebSocketWorker} \
--worker-connections ${SERVER_WORKER_CONNECTIONS:-10} \
--timeout ${GUNICORN_TIMEOUT:-360} \
app:socketio_app
Tunable Environment Variables#
Defaults from docker/.env.example:
| Variable | Default | Notes |
|---|---|---|
DEBUG | false | Switches between pywsgi and Gunicorn |
DIFY_BIND_ADDRESS | 0.0.0.0 | Listen address |
DIFY_PORT | 5001 | Listen port |
SERVER_WORKER_AMOUNT | 1 | Number of Gunicorn worker processes |
SERVER_WORKER_CLASS | gevent | Worker class (passed to --worker-class) |
SERVER_WORKER_CONNECTIONS | 10 | Max simultaneous connections per worker |
GUNICORN_TIMEOUT | 360 | Request timeout in seconds |
Production sizing note: The default of 1 worker + 10 connections is intentionally conservative. Each Gunicorn worker holds its connection to the plugin daemon for the full duration of a call (up to
PLUGIN_DAEMON_TIMEOUT, default 600 s). Under concurrent agent workloads, a single worker can starve all other API requests. See Worker Exhaustion Under Concurrent Load for a detailed analysis. The minimum recommended starting point isSERVER_WORKER_AMOUNT=4or CPU core count .
gevent Patching in Gunicorn#
Gunicorn's gevent worker applies monkey-patching automatically. api/gunicorn.conf.py adds a post_patch hook that subscribes to GeventDidPatchBuiltinModulesEvent to initialize gRPC gevent support and patch psycopg2 after the stdlib is patched. This ordering is required β calling grpc_gevent.init_gevent() before patching causes deadlocks .
The app.py module-level code does not apply monkey-patching when loaded by Gunicorn; patching is handled entirely by the worker class and gunicorn.conf.py .
Key Files#
| File | Purpose |
|---|---|
api/docker/entrypoint.sh | Container entrypoint; DEBUG switch + Gunicorn startup |
api/app.py | pywsgi server (debug mode) + Gunicorn WSGI app object |
api/gunicorn.conf.py | Gunicorn post-patch hooks for gRPC and psycopg2 |
docker/.env.example | Default values for all server worker variables |