mirror of
https://github.com/langgenius/dify.git
synced 2026-11-13 06:41:07 +08:00
625 lines
32 KiB
Markdown
625 lines
32 KiB
Markdown
# Docker deployment
|
|
|
|
Run Dify with Docker Compose. For the default deployment, copy `.env.example` to
|
|
`.env`, fill in the required token, and start the services. Defaults for the API,
|
|
workers, and supporting services load automatically; additional files are optional.
|
|
|
|
- [Start Dify](#start-dify)
|
|
- [Configure Dify](#configure-dify)
|
|
- [Troubleshoot setup and configuration](#troubleshoot-setup-and-configuration)
|
|
- [Review configuration after an upgrade](#review-configuration-after-an-upgrade)
|
|
- [Run middleware for development](#run-middleware-for-development)
|
|
- [Configure HTTPS and telemetry](#configure-https-and-telemetry)
|
|
- [Configure worker queues and webhooks](#configure-worker-queues-and-webhooks)
|
|
- [Enable the KnowledgeFS integration](#enable-the-knowledgefs-integration)
|
|
- [Configure client IP and trusted proxies](#client-ip-and-trusted-proxies)
|
|
|
|
## Start Dify
|
|
|
|
Before you begin, install Docker with a running daemon, Docker Compose **v2.35.0 or
|
|
later**, and OpenSSL to generate the sandbox token. Check your Compose version with
|
|
`docker compose version`. Version 2.35.0 or later is required for root `.env`
|
|
overrides to take precedence when Compose resolves service defaults.
|
|
|
|
For an existing deployment, edit your current `.env` instead of replacing it.
|
|
For a new deployment, follow these steps:
|
|
|
|
1. From the repository root, enter the Docker directory and copy the template:
|
|
|
|
```bash
|
|
cd docker
|
|
cp .env.example .env
|
|
```
|
|
|
|
Unless noted otherwise, run commands below from `docker/`.
|
|
|
|
2. Generate a token:
|
|
|
|
```bash
|
|
openssl rand -hex 32
|
|
```
|
|
|
|
Open `.env` and paste the output as the value of
|
|
`DIFY_AGENT_LOCAL_SANDBOX_AUTH_TOKEN`. Keep
|
|
`COMPOSE_PROFILES=weaviate,postgresql,collaboration` for the default deployment.
|
|
No other configuration files are required.
|
|
|
|
3. Start the services and check their status:
|
|
|
|
```bash
|
|
docker compose up -d
|
|
docker compose ps --all
|
|
```
|
|
|
|
Wait for the long-running services to start and their health checks to pass.
|
|
The one-time `init_permissions` service is expected to exit with code `0`.
|
|
|
|
4. Open [http://localhost/install](http://localhost/install) and complete the
|
|
initial setup. If you changed the published HTTP port, use that port in the URL.
|
|
|
|
Before using this deployment in production, replace the bundled credentials using
|
|
[the security template](envs/security.env.example) and the matching service files,
|
|
and configure [HTTPS](#configure-https-and-telemetry) and
|
|
[trusted proxies](#client-ip-and-trusted-proxies).
|
|
|
|
## Configure Dify
|
|
|
|
### Choose the configuration file
|
|
|
|
| File | Purpose | Loaded directly? |
|
|
| --- | --- | --- |
|
|
| `.env.example` | Minimal template for required deployment inputs | No; copy it to `.env` |
|
|
| `.env` | Deployment inputs and explicit overrides, including Compose settings | Yes |
|
|
| `envs/**/*.defaults` | Tracked defaults for the matching services | Yes, automatically |
|
|
| `envs/**/*.env` | Optional service or provider overrides | Yes, when the matching service references the file |
|
|
| `envs/**/*.env.example` | Templates for optional application and provider settings | No; remove `.example`, except for the middleware template below |
|
|
| `envs/middleware.env.example` | Template for the separate source-code development stack | No; copy to `middleware.env` in `docker/` |
|
|
|
|
Keep settings with usable defaults out of the root `.env.example`. To customize a
|
|
service, copy its `.defaults` file to the override path named in its comments,
|
|
usually replacing `.defaults` with `.env` in the same directory. Edit the copy,
|
|
or the existing `.env` if one is already present. Uncomment only the optional
|
|
assignments you want to change; leave unused empty values and placeholders
|
|
commented. For an optional `.env.example` template, review its comments and fill
|
|
in the settings before use.
|
|
|
|
Find settings in:
|
|
|
|
- [Core services](envs/core-services/): API, workers, web, plugin daemon, and
|
|
sandboxes. [api-worker.defaults](envs/core-services/api-worker.defaults) contains the
|
|
common API, worker, and Beat settings, grouped by function. API process options
|
|
live in `api.defaults`; worker autoscaling lives in `worker.defaults`.
|
|
- [Databases](envs/databases/): PostgreSQL, MySQL, and Redis.
|
|
- [Vector stores](envs/vectorstores/): bundled and external vector databases,
|
|
including their API/worker client settings. Providers without a dedicated
|
|
template are documented in `api-worker.defaults`.
|
|
- [Infrastructure](envs/infrastructure/): nginx, Certbot, proxies, and supporting services.
|
|
|
|
### Change a service setting
|
|
|
|
For example, to set nginx's upload limit to `200M`:
|
|
|
|
1. Create the optional override file if it does not already exist:
|
|
|
|
```bash
|
|
cp envs/infrastructure/nginx.defaults envs/infrastructure/nginx.env
|
|
```
|
|
|
|
2. In `envs/infrastructure/nginx.env`, replace the input setting with:
|
|
|
|
```dotenv
|
|
NGINX_CLIENT_MAX_BODY_SIZE=200M
|
|
```
|
|
|
|
Leave expressions under `Container variable mappings` unchanged. They translate
|
|
input names such as `SANDBOX_WORKER_TIMEOUT` into the container's `WORKER_TIMEOUT`.
|
|
|
|
3. Apply the change and inspect nginx's active configuration:
|
|
|
|
```bash
|
|
docker compose up -d
|
|
docker compose exec -T nginx nginx -T 2>&1 | grep client_max_body_size
|
|
```
|
|
|
|
The output should contain `client_max_body_size 200M;`.
|
|
|
|
Use `docker compose up -d` after editing configuration files. Compose recreates
|
|
containers whose configuration changed. `docker compose restart` does not reload
|
|
environment variables. No extra `--env-file` option is needed for this deployment.
|
|
|
|
### Change a published port or another Compose setting
|
|
|
|
Put settings consumed by Compose in root `.env`: `COMPOSE_PROFILES`, published
|
|
ports, volume paths, resource limits, and health-check intervals. Service env
|
|
files cannot change those parts of the Compose model.
|
|
|
|
For example, add or update this line in `.env` to use HTTP port `8080`:
|
|
|
|
```dotenv
|
|
EXPOSE_NGINX_PORT=8080
|
|
```
|
|
|
|
Run `docker compose up -d`, then open
|
|
[http://localhost:8080/install](http://localhost:8080/install).
|
|
Use root `.env` for values shared with the isolated local Agent sandbox, including
|
|
its authentication token.
|
|
|
|
### Change shared plugin credentials
|
|
|
|
Set both shared plugin credentials in root `.env`, so every service receives the
|
|
same values:
|
|
|
|
| Root `.env` setting | Used by |
|
|
| --- | --- |
|
|
| `PLUGIN_DAEMON_KEY` | Plugin daemon authentication and its API, worker, and Agent clients |
|
|
| `PLUGIN_DIFY_INNER_API_KEY` | API inner-endpoint authentication and its plugin daemon, worker, Agent, and KnowledgeFS clients |
|
|
|
|
Generate a separate value for each key with `openssl rand -hex 32`, then add the two
|
|
assignments to `.env`. If you previously set these keys in a service `.env` file,
|
|
move them to root `.env`. Leave the derived container key expressions unchanged
|
|
when copying service defaults, including the Agent's derived key expressions.
|
|
Editing only `plugin-daemon.env`, `api.env`, or `worker.env` does not update every
|
|
consumer and can cause HTTP 401 responses.
|
|
|
|
Run `docker compose up -d` to apply the credentials to all affected services.
|
|
These optional overrides do not need to be added to `.env.example`.
|
|
|
|
### Select a database or vector store
|
|
|
|
In root `.env`, set `VECTOR_STORE` and update `COMPOSE_PROFILES` to select the
|
|
matching bundled vector store. Compose supplies its connection defaults to the
|
|
API, workers and Beat automatically. For example, a new deployment with Qdrant
|
|
and PostgreSQL uses:
|
|
|
|
```dotenv
|
|
VECTOR_STORE=qdrant
|
|
COMPOSE_PROFILES=qdrant,postgresql,collaboration
|
|
```
|
|
|
|
Changing `VECTOR_STORE` selects the default for new indexes. Existing knowledge
|
|
bases keep using their stored backend, so preserve its connection settings and
|
|
keep its service running. If any use bundled Weaviate, retain its profile with
|
|
`COMPOSE_PROFILES=weaviate,qdrant,postgresql,collaboration` for this example.
|
|
|
|
Bundled Weaviate connection defaults remain available when another provider is
|
|
selected. An unchanged bundled service needs no additional connection settings;
|
|
existing overrides in `weaviate.env`, `api-worker.env`, and `shared.env` still
|
|
apply, with root `.env` taking precedence.
|
|
|
|
To customize the connection, copy the provider's `.defaults` file under
|
|
`envs/vectorstores/` to its `.env` path if that file does not already exist. Edit
|
|
the copy or the existing `.env` file. Elasticsearch's two selectors use
|
|
`elasticsearch.env`. Existing provider `.env` and `shared.env`
|
|
overrides remain supported. Keep `VECTOR_STORE` in root `.env`, since Compose
|
|
selects the defaults file before reading service files.
|
|
|
|
For an external vector store, omit its bundled profile and provide its connection
|
|
settings and credentials. For databases with stored user passwords, change the
|
|
password in the database before updating the corresponding client setting.
|
|
Starting a different database or vector store does not migrate existing data.
|
|
|
|
For OpenSearch HTTPS connections, `OPENSEARCH_VERIFY_CERTS` defaults to `true`
|
|
whenever `VECTOR_STORE=opensearch`, even without the bundled `opensearch` profile.
|
|
Keep verification enabled for production and external HTTPS servers, and use
|
|
certificates trusted by the client.
|
|
|
|
The bundled OpenSearch image uses demo certificates. For local development with
|
|
those certificates, explicitly set `OPENSEARCH_VERIFY_CERTS=false` in
|
|
`envs/vectorstores/opensearch.env` or root `.env`. To keep verification enabled,
|
|
configure certificates trusted by the client.
|
|
|
|
For example, the default deployment selects PostgreSQL and Weaviate with
|
|
`COMPOSE_PROFILES=weaviate,postgresql,collaboration`. The `collaboration` profile
|
|
starts the WebSocket API. Set `DB_TYPE` and the SQL database's connection settings
|
|
when changing that provider. See the [database](envs/databases/) and
|
|
[vector store](envs/vectorstores/) files for provider-specific settings.
|
|
|
|
For a new deployment using bundled MySQL and Weaviate, set the complete connection
|
|
in root `.env`:
|
|
|
|
```dotenv
|
|
DB_TYPE=mysql
|
|
DB_HOST=db_mysql
|
|
DB_PORT=3306
|
|
DB_USERNAME=root
|
|
COMPOSE_PROFILES=weaviate,mysql,collaboration
|
|
```
|
|
|
|
Keep your selected vector-store profile if it differs from this example. The
|
|
MySQL profile starts the database; it does not replace the PostgreSQL connection
|
|
defaults. Set `DB_PASSWORD` to the same value used to initialize the MySQL server.
|
|
Changing these settings on an existing PostgreSQL deployment does not migrate its data.
|
|
|
|
### Configure sandbox credentials
|
|
|
|
Set `DIFY_AGENT_LOCAL_SANDBOX_AUTH_TOKEN` only in root `.env`, using the secret
|
|
generated during setup. Compose supplies it to both the Agent backend and its
|
|
local sandbox. Move any existing copy of this token from `dify-agent.env` to root
|
|
`.env` and remove the duplicate; keep the same secret during the move.
|
|
|
|
The separate Code sandbox uses two settings that must match: `SANDBOX_API_KEY`
|
|
in `envs/core-services/sandbox.env` and `CODE_EXECUTION_API_KEY` in
|
|
`envs/security.env` (copied from `security.env.example`). Use the same generated
|
|
secret in both files, then run `docker compose up -d` to apply both changes.
|
|
You can also set both variables to the same value in root `.env`.
|
|
|
|
### Understand which value takes effect
|
|
|
|
For services that load root `.env`, precedence is:
|
|
|
|
1. Root `.env` overrides.
|
|
2. Optional service `.env` overrides.
|
|
3. Tracked `.defaults` values, followed by application defaults for unset settings.
|
|
|
|
Other services, including databases, vector stores, and nginx, receive root values
|
|
only through `${...}` expressions in their defaults or explicit Compose mappings.
|
|
For those inputs, root `.env` takes precedence over the service file. Arbitrary
|
|
native container variables do not inherit this precedence: for example, put
|
|
Weaviate's `ASYNC_INDEXING` in `envs/vectorstores/weaviate.env`; adding it to root
|
|
`.env` alone does not configure the Weaviate container.
|
|
|
|
The `knowledge_fs_unstructured` parser loads its defaults followed by
|
|
`envs/core-services/knowledge-fs-unstructured.env`, without loading root `.env`.
|
|
Set its parsing options in that service file.
|
|
|
|
Shell variables take precedence when Compose interpolates `${...}` expressions.
|
|
An explicit Compose `environment` entry also takes precedence over service env
|
|
files; [trusted-proxy settings](#client-ip-and-trusted-proxies) are one example.
|
|
The [KnowledgeFS section](#enable-the-knowledgefs-integration) describes its
|
|
restricted root overrides separately.
|
|
|
|
The API, workers, and plugin daemon also read the database and Redis override
|
|
files, so shared connection settings reach both the bundled server and its clients.
|
|
Changing a PostgreSQL or MySQL initialization password does not rotate credentials
|
|
in an existing database; use the database's credential-rotation procedure as well.
|
|
|
|
## Troubleshoot setup and configuration
|
|
|
|
Validate the Compose configuration and inspect the affected services:
|
|
|
|
```bash
|
|
docker compose config --quiet
|
|
docker compose ps --all
|
|
docker compose logs --tail=100 api worker nginx
|
|
```
|
|
|
|
Replace the service names in the logs command with the service you are diagnosing.
|
|
A successful `config --quiet` produces no output; it validates the Compose model,
|
|
not application readiness.
|
|
|
|
| Symptom | What to check |
|
|
| --- | --- |
|
|
| Editing a template has no effect | Copy `.env.example` to `.env`, or a service template to its documented `.env` path. Templates ending in `.example` are not loaded. |
|
|
| A service still uses its old value | Run `docker compose up -d`. Check for a higher-priority value in root `.env`, the shell, or an explicit Compose `environment` entry. |
|
|
| A port or profile change has no effect | Put the setting in root `.env`; these settings cannot be supplied through a service env file. |
|
|
| Service overrides resolve unexpectedly | Check that Docker Compose is v2.35.0 or later and that container-variable mapping expressions are intact. |
|
|
| Python sandbox code returns `operation not permitted` | Check the network-setting note in [sandbox.defaults](envs/core-services/sandbox.defaults). Sandbox 0.2.15 restricts the `epoll_pwait` syscall when networking is disabled on both ARM64 and AMD64. The runtime failure has been reproduced on ARM64. |
|
|
|
|
## Review configuration after an upgrade
|
|
|
|
Review the new root `.env.example` for required deployment inputs and the matching
|
|
`.defaults` files for changed service defaults. Preserve your existing `.env`
|
|
files; a copied service file can pin values from an older release.
|
|
|
|
Review any saved `OPENSEARCH_VERIFY_CERTS=false`: it stays in effect after an
|
|
upgrade. Remove the assignment or set it to `true` to enable certificate
|
|
verification.
|
|
|
|
Bundled service templates now use the `.defaults` extension. Existing service
|
|
`.env` paths still work. Root `.env.example` remains the only required starting
|
|
template, and the Compose generator creates only a missing root `.env`.
|
|
|
|
Common API and worker application settings are documented in
|
|
[api-worker.defaults](envs/core-services/api-worker.defaults). New customizations
|
|
use `envs/core-services/api-worker.env`. Existing `shared.env` files and other
|
|
service override paths remain supported; keep local files and edit them in place.
|
|
If both `shared.env` and `api-worker.env` exist, `api-worker.env` takes precedence
|
|
for matching settings. Root `.env` retains precedence over both files, including
|
|
for settings documented in a provider template.
|
|
|
|
Review accidental empty assignments left by older template copies. For example,
|
|
`CELERY_WORKER_AMOUNT=` overrides the Docker default of `4` and lets the worker
|
|
entrypoint fall back to `1`. Remove or comment out that assignment to restore
|
|
the Docker default. Likewise, remove accidental empty `SERVER_WORKER_CLASS=`
|
|
or `GUNICORN_TIMEOUT=` entries to restore `gevent` and `360`. Keep intentional
|
|
overrides; the configuration loader does not rewrite or discard them.
|
|
|
|
To merge new root-template keys into an existing `.env`, optionally run:
|
|
|
|
```bash
|
|
bash dify-env-sync.sh
|
|
```
|
|
|
|
The script backs up `.env` to `env-backup/.env.backup_<timestamp>`, adds missing
|
|
keys from `.env.example`, preserves existing values and extra local overrides,
|
|
and reports differences for review. It does not synchronize the files in `envs/`.
|
|
Review the resulting settings before running `docker compose up -d`.
|
|
|
|
## Run middleware for development
|
|
|
|
Use `docker-compose.middleware.yaml` when running the application from source and
|
|
you need its supporting services in Docker.
|
|
|
|
1. Create `middleware.env` if it does not exist:
|
|
|
|
```bash
|
|
cp envs/middleware.env.example middleware.env
|
|
```
|
|
|
|
2. Edit database and other middleware settings, then start the services:
|
|
|
|
```bash
|
|
docker compose --env-file middleware.env -f docker-compose.middleware.yaml -p dify up -d
|
|
```
|
|
|
|
This separate workflow requires `--env-file middleware.env`. The template defines
|
|
`COMPOSE_PROFILES=${DB_TYPE:-postgresql},weaviate`, which selects the database and
|
|
Weaviate. Update that value if you need different profiles.
|
|
|
|
## Configure HTTPS and telemetry
|
|
|
|
For HTTPS certificates, follow the [Certbot guide](certbot/README.md).
|
|
|
|
For OpenTelemetry, create `envs/core-services/api-worker.env` from `api-worker.defaults`
|
|
if it does not exist. Uncomment `ENABLE_OTEL` and set it to `true`; uncomment
|
|
`OTLP_BASE_ENDPOINT` and set it to your collector's endpoint, reachable from
|
|
the API and worker containers. The same file documents optional `OTEL_*`
|
|
tuning. Apply the changes with `docker compose up -d`.
|
|
|
|
## Configure worker queues and webhooks
|
|
|
|
Custom worker queue lists set through `CELERY_QUEUES` or `CELERY_WORKER_QUEUES` must include
|
|
`human_input_delivery` to process durable Human Input IM inbox events and recover
|
|
unconfirmed Human Input v2 notifications, and
|
|
`human_input_contact_sync` to process manual IM Contact directory synchronization.
|
|
|
|
Human Input IM channels in `WEBHOOK` mode build their Callback URL from `TRIGGER_URL`.
|
|
Set it to the externally reachable HTTPS origin of the API when configuring a remote
|
|
deployment. A localhost value is only suitable for local development. Reverse proxies
|
|
must forward `/callbacks/human-input/v2/im/` to the API and preserve the request path,
|
|
body, and provider signature headers. Copy the channel's Callback URL into the
|
|
provider's interaction configuration after changing the public origin.
|
|
|
|
### Ops tracing rolling upgrades
|
|
|
|
New tracing tasks use `OPS_TRACE_QUEUE=ops_trace_v2` by default. Set it consistently on the API,
|
|
workers, and Beat in `docker/envs/core-services/api-worker.env` (or `docker/.env`). Default worker
|
|
subscriptions follow this value; explicit `CELERY_QUEUES` or `CELERY_WORKER_QUEUES` lists must
|
|
include it and exclude legacy `ops_trace` while old workers are draining.
|
|
|
|
Keep an old tracing worker pool on `ops_trace` until old producers stop and their queued, active, reserved, scheduled, and
|
|
retry tasks finish. To return to `ops_trace`, first remove old workers, have new workers consume
|
|
both queues, then change `OPS_TRACE_QUEUE` on all new processes and drain `ops_trace_v2` before
|
|
removing its consumers. See the [complete rollout sequence](../api/providers/trace/README.md#rolling-upgrade-from-the-previous-pipeline).
|
|
|
|
## Enable the KnowledgeFS integration
|
|
|
|
The optional `knowledge-fs` Compose profile starts the internal KnowledgeFS API service and the
|
|
dedicated Dataset upgrade worker. The API service publishes no host port and has no nginx route.
|
|
Model, datasource, and object-storage calls go through Dify's inner API.
|
|
Dify resolves active Workspace/plugin configuration and remains the only owner of physical
|
|
storage credentials. `KNOWLEDGE_FS_ENABLED` remains `false`, so starting the container does not
|
|
enable product traffic.
|
|
|
|
Copy the dedicated service template if the local file does not already exist:
|
|
|
|
```bash
|
|
cp envs/core-services/knowledge-fs.env.example envs/core-services/knowledge-fs.env
|
|
```
|
|
|
|
Fill in the operator-owned inputs described in `knowledge-fs.env` before starting
|
|
the services. The default image is the CI-published deployment-branch image; set
|
|
`KNOWLEDGE_FS_API_IMAGE` to pin another tag or immutable SHA tag. If the image
|
|
repository is private, authenticate with `docker login` before pulling:
|
|
|
|
```bash
|
|
docker compose --profile knowledge-fs --profile knowledge-fs-unstructured config --quiet
|
|
docker compose --profile knowledge-fs --profile knowledge-fs-unstructured pull knowledge_fs knowledge_fs_unstructured
|
|
docker compose --profile knowledge-fs --profile knowledge-fs-unstructured up -d
|
|
```
|
|
|
|
The service env file intentionally contains only operator-owned inputs: the dedicated database,
|
|
durable compilation switch, Capability v2 public verification material, and optional Unstructured
|
|
endpoint. Compose injects the Dify inner API connection and integrated mode. KnowledgeFS stores
|
|
objects below an internal namespace in Dify's configured `STORAGE_TYPE`; do not duplicate Dify's
|
|
bucket, endpoint, or provider credentials in `knowledge-fs.env`. Feature-specific rollout flags
|
|
and capacity tunables should be added only when deliberately overriding their safe runtime
|
|
defaults.
|
|
|
|
### Configure document parsing
|
|
|
|
The optional `knowledge-fs-unstructured` profile starts one isolated parser service named
|
|
`knowledge_fs_unstructured` for every KnowledgeFS remote format. Its tracked
|
|
`knowledge-fs-unstructured-service.defaults` additionally enables bounded page parallelism for
|
|
PDFs and a 25-million-pixel pre-allocation limit per page at the pinned 350 DPI; an optional copied
|
|
`knowledge-fs-unstructured.env` can override those service values. Do not raise the DPI or pixel
|
|
limit, or disable the guard: the KnowledgeFS client estimates page rasters at 350 DPI and rejects
|
|
oversized or unverifiable page geometry before sending it to the parser. Oversized pages need
|
|
smaller page dimensions or tiling before import; reducing compressed file size alone does not
|
|
help. Existing installations need the new KnowledgeFS image and a recreated parser service to
|
|
activate both guards. The existing `unstructured` profile remains unchanged for Dify's legacy
|
|
ETL, so KnowledgeFS tuning cannot alter its PDF or Office parsing behavior. The copied
|
|
`knowledge-fs.env` pairs every PDF and structurally/byte-heavy remote document with the longer
|
|
deadline and narrower admission gate; ordinary formats retain two concurrent requests and a
|
|
600-second timeout, while heavy work uses one concurrent request and a 2,400-second timeout. The
|
|
remote input cap defaults to 15 MiB so the parser accepts the complete product upload envelope. The
|
|
legacy `UNSTRUCTURED_PDF_*` names remain lower-precedence compatibility aliases. The isolated
|
|
service is available to KnowledgeFS at `http://knowledge_fs_unstructured:8000`; it does not
|
|
publish a host port.
|
|
|
|
### Configure PDF image rendering
|
|
|
|
The KnowledgeFS API image includes Poppler and enables its `pdftoppm` PDF image rasterizer with
|
|
bounded defaults (144 DPI, 48 DPI thumbnails, a 30-second timeout, at most 500 assets per document,
|
|
and two concurrent Poppler page batches per replica). Canonical settings live in the dedicated
|
|
`knowledge-fs.env`; whitelisted `DIFY_ROOT_*_OVERRIDE` proxies let explicitly set values in
|
|
`docker/.env` take precedence without injecting the complete root environment. When a root value
|
|
is unset, the service env or image default remains authoritative. Set
|
|
`KNOWLEDGE_PDF_RASTERIZER=off` in either operator env as an emergency or low-resource kill switch. Existing
|
|
documents whose parse artifacts lack image asset references must be ingested again after rollout.
|
|
|
|
### Check storage and readiness before enabling traffic
|
|
|
|
Use a dedicated KnowledgeFS database. Do not point `DATABASE_URL` at Dify's application database,
|
|
reuse Dataset/Document tables, or run a data migration as part of this service. KnowledgeFS
|
|
migrations remain a separate controlled operator step. The selected Dify storage backend must
|
|
support recursive `scan`; the currently verified paths are S3 and OpenDAL/local.
|
|
|
|
The production entrypoint supports the explicitly selected Capability v2 verifier and accepts only
|
|
public JWKS material. The `knowledge_fs` container can still return `200` from
|
|
`/health` while `/ready` returns `503` when the verifier or another durable dependency is missing;
|
|
this is intentional fail-closed behavior. Do not add a proxy route, set
|
|
`KNOWLEDGE_FS_ENABLED=true`, or send product traffic until readiness returns `200` and the migration
|
|
and per-Workspace cutover gates are complete.
|
|
|
|
### Run lifecycle and upgrade workers
|
|
|
|
The standard Dify worker consumes `knowledge_fs_lifecycle` for provisioning, deletion, initial
|
|
source imports, and staged-upload cleanup. Deployments overriding `CELERY_QUEUES` or
|
|
`CELERY_WORKER_QUEUES` must include this queue in a worker pool. Enable the lifecycle rollout gates
|
|
on the API, workers, and Beat before creating spaces.
|
|
|
|
Classic Dataset upgrades use the separate `worker_knowledge_fs_upgrade` service. It starts with
|
|
the `knowledge-fs` Compose profile, so enable that profile before submitting an upgrade. This
|
|
worker must use `CELERY_WORKER_POOL=prefork`; for local development, run
|
|
`./dev/start-worker --queues knowledge_fs_upgrade --pool prefork` from the repository root.
|
|
Each checkpoint has a 570-second
|
|
soft limit and a 600-second hard limit. Do not override these task limits: recovery relies on the
|
|
child having stopped before reclaiming its execution window. Beat checks for abandoned running
|
|
jobs and publication claims every minute after the lifecycle gates are ready. Claims without
|
|
progress for 11 minutes can be recovered automatically or through the upgrade retry endpoint.
|
|
Stop existing upgrade workers before deploying this recovery change, then recreate the API,
|
|
worker, upgrade worker, and Beat with the new image and pool configuration.
|
|
|
|
Document reconciliation has its own durable delivery lease after the parent upgrade succeeds.
|
|
Beat also scans successful upgrades with unfinished document checkpoints, so a failed publication
|
|
or interrupted reconciliation is retried without restarting the upgrade. Unclaimed successful jobs
|
|
are eligible immediately; lost deliveries are reclaimed after the 11-minute lease expires, and
|
|
completed attempts with unfinished work become eligible again after one minute. Apply the
|
|
`b9d3f7a5c102` migration before starting the updated processes; existing successful upgrades receive
|
|
NULL leases and are picked up automatically. Reconciliation uses the same prefork pool and
|
|
570/600-second task limits. Keep Beat running with the lifecycle rollout gates enabled.
|
|
|
|
Upgrade uploads retain their logical document identity before compilation finishes, so pending
|
|
or failed documents can have their legacy disabled state restored without an active revision.
|
|
Reconciliation releases a deleted document's checkpoint only after verifying a completed durable
|
|
deletion receipt for that identity; a missing document or upstream error alone is not sufficient.
|
|
Custom metadata is restored from the snapshot's field definitions, converting Classic UTC epoch
|
|
seconds to ISO timestamps for time fields. Classic built-in fields are omitted because KnowledgeFS
|
|
owns its system metadata. These corrections also apply when retrying existing unfinished
|
|
checkpoints and require no additional migration.
|
|
|
|
## Client IP and trusted proxies
|
|
|
|
Dify uses the request's resolved client IP for rate limits and audit records. The
|
|
bundled Nginx overwrites `X-Forwarded-For` with `$remote_addr`, and Compose enables
|
|
`RESPECT_XFORWARD_HEADERS_ENABLED` for the API and WebSocket API services. Dify's
|
|
proxy middleware trusts one forwarded value, so different visitors keep separate
|
|
IP buckets while caller-supplied IP headers cannot override Nginx's address.
|
|
|
|
The middleware does not authenticate the proxy. Keep the API port private and
|
|
restrict direct API connections to trusted callers. Compose does not publish that
|
|
port, but services on its shared Docker networks can still connect directly,
|
|
including the code sandbox on `ssrf_proxy_network`. Those connections bypass
|
|
Nginx's header replacement. If those workloads are untrusted, enforce network or
|
|
firewall isolation and route their API calls through a sanitizing gateway before
|
|
enabling forwarded-header trust. Merely setting a Docker network to `internal`
|
|
does not isolate containers from each other.
|
|
|
|
For a directly exposed API, leave `RESPECT_XFORWARD_HEADERS_ENABLED=false`.
|
|
The Python configuration and `api/.env.example` retain that default. To override
|
|
the Compose default, set the variable in `docker/.env`, the shell used by Compose,
|
|
or a Compose override. The API services' explicit `environment` entry takes
|
|
precedence over `envs/core-services/api-worker.env` and legacy `shared.env` files.
|
|
Existing `false` overrides in `docker/.env`, the invoking shell, or a Compose
|
|
override remain in effect during upgrades. Move settings previously supplied only
|
|
by `api-worker.env` or `shared.env` to one of those override locations if you need to preserve them.
|
|
After establishing the trusted ingress boundary, enable the setting to retain
|
|
visitor IPs.
|
|
|
|
### Cloudflare or another load balancer before Nginx
|
|
|
|
With an upstream proxy, configure Nginx to resolve the visitor address before
|
|
forwarding it. Otherwise `$remote_addr` is the upstream proxy's address, and its
|
|
visitors share a rate-limit bucket. Add an operator-managed
|
|
`docker/nginx/conf.d/real-ip.conf`; the existing mount and Nginx include load this
|
|
file without changes to the entrypoint.
|
|
|
|
For a load balancer that supplies a correctly maintained `X-Forwarded-For` chain:
|
|
|
|
```nginx
|
|
# Replace this documentation address with the actual trusted proxy address/CIDR.
|
|
set_real_ip_from 192.0.2.10/32;
|
|
real_ip_header X-Forwarded-For;
|
|
real_ip_recursive on;
|
|
```
|
|
|
|
For Cloudflare connecting directly to Nginx, use `real_ip_header CF-Connecting-IP`
|
|
and `set_real_ip_from` entries for Cloudflare's current published IPv4 and IPv6
|
|
ranges. Restrict origin access to the intended Cloudflare path; a Tunnel or
|
|
Authenticated Origin Pulls with your own certificate can authenticate your zone.
|
|
Cloudflare IP ranges alone identify its network, not your zone. If another load
|
|
balancer sits between Cloudflare and Nginx, validate the source and sanitize
|
|
headers at that load balancer too. Do not trust an arbitrary Cloudflare header
|
|
merely because an internal load balancer forwarded it.
|
|
|
|
Never use `0.0.0.0/0`, `::/0`, or an entire untrusted workload network as the trusted
|
|
proxy range. Reload Nginx after updating its configuration. See the
|
|
[Nginx real-IP module](https://nginx.org/en/docs/http/ngx_http_realip_module.html),
|
|
[Cloudflare IP ranges](https://www.cloudflare.com/ips/), and
|
|
[Cloudflare origin protection](https://developers.cloudflare.com/fundamentals/security/protect-your-origin-server/).
|
|
|
|
### Kubernetes
|
|
|
|
Use stable workload selectors to restrict API access; individual ingress pod IPs
|
|
do not need to be configured in Dify. The ingress must resolve and overwrite the
|
|
forwarded client IP as above. Keep the API Service as `ClusterIP`, set
|
|
`RESPECT_XFORWARD_HEADERS_ENABLED=true` on its Deployment, and enforce a
|
|
NetworkPolicy on the API pods. `ClusterIP` alone does not restrict other pods.
|
|
|
|
This example must be adapted to your namespaces, pod labels, and API port:
|
|
|
|
```yaml
|
|
apiVersion: networking.k8s.io/v1
|
|
kind: NetworkPolicy
|
|
metadata:
|
|
name: api-from-ingress
|
|
namespace: dify
|
|
spec:
|
|
podSelector:
|
|
matchLabels:
|
|
app: dify-api
|
|
policyTypes:
|
|
- Ingress
|
|
ingress:
|
|
- from:
|
|
- namespaceSelector:
|
|
matchLabels:
|
|
kubernetes.io/metadata.name: ingress-system
|
|
podSelector:
|
|
matchLabels:
|
|
app: ingress-controller
|
|
ports:
|
|
- protocol: TCP
|
|
port: 5001
|
|
```
|
|
|
|
Both selectors belong to the same `from` entry, so the namespace **and** pod labels
|
|
must match. Keep that namespace restricted to trusted workloads. Confirm that
|
|
your CNI enforces NetworkPolicy, no other policy broadly allows API access, and
|
|
any `hostNetwork` ingress is covered by your CNI's policy behavior. Allow rules
|
|
from multiple policies are additive. See the
|
|
[Kubernetes NetworkPolicy documentation](https://kubernetes.io/docs/concepts/services-networking/network-policies/).
|
|
|
|
Inventory internal API callers before applying the policy. Route untrusted
|
|
callers through the same sanitizing ingress; directly allowed callers can supply
|
|
forwarded headers too. Internal requests without a verified visitor address are
|
|
attributed to the calling service, not an end user. Preserve required internal
|
|
service connectivity while enforcing this boundary.
|
|
|
|
Before rollout, verify that two distinct visitor IPs use different limit buckets,
|
|
changing client-supplied IP headers does not change the resolved address, and an
|
|
untrusted pod cannot connect directly to the API. IP limits still need independent
|
|
account/email limits because NAT can share public addresses and attackers can
|
|
use multiple real addresses.
|