fix(docker): honor categorized service environment overrides (#45359)

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
-LAN-andautofix-ci[bot] authored and GitHub committed 2026-11-03 01:58:43 +00:00
1 parent 8d812b938a
commit 53ea596fc7
75 files changed
+2793 -2045

No files matched your search

+7
View File
@@ -30,6 +30,9 @@ jobs:
docker/.env.example
docker/docker-compose-template.yaml
docker/docker-compose.yaml
docker/docker-compose.e2b.yaml
docker/envs/**
docker/tests/**
- name: Check api inputs
if: github.event_name != 'merge_group'
id: api-changes
@@ -72,6 +75,10 @@ jobs:
cd docker
./generate_docker_compose
- name: Check Docker environment overrides
if: github.event_name != 'merge_group' && steps.docker-compose-changes.outputs.any_changed == 'true'
run: python3 -m unittest discover -s docker/tests -p 'test_*.py'
- if: github.event_name != 'merge_group' && steps.api-changes.outputs.any_changed == 'true'
run: |
cd api
+1 -1
View File
@@ -111,7 +111,7 @@ jobs:
- 'docker/dify-env-sync.sh'
- 'docker/docker-compose-template.yaml'
- 'docker/docker-compose.yaml'
- 'docker/envs/core-services/api.env.example'
- 'docker/envs/core-services/api.defaults'
- 'docker/envs/core-services/knowledge-fs.env.example'
- 'docker/envs/core-services/knowledge-fs-unstructured-service.defaults'
- 'docker/envs/core-services/knowledge-fs-unstructured.env.example'
@@ -1,3 +1,4 @@
import re
from pathlib import Path
from dotenv import dotenv_values
@@ -99,22 +100,58 @@ def _api_config_set() -> set[str]:
return set(dotenv_values(REPO_ROOT / "api" / ".env.example").keys())
def _docker_config_set() -> set[str]:
docker_config_set = set(dotenv_values(REPO_ROOT / "docker" / ".env.example").keys())
envs_dir = REPO_ROOT / "docker" / "envs"
if envs_dir.exists():
for env_file_path in envs_dir.rglob("*.env.example"):
docker_config_set.update(dotenv_values(env_file_path).keys())
def _docker_config_set(docker_dir: Path) -> set[str]:
"""Return keys documented in readable Docker templates, excluding local overrides.
Include assignments, commented assignments, and explicit root .env instructions.
The root .env.example must exist; read failures propagate without changing any files.
"""
envs_dir = docker_dir / "envs"
env_files = [docker_dir / ".env.example", *envs_dir.rglob("*.env.example"), *envs_dir.rglob("*.defaults")]
docker_config_set: set[str] = set()
for env_file_path in env_files:
content = env_file_path.read_text()
docker_config_set.update(dotenv_values(env_file_path, interpolate=False).keys())
docker_config_set.update(re.findall(r"(?m)^[ \t]*#[ \t]*([A-Z_][A-Z0-9_]*)=", content))
docker_config_set.update(re.findall(r"(?m)^# Set ([A-Z_][A-Z0-9_]*) in docker/\.env\b", content))
return docker_config_set
def test_docker_config_set_includes_documented_keys_only(tmp_path: Path) -> None:
"""Given templates and local overrides, collect only keys documented in the templates."""
envs_dir = tmp_path / "envs" / "core-services"
envs_dir.mkdir(parents=True)
(tmp_path / ".env.example").write_text("ROOT_KEY=value\n# ROOT_OPTIONAL=\n")
(envs_dir / "service.defaults").write_text(
"DEFAULT_KEY=${ROOT_KEY:-fallback}\n# OPTIONAL_KEY=\n # INDENTED_KEY=value\n"
"# Set COMPOSE_PORT in docker/.env; Compose needs it before loading service files.\n"
"# Prose with NOT_A_KEY=value\n# NO_ASSIGNMENT\n"
)
(envs_dir / "provider.env.example").write_text("PROVIDER_KEY=value\n# PROVIDER_OPTIONAL=value\n")
(tmp_path / ".env").write_text("LOCAL_ROOT_KEY=private\n")
(envs_dir / "service.env").write_text("LOCAL_SERVICE_KEY=private\n")
assert _docker_config_set(tmp_path) == {
"ROOT_KEY",
"ROOT_OPTIONAL",
"DEFAULT_KEY",
"OPTIONAL_KEY",
"INDENTED_KEY",
"COMPOSE_PORT",
"PROVIDER_KEY",
"PROVIDER_OPTIONAL",
}
def test_api_env_keys_exist_in_docker_env_examples() -> None:
diff = _api_config_set() - _docker_config_set() - BASE_API_AND_DOCKER_CONFIG_SET_DIFF
"""Require every non-exempt API setting to remain documented in Docker templates."""
diff = _api_config_set() - _docker_config_set(REPO_ROOT / "docker") - BASE_API_AND_DOCKER_CONFIG_SET_DIFF
assert not diff, f"API and Docker config sets are different with keys: {sorted(diff)}"
def test_api_env_keys_exist_in_docker_compose_env_examples() -> None:
diff = _api_config_set() - _docker_config_set() - BASE_API_AND_DOCKER_COMPOSE_CONFIG_SET_DIFF
"""Require every non-exempt API setting to remain documented for Docker Compose."""
diff = _api_config_set() - _docker_config_set(REPO_ROOT / "docker") - BASE_API_AND_DOCKER_COMPOSE_CONFIG_SET_DIFF
assert not diff, f"API and Docker Compose config sets are different with keys: {sorted(diff)}"
@@ -25,10 +25,8 @@ def test_binding_file_download_timeout_rejects_non_positive_values() -> None:
def test_binding_file_timeout_docker_settings_use_their_service_env_files() -> None:
root_env_example = (_REPOSITORY_ROOT / "docker/.env.example").read_text(encoding="utf-8")
api_env_example = (_REPOSITORY_ROOT / "docker/envs/core-services/api.env.example").read_text(encoding="utf-8")
agent_env_example = (_REPOSITORY_ROOT / "docker/envs/core-services/dify-agent.env.example").read_text(
encoding="utf-8"
)
api_env_example = (_REPOSITORY_ROOT / "docker/envs/core-services/api.defaults").read_text(encoding="utf-8")
agent_env_example = (_REPOSITORY_ROOT / "docker/envs/core-services/dify-agent.defaults").read_text(encoding="utf-8")
compose_template = (_REPOSITORY_ROOT / "docker/docker-compose-template.yaml").read_text(encoding="utf-8")
assert f"{_API_TIMEOUT_ENV}=" not in root_env_example
@@ -122,7 +122,7 @@ def test_disabled_knowledge_fs_config_allows_partial_connection() -> None:
def test_knowledge_fs_docker_config_is_not_shadowed_by_root_env() -> None:
root_env_example = (_REPOSITORY_ROOT / "docker/.env.example").read_text(encoding="utf-8")
api_env_example = (_REPOSITORY_ROOT / "docker/envs/core-services/api.env.example").read_text(encoding="utf-8")
api_env_example = (_REPOSITORY_ROOT / "docker/envs/core-services/api.defaults").read_text(encoding="utf-8")
for variable in _KNOWLEDGE_FS_DOCKER_VARIABLES:
assert f"{variable}=" not in root_env_example
+1 -1
View File
@@ -58,7 +58,7 @@ DIFY_AGENT_E2B_ACTIVE_TIMEOUT_SECONDS=3600
DIFY_AGENT_E2B_SHELLCTL_PORT=5004
# Minimal OpenShell configuration subset for local debugging.
# Full configuration reference: docker/envs/core-services/dify-agent.env.example
# Full configuration reference: docker/envs/core-services/dify-agent.defaults
DIFY_AGENT_OPENSHELL_GATEWAY_ENDPOINT=localhost:17670
DIFY_AGENT_OPENSHELL_TLS_CA_PATH=${HOME}/.config/openshell/gateways/openshell/mtls/ca.crt
DIFY_AGENT_OPENSHELL_TLS_CLIENT_CERT_PATH=${HOME}/.config/openshell/gateways/openshell/mtls/tls.crt
@@ -153,7 +153,7 @@ spec:
```
Configure the backend in `docker/.env`. The full `DIFY_AGENT_OPENSHELL_*`
variable reference lives in `docker/envs/core-services/dify-agent.env.example`;
variable reference lives in `docker/envs/core-services/dify-agent.defaults`;
values may also be set in the `envs/core-services/dify-agent.env` env_file,
but `docker/.env` is loaded last into `agent_backend` and overrides it. These
lines are `.env` file content, not shell commands — values are taken verbatim,
+6 -1
View File
@@ -1,10 +1,15 @@
# Only settings requiring manual configuration belong in this file.
# Requires Docker Compose v2.35.0+ for .env override precedence.
# Application and Docker defaults are loaded automatically; do not repeat them here.
# Copy this file to .env, then select the services for your deployment.
# Optional overrides and provider settings are documented in envs/**/*.env.example.
# Optional overrides and provider settings are documented in envs/.
# Values in .env take precedence over the matching envs/*.env files.
# Compose requires an explicit selection of the bundled database, vector store,
# and websocket service. Match these profiles to your DB_TYPE and VECTOR_STORE
# overrides when using different providers; omit services hosted externally.
COMPOSE_PROFILES=weaviate,postgresql,collaboration
# Required for the default local Agent sandbox. Generate with: openssl rand -hex 32
# Both the Agent backend and shellctl use this shared secret.
DIFY_AGENT_LOCAL_SANDBOX_AUTH_TOKEN=
+362 -171
View File
@@ -1,103 +1,299 @@
# Docker deployment
Run Dify with Docker Compose. Configuration templates live in `.env.example` and `envs/`; local overrides belong in `.env`.
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.
## How to Deploy Dify with `docker-compose.yaml`
- [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:
1. **Prerequisites**: Ensure Docker and Docker Compose v2.24.0 or later are installed on your system.
2. **Environment Setup**:
- Navigate to the `docker` directory.
- Copy `.env.example` to `.env`.
- Select the bundled services through `COMPOSE_PROFILES`. Add overrides to `.env` only when needed. Copy optional files from `envs/` without the `.example` suffix when you need advanced settings.
- **Optional (for advanced deployments)**:
If you maintain a full `.env` file copied from `.env.example`, you may use the environment synchronization tool to keep it aligned with the latest `.env.example` updates while preserving your custom settings.
See the [Environment Variables Synchronization](#environment-variables-synchronization) section below.
3. **Running the Services**:
- Execute `docker compose up -d` from the `docker` directory to start the services.
- To specify a vector database, set the `VECTOR_STORE` variable in your `.env` file to your desired vector database service, such as `milvus`, `weaviate`, or `opensearch`, and select the matching service in `COMPOSE_PROFILES`. See `envs/vectorstores/` for the full list of supported options.
```bash
cd docker
cp .env.example .env
docker compose up -d
```
4. **SSL Certificate Setup**:
- Refer to [the Certbot guide](certbot/README.md) to set up SSL certificates using Certbot.
5. **OpenTelemetry Collector Setup**:
- Copy `envs/core-services/shared.env.example` to `envs/core-services/shared.env`.
- Set `ENABLE_OTEL=true` and configure `OTLP_BASE_ENDPOINT`. Tune the other `OTEL_*` knobs in the same file if needed.
Unless noted otherwise, run commands below from `docker/`.
## KnowledgeFS Integration Service
2. Generate a token:
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.
```bash
openssl rand -hex 32
```
Copy and fill the dedicated service configuration before enabling KnowledgeFS traffic. 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 the deployment host with
`docker login` before pulling:
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.
```bash
cp envs/core-services/knowledge-fs.env.example envs/core-services/knowledge-fs.env
docker compose --profile knowledge-fs --profile knowledge-fs-unstructured config
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
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 only `.example` when copying |
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. [shared.defaults](envs/core-services/shared.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 `shared.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
```
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.
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.
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 required
defaults file deliberately does not end
in `.env`, so it remains tracked and a clean checkout can validate the profile; files ending in
`.env.example` are copy-only templates and are never loaded as runtime configuration. The isolated
service is available to KnowledgeFS at `http://knowledge_fs_unstructured:8000`; it does not publish
a host port.
### Change shared plugin credentials
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.
Set both shared plugin credentials in root `.env`, so every service receives the
same values:
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.
| 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 |
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.
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
Set `DB_TYPE` or `VECTOR_STORE` and the provider's connection settings in the
appropriate override file. In root `.env`, update `COMPOSE_PROFILES` to select the
matching bundled services. Omit a service's profile when that service runs
externally. Starting a different database does not migrate existing data.
For example, the default deployment selects PostgreSQL and Weaviate with
`COMPOSE_PROFILES=weaviate,postgresql,collaboration`. The `collaboration` profile
starts the WebSocket API. See the [database](envs/databases/) and
[vector store](envs/vectorstores/) files for provider-specific settings.
### Understand which value takes effect
For settings loaded through these env files, precedence is:
1. Root `.env` overrides.
2. Optional service `.env` overrides.
3. Tracked `.defaults` values, followed by application defaults for unset settings.
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). On sandbox 0.2.15/ARM64, requests with networking disabled can trigger a runtime syscall restriction. |
## 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.
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`.
The shared application reference is now consolidated in
[shared.defaults](envs/core-services/shared.defaults). Existing `shared.env`
and other override paths still work; do not replace or rename your local files.
New customizations use the matching template listed above. Root `.env` retains
precedence, including for settings that have moved to 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/shared.env` from `shared.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
@@ -111,7 +307,87 @@ retry tasks finish. To return to `ops_trace`, first remove old workers, have new
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).
### KnowledgeFS lifecycle and upgrade workers
## 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
@@ -120,8 +396,9 @@ 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`; local development uses
`./dev/start-worker --queues knowledge_fs_upgrade --pool prefork`. Each checkpoint has a 570-second
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
@@ -260,89 +537,3 @@ 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.
## How to Deploy Middleware for Developing Dify
1. **Middleware Setup**:
- Use the `docker-compose.middleware.yaml` for setting up essential middleware services like databases and caches.
- Navigate to the `docker` directory.
- Ensure the `middleware.env` file is created by running `cp envs/middleware.env.example middleware.env` (refer to the `envs/middleware.env.example` file).
2. **Running Middleware Services**:
- Navigate to the `docker` directory.
- Execute `docker compose --env-file middleware.env -f docker-compose.middleware.yaml -p dify up -d` to start PostgreSQL/MySQL (per `DB_TYPE`) plus the bundled Weaviate instance.
> Compose automatically loads `COMPOSE_PROFILES=${DB_TYPE:-postgresql},weaviate` from `middleware.env`, so no extra `--profile` flags are needed. Adjust variables in `middleware.env` if you want a different combination of services.
## Overview of `.env`, `.env.example`, and `envs/`
- `.env.example` contains only settings requiring manual configuration, such as the Compose service selection.
- `.env` contains your deployment inputs and any explicit overrides.
- `envs/*.env.example` files contain optional advanced configuration grouped by theme.
Keep the root `.env.example` limited to settings that require manual user configuration.
Settings with usable application or Docker defaults must not appear there. Document optional,
advanced, provider-specific, and service-specific overrides in the appropriate `envs/*.env.example` file.
Docker Compose loads Docker-specific defaults from `envs/core-services/shared.defaults`,
then optional `envs/*.env` files, then `.env` so your overrides take precedence. Other defaults
come from the application and each service in `docker-compose.yaml`; do not copy them into `.env`.
The bundled credentials are intended for local deployment; override them for production using
the matching security and service templates.
For the available variables and defaults, read the matching `envs/**/*.env.example` template and its service in `docker-compose.yaml`.
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.
## Environment Variables Synchronization
When upgrading Dify or pulling the latest changes, new environment variables may be introduced in `.env.example` only when they require manual configuration,
or in the optional files under `envs/` for advanced, provider-specific, and service-specific settings.
If you use the default workflow, review `.env.example` and supply any new deployment inputs that require manual configuration.
If you maintain a customized `.env` file copied from `.env.example`, an optional environment variables synchronization tool is provided.
> This tool performs a **one-way synchronization** from `.env.example` to `.env`.
> Existing values in `.env` are never overwritten automatically.
### `dify-env-sync.sh` (Optional)
This script compares your current `.env` file with the latest `.env.example` template and helps safely apply new or updated environment variables.
**What it does**
- Creates a backup of the current `.env` file before making any changes
- Synchronizes newly added environment variables from `.env.example`
- Preserves the existing `.env`, including custom settings absent from `.env.example`
- Displays differences and additional local overrides for review
**Backup behavior**
Before synchronization, the current `.env` file is saved to the `env-backup/` directory with a timestamped filename
(e.g. `env-backup/.env.backup_20231218_143022`).
**When to use**
- After upgrading Dify to a newer version with a full `.env` file
- When `.env.example` has been updated with new environment variables
- When managing a large or heavily customized `.env` file copied from `.env.example`
**Usage**
```bash
# Grant execution permission (first time only)
chmod +x dify-env-sync.sh
# Run the synchronization
./dify-env-sync.sh
```
+171 -307
View File
@@ -1,11 +1,8 @@
# Shared configuration using YAML anchors and env_file
x-shared-api-worker-config: &shared-api-worker-config
x-shared-api-config: &shared-api-config
env_file:
- ./envs/core-services/shared.defaults
- path: ./envs/core-services/shared.env
required: false
- path: ./envs/core-services/api.env
required: false
- path: ./envs/security.env
required: false
- path: ./envs/databases/db-postgres.env
@@ -60,7 +57,11 @@ x-shared-api-worker-config: &shared-api-worker-config
required: false
- path: ./envs/infrastructure/milvus-standalone.env
required: false
- path: ./envs/core-services/api.env
required: false
- ./.env
- ./envs/core-services/shared.defaults
- ./envs/core-services/api.defaults
networks:
- ssrf_proxy_network
- default
@@ -68,11 +69,8 @@ x-shared-api-worker-config: &shared-api-worker-config
x-shared-worker-config: &shared-worker-config
env_file:
- ./envs/core-services/shared.defaults
- path: ./envs/core-services/shared.env
required: false
- path: ./envs/core-services/worker.env
required: false
- path: ./envs/security.env
required: false
- path: ./envs/databases/db-postgres.env
@@ -127,7 +125,11 @@ x-shared-worker-config: &shared-worker-config
required: false
- path: ./envs/infrastructure/milvus-standalone.env
required: false
- path: ./envs/core-services/worker.env
required: false
- ./.env
- ./envs/core-services/shared.defaults
- ./envs/core-services/worker.defaults
networks:
- ssrf_proxy_network
- default
@@ -143,11 +145,8 @@ x-knowledge-fs-celery-worker: &knowledge-fs-celery-worker
# Match the two-hour default task deadline plus shutdown margin for long document jobs.
stop_grace_period: 125m
env_file:
- ./envs/core-services/shared.defaults
- path: ./envs/core-services/shared.env
required: false
- path: ./envs/core-services/worker.env
required: false
- path: ./envs/security.env
required: false
- path: ./envs/databases/db-postgres.env
@@ -160,7 +159,11 @@ x-knowledge-fs-celery-worker: &knowledge-fs-celery-worker
required: false
- path: ./envs/core-services/knowledge-fs-worker.env
required: false
- path: ./envs/core-services/worker.env
required: false
- ./.env
- ./envs/core-services/shared.defaults
- ./envs/core-services/worker.defaults
environment: &knowledge-fs-celery-environment
MODE: worker
MIGRATION_ENABLED: "false"
@@ -181,11 +184,8 @@ x-knowledge-fs-celery-worker: &knowledge-fs-celery-worker
x-shared-worker-beat-config: &shared-worker-beat-config
env_file:
- ./envs/core-services/shared.defaults
- path: ./envs/core-services/shared.env
required: false
- path: ./envs/core-services/worker-beat.env
required: false
- path: ./envs/security.env
required: false
- path: ./envs/databases/db-postgres.env
@@ -240,7 +240,11 @@ x-shared-worker-beat-config: &shared-worker-beat-config
required: false
- path: ./envs/infrastructure/milvus-standalone.env
required: false
- path: ./envs/core-services/worker-beat.env
required: false
- ./.env
- ./envs/core-services/shared.defaults
- ./envs/core-services/worker-beat.defaults
networks:
- ssrf_proxy_network
- default
@@ -268,22 +272,10 @@ services:
# API service
api:
<<: *shared-api-worker-config
<<: *shared-api-config
image: langgenius/dify-api:1.18.0
environment:
MODE: api
# The bundled Nginx supplies a verified client IP; keep direct API callers trusted.
RESPECT_XFORWARD_HEADERS_ENABLED: ${RESPECT_XFORWARD_HEADERS_ENABLED:-true}
SENTRY_DSN: ${API_SENTRY_DSN:-}
SENTRY_TRACES_SAMPLE_RATE: ${API_SENTRY_TRACES_SAMPLE_RATE:-1.0}
SENTRY_PROFILES_SAMPLE_RATE: ${API_SENTRY_PROFILES_SAMPLE_RATE:-1.0}
PLUGIN_REMOTE_INSTALL_HOST: ${EXPOSE_PLUGIN_DEBUGGING_HOST:-localhost}
PLUGIN_REMOTE_INSTALL_PORT: ${EXPOSE_PLUGIN_DEBUGGING_PORT:-5003}
PLUGIN_MAX_PACKAGE_SIZE: ${PLUGIN_MAX_PACKAGE_SIZE:-52428800}
PLUGIN_DAEMON_TIMEOUT: ${PLUGIN_DAEMON_TIMEOUT:-600.0}
INNER_API_KEY_FOR_PLUGIN: ${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1}
AGENT_BACKEND_BASE_URL: ${AGENT_BACKEND_BASE_URL:-http://agent_backend:5050}
AGENT_BACKEND_API_TOKEN: ${DIFY_AGENT_API_TOKEN:-dify-agent-run-token-for-dev-only}
depends_on:
init_permissions:
condition: service_completed_successfully
@@ -318,17 +310,22 @@ services:
# WebSocket service for workflow collaboration.
api_websocket:
<<: *shared-api-worker-config
<<: *shared-api-config
image: langgenius/dify-api:1.18.0
profiles:
- collaboration
environment:
MODE: api
RESPECT_XFORWARD_HEADERS_ENABLED: ${RESPECT_XFORWARD_HEADERS_ENABLED:-true}
SERVER_WORKER_AMOUNT: ${API_WEBSOCKET_WORKER_AMOUNT:-1}
SERVER_WORKER_CLASS: ${API_WEBSOCKET_WORKER_CLASS:-geventwebsocket.gunicorn.workers.GeventWebSocketWorker}
SERVER_WORKER_CONNECTIONS: ${API_WEBSOCKET_WORKER_CONNECTIONS:-1000}
GUNICORN_TIMEOUT: ${API_WEBSOCKET_GUNICORN_TIMEOUT:-360}
# Resolve websocket settings after loading the shared/API service files.
entrypoint:
- /bin/bash
- -c
- |
export SERVER_WORKER_AMOUNT="$${API_WEBSOCKET_WORKER_AMOUNT:-1}"
export SERVER_WORKER_CLASS="$${API_WEBSOCKET_WORKER_CLASS:-geventwebsocket.gunicorn.workers.GeventWebSocketWorker}"
export SERVER_WORKER_CONNECTIONS="$${API_WEBSOCKET_WORKER_CONNECTIONS:-1000}"
export GUNICORN_TIMEOUT="$${API_WEBSOCKET_GUNICORN_TIMEOUT:-360}"
exec /bin/bash /entrypoint.sh
depends_on:
init_permissions:
condition: service_completed_successfully
@@ -347,20 +344,12 @@ services:
- ssrf_proxy_network
- default
# worker service
# The Celery worker for processing all queues (dataset, workflow, mail, etc.)
worker:
<<: *shared-worker-config
image: langgenius/dify-api:1.18.0
environment:
MODE: worker
SENTRY_DSN: ${API_SENTRY_DSN:-}
SENTRY_TRACES_SAMPLE_RATE: ${API_SENTRY_TRACES_SAMPLE_RATE:-1.0}
SENTRY_PROFILES_SAMPLE_RATE: ${API_SENTRY_PROFILES_SAMPLE_RATE:-1.0}
PLUGIN_MAX_PACKAGE_SIZE: ${PLUGIN_MAX_PACKAGE_SIZE:-52428800}
INNER_API_KEY_FOR_PLUGIN: ${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1}
AGENT_BACKEND_BASE_URL: ${AGENT_BACKEND_BASE_URL:-http://agent_backend:5050}
AGENT_BACKEND_API_TOKEN: ${DIFY_AGENT_API_TOKEN:-dify-agent-run-token-for-dev-only}
depends_on:
init_permissions:
condition: service_completed_successfully
@@ -407,9 +396,6 @@ services:
CELERY_WORKER_POOL: prefork
CELERY_WORKER_CONCURRENCY: ${KNOWLEDGE_FS_UPGRADE_WORKER_AMOUNT:-2}
CELERY_PREFETCH_MULTIPLIER: 1
SENTRY_DSN: ${API_SENTRY_DSN:-}
SENTRY_TRACES_SAMPLE_RATE: ${API_SENTRY_TRACES_SAMPLE_RATE:-1.0}
SENTRY_PROFILES_SAMPLE_RATE: ${API_SENTRY_PROFILES_SAMPLE_RATE:-1.0}
depends_on:
init_permissions:
condition: service_completed_successfully
@@ -467,123 +453,91 @@ services:
image: langgenius/dify-web:1.18.0
restart: always
env_file:
- ./envs/core-services/shared.defaults
- path: ./envs/core-services/web.env
required: false
- path: ./envs/security.env
required: false
- ./.env
environment:
CONSOLE_API_URL: ${CONSOLE_API_URL:-}
SERVER_CONSOLE_API_URL: ${SERVER_CONSOLE_API_URL:-http://api:5001}
APP_API_URL: ${APP_API_URL:-}
AMPLITUDE_API_KEY: ${AMPLITUDE_API_KEY:-}
TURNSTILE_SITE_KEY: ${TURNSTILE_SITE_KEY:-}
NEXT_PUBLIC_COOKIE_DOMAIN: ${NEXT_PUBLIC_COOKIE_DOMAIN:-}
NEXT_PUBLIC_SOCKET_URL: ${NEXT_PUBLIC_SOCKET_URL:-ws://localhost}
SENTRY_DSN: ${WEB_SENTRY_DSN:-}
NEXT_TELEMETRY_DISABLED: ${NEXT_TELEMETRY_DISABLED:-0}
EXPERIMENTAL_ENABLE_VINEXT: ${EXPERIMENTAL_ENABLE_VINEXT:-false}
TEXT_GENERATION_TIMEOUT_MS: ${TEXT_GENERATION_TIMEOUT_MS:-60000}
CSP_WHITELIST: ${CSP_WHITELIST:-}
ALLOW_EMBED: ${ALLOW_EMBED:-false}
ALLOW_UNSAFE_DATA_SCHEME: ${ALLOW_UNSAFE_DATA_SCHEME:-false}
MARKETPLACE_API_URL: ${MARKETPLACE_API_URL:-https://marketplace.dify.ai}
MARKETPLACE_URL: ${MARKETPLACE_URL:-https://marketplace.dify.ai}
TOP_K_MAX_VALUE: ${TOP_K_MAX_VALUE:-10}
INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH: ${INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH:-4000}
LOOP_NODE_MAX_COUNT: ${LOOP_NODE_MAX_COUNT:-100}
MAX_TOOLS_NUM: ${MAX_TOOLS_NUM:-10}
MAX_PARALLEL_LIMIT: ${MAX_PARALLEL_LIMIT:-10}
MAX_ITERATIONS_NUM: ${MAX_ITERATIONS_NUM:-99}
MAX_TREE_DEPTH: ${MAX_TREE_DEPTH:-50}
ENABLE_WEBSITE_JINAREADER: ${ENABLE_WEBSITE_JINAREADER:-true}
ENABLE_WEBSITE_FIRECRAWL: ${ENABLE_WEBSITE_FIRECRAWL:-true}
ENABLE_WEBSITE_WATERCRAWL: ${ENABLE_WEBSITE_WATERCRAWL:-true}
- ./envs/core-services/web.defaults
# The PostgreSQL database.
db_postgres:
env_file:
- path: ./envs/databases/db-postgres.env
required: false
- ./envs/databases/db-postgres.defaults
image: postgres:15-alpine
profiles:
- postgresql
restart: always
environment:
POSTGRES_USER: ${DB_USERNAME:-postgres}
POSTGRES_PASSWORD: ${DB_PASSWORD:-difyai123456}
POSTGRES_DB: ${DB_DATABASE:-dify}
PGDATA: ${PGDATA:-/var/lib/postgresql/data/pgdata}
command: >
postgres -c 'max_connections=${POSTGRES_MAX_CONNECTIONS:-200}'
-c 'shared_buffers=${POSTGRES_SHARED_BUFFERS:-128MB}'
-c 'work_mem=${POSTGRES_WORK_MEM:-4MB}'
-c 'maintenance_work_mem=${POSTGRES_MAINTENANCE_WORK_MEM:-64MB}'
-c 'effective_cache_size=${POSTGRES_EFFECTIVE_CACHE_SIZE:-4096MB}'
-c 'statement_timeout=${POSTGRES_STATEMENT_TIMEOUT:-0}'
-c 'idle_in_transaction_session_timeout=${POSTGRES_IDLE_IN_TRANSACTION_SESSION_TIMEOUT:-0}'
# Expand service-file settings inside the container, preserving the image's initialization.
command:
- sh
- -c
- >-
exec docker-entrypoint.sh postgres
-c "max_connections=$$POSTGRES_MAX_CONNECTIONS"
-c "shared_buffers=$$POSTGRES_SHARED_BUFFERS"
-c "work_mem=$$POSTGRES_WORK_MEM"
-c "maintenance_work_mem=$$POSTGRES_MAINTENANCE_WORK_MEM"
-c "effective_cache_size=$$POSTGRES_EFFECTIVE_CACHE_SIZE"
-c "statement_timeout=$$POSTGRES_STATEMENT_TIMEOUT"
-c "idle_in_transaction_session_timeout=$$POSTGRES_IDLE_IN_TRANSACTION_SESSION_TIMEOUT"
volumes:
- ./volumes/db/data:/var/lib/postgresql/data
healthcheck:
test:
[
"CMD",
"pg_isready",
"-h",
"db_postgres",
"-U",
"${DB_USERNAME:-postgres}",
"-d",
"${DB_DATABASE:-dify}",
]
test: ["CMD-SHELL", 'pg_isready -h db_postgres -U "$$POSTGRES_USER" -d "$$POSTGRES_DB"']
interval: 1s
timeout: 3s
retries: 60
# The mysql database.
db_mysql:
env_file:
- path: ./envs/databases/db-postgres.env
required: false
- path: ./envs/databases/db-mysql.env
required: false
- ./envs/databases/db-mysql.defaults
image: mysql:8.0
profiles:
- mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD:-difyai123456}
MYSQL_DATABASE: ${DB_DATABASE:-dify}
command: >
--max_connections=${MYSQL_MAX_CONNECTIONS:-1000}
--innodb_buffer_pool_size=${MYSQL_INNODB_BUFFER_POOL_SIZE:-512M}
--innodb_log_file_size=${MYSQL_INNODB_LOG_FILE_SIZE:-128M}
--innodb_flush_log_at_trx_commit=${MYSQL_INNODB_FLUSH_LOG_AT_TRX_COMMIT:-2}
command:
- sh
- -c
- >-
exec docker-entrypoint.sh mysqld
"--max_connections=$$MYSQL_MAX_CONNECTIONS"
"--innodb_buffer_pool_size=$$MYSQL_INNODB_BUFFER_POOL_SIZE"
"--innodb_log_file_size=$$MYSQL_INNODB_LOG_FILE_SIZE"
"--innodb_flush_log_at_trx_commit=$$MYSQL_INNODB_FLUSH_LOG_AT_TRX_COMMIT"
volumes:
- ${MYSQL_HOST_VOLUME:-./volumes/mysql/data}:/var/lib/mysql
healthcheck:
test:
[
"CMD",
"mysqladmin",
"ping",
"-u",
"root",
"-p${DB_PASSWORD:-difyai123456}",
]
test: ["CMD-SHELL", 'mysqladmin ping -u root -p"$$MYSQL_ROOT_PASSWORD"']
interval: 1s
timeout: 3s
retries: 30
# The redis cache.
redis:
env_file:
- path: ./envs/databases/redis.env
required: false
- ./envs/databases/redis.defaults
image: redis:6-alpine
restart: always
environment:
REDISCLI_AUTH: ${REDIS_PASSWORD:-difyai123456}
volumes:
# Mount the redis data directory to the container.
- ./volumes/redis/data:/data
# Set the redis password when startup redis server.
command: redis-server --requirepass ${REDIS_PASSWORD:-difyai123456}
command: ["sh", "-c", 'exec docker-entrypoint.sh redis-server --requirepass "$$REDIS_PASSWORD"']
healthcheck:
test:
[
"CMD-SHELL",
"redis-cli -a ${REDIS_PASSWORD:-difyai123456} ping | grep -q PONG",
"redis-cli ping | grep -q PONG",
]
# The DifySandbox
@@ -596,23 +550,12 @@ services:
- path: ./envs/security.env
required: false
- ./.env
environment:
# The DifySandbox configurations
# Make sure you are changing this key for your deployment with a strong key.
# You can generate a strong key using `openssl rand -base64 42`.
API_KEY: ${SANDBOX_API_KEY:-dify-sandbox}
GIN_MODE: ${SANDBOX_GIN_MODE:-release}
WORKER_TIMEOUT: ${SANDBOX_WORKER_TIMEOUT:-15}
ENABLE_NETWORK: ${SANDBOX_ENABLE_NETWORK:-true}
HTTP_PROXY: ${SANDBOX_HTTP_PROXY:-http://ssrf_proxy:3128}
HTTPS_PROXY: ${SANDBOX_HTTPS_PROXY:-http://ssrf_proxy:3128}
SANDBOX_PORT: ${SANDBOX_PORT:-8194}
PIP_MIRROR_URL: ${PIP_MIRROR_URL:-}
- ./envs/core-services/sandbox.defaults
volumes:
- ./volumes/sandbox/dependencies:/dependencies
- ./volumes/sandbox/conf:/conf
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8194/health"]
test: ["CMD-SHELL", 'curl -f "http://localhost:$$SANDBOX_PORT/health"']
networks:
- ssrf_proxy_network
@@ -668,57 +611,13 @@ services:
- path: ./envs/databases/redis.env
required: false
- ./.env
- ./envs/core-services/shared.defaults
- ./envs/core-services/plugin-daemon.defaults
networks:
- ssrf_proxy_network
- default
environment:
DB_DATABASE: ${DB_PLUGIN_DATABASE:-dify_plugin}
DB_SSL_MODE: ${DB_SSL_MODE:-disable}
SERVER_PORT: ${PLUGIN_DAEMON_PORT:-5002}
SERVER_KEY: ${PLUGIN_DAEMON_KEY:-lYkiYYT6owG+71oLerGzA7GXCgOT++6ovaezWAjpCjf+Sjc3ZtU+qUEi}
MAX_PLUGIN_PACKAGE_SIZE: ${PLUGIN_MAX_PACKAGE_SIZE:-52428800}
PPROF_ENABLED: ${PLUGIN_PPROF_ENABLED:-false}
DIFY_INNER_API_URL: ${PLUGIN_DIFY_INNER_API_URL:-http://api:5001}
DIFY_INNER_API_KEY: ${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1}
PLUGIN_REMOTE_INSTALLING_HOST: ${PLUGIN_DEBUGGING_HOST:-0.0.0.0}
PLUGIN_REMOTE_INSTALLING_PORT: ${PLUGIN_DEBUGGING_PORT:-5003}
PLUGIN_WORKING_PATH: ${PLUGIN_WORKING_PATH:-/app/storage/cwd}
FORCE_VERIFYING_SIGNATURE: ${FORCE_VERIFYING_SIGNATURE:-true}
PYTHON_ENV_INIT_TIMEOUT: ${PLUGIN_PYTHON_ENV_INIT_TIMEOUT:-120}
PLUGIN_MAX_EXECUTION_TIMEOUT: ${PLUGIN_MAX_EXECUTION_TIMEOUT:-600}
PLUGIN_STDIO_BUFFER_SIZE: ${PLUGIN_STDIO_BUFFER_SIZE:-1024}
PLUGIN_STDIO_MAX_BUFFER_SIZE: ${PLUGIN_STDIO_MAX_BUFFER_SIZE:-5242880}
PIP_MIRROR_URL: ${PIP_MIRROR_URL:-}
PLUGIN_STORAGE_TYPE: ${PLUGIN_STORAGE_TYPE:-local}
PLUGIN_STORAGE_LOCAL_ROOT: ${PLUGIN_STORAGE_LOCAL_ROOT:-/app/storage}
PLUGIN_INSTALLED_PATH: ${PLUGIN_INSTALLED_PATH:-plugin}
PLUGIN_PACKAGE_CACHE_PATH: ${PLUGIN_PACKAGE_CACHE_PATH:-plugin_packages}
PLUGIN_MEDIA_CACHE_PATH: ${PLUGIN_MEDIA_CACHE_PATH:-assets}
PLUGIN_STORAGE_OSS_BUCKET: ${PLUGIN_STORAGE_OSS_BUCKET:-}
S3_USE_AWS_MANAGED_IAM: ${PLUGIN_S3_USE_AWS_MANAGED_IAM:-false}
S3_USE_AWS: ${PLUGIN_S3_USE_AWS:-false}
S3_ENDPOINT: ${PLUGIN_S3_ENDPOINT:-}
S3_USE_PATH_STYLE: ${PLUGIN_S3_USE_PATH_STYLE:-false}
AWS_ACCESS_KEY: ${PLUGIN_AWS_ACCESS_KEY:-}
AWS_SECRET_KEY: ${PLUGIN_AWS_SECRET_KEY:-}
AWS_REGION: ${PLUGIN_AWS_REGION:-}
AZURE_BLOB_STORAGE_CONNECTION_STRING: ${PLUGIN_AZURE_BLOB_STORAGE_CONNECTION_STRING:-}
AZURE_BLOB_STORAGE_CONTAINER_NAME: ${PLUGIN_AZURE_BLOB_STORAGE_CONTAINER_NAME:-}
TENCENT_COS_SECRET_KEY: ${PLUGIN_TENCENT_COS_SECRET_KEY:-}
TENCENT_COS_SECRET_ID: ${PLUGIN_TENCENT_COS_SECRET_ID:-}
TENCENT_COS_REGION: ${PLUGIN_TENCENT_COS_REGION:-}
ALIYUN_OSS_REGION: ${PLUGIN_ALIYUN_OSS_REGION:-}
ALIYUN_OSS_ENDPOINT: ${PLUGIN_ALIYUN_OSS_ENDPOINT:-}
ALIYUN_OSS_ACCESS_KEY_ID: ${PLUGIN_ALIYUN_OSS_ACCESS_KEY_ID:-}
ALIYUN_OSS_ACCESS_KEY_SECRET: ${PLUGIN_ALIYUN_OSS_ACCESS_KEY_SECRET:-}
ALIYUN_OSS_AUTH_VERSION: ${PLUGIN_ALIYUN_OSS_AUTH_VERSION:-v4}
ALIYUN_OSS_PATH: ${PLUGIN_ALIYUN_OSS_PATH:-}
VOLCENGINE_TOS_ENDPOINT: ${PLUGIN_VOLCENGINE_TOS_ENDPOINT:-}
VOLCENGINE_TOS_ACCESS_KEY: ${PLUGIN_VOLCENGINE_TOS_ACCESS_KEY:-}
VOLCENGINE_TOS_SECRET_KEY: ${PLUGIN_VOLCENGINE_TOS_SECRET_KEY:-}
VOLCENGINE_TOS_REGION: ${PLUGIN_VOLCENGINE_TOS_REGION:-}
SENTRY_ENABLED: ${PLUGIN_SENTRY_ENABLED:-false}
SENTRY_DSN: ${PLUGIN_SENTRY_DSN:-}
ports:
- "${EXPOSE_PLUGIN_DEBUGGING_PORT:-5003}:${PLUGIN_DEBUGGING_PORT:-5003}"
volumes:
@@ -827,29 +726,14 @@ services:
image: langgenius/dify-agent-backend:1.18.0
restart: always
env_file:
- path: ./envs/core-services/dify-agent.env
required: false
- path: ./envs/security.env
required: false
- path: ./envs/databases/redis.env
required: false
- path: ./envs/core-services/dify-agent.env
required: false
- ./.env
environment:
DIFY_AGENT_REDIS_URL: ${DIFY_AGENT_REDIS_URL:-redis://:${REDIS_PASSWORD:-difyai123456}@redis:6379/2}
DIFY_AGENT_PLUGIN_DAEMON_URL: ${DIFY_AGENT_PLUGIN_DAEMON_URL:-${PLUGIN_DAEMON_URL:-http://plugin_daemon:5002}}
DIFY_AGENT_PLUGIN_DAEMON_API_KEY: ${DIFY_AGENT_PLUGIN_DAEMON_API_KEY:-${PLUGIN_DAEMON_KEY:-lYkiYYT6owG+71oLerGzA7GXCgOT++6ovaezWAjpCjf+Sjc3ZtU+qUEi}}
DIFY_AGENT_INNER_API_URL: ${DIFY_AGENT_INNER_API_URL:-${PLUGIN_DIFY_INNER_API_URL:-http://api:5001}}
DIFY_AGENT_INNER_API_KEY: ${DIFY_AGENT_INNER_API_KEY:-${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1}}
DIFY_AGENT_RUNTIME_BACKEND: ${DIFY_AGENT_RUNTIME_BACKEND:-local}
DIFY_AGENT_LOCAL_SANDBOX_ENDPOINT: ${DIFY_AGENT_LOCAL_SANDBOX_ENDPOINT:-${DIFY_AGENT_SHELLCTL_ENTRYPOINT:-http://local_sandbox:5004}}
DIFY_AGENT_LOCAL_SANDBOX_AUTH_TOKEN: ${DIFY_AGENT_LOCAL_SANDBOX_AUTH_TOKEN:-${DIFY_AGENT_SHELLCTL_AUTH_TOKEN:-}}
DIFY_AGENT_STUB_API_BASE_URL: ${DIFY_AGENT_STUB_API_BASE_URL:-http://agent_backend:5050/agent-stub}
DIFY_AGENT_SANDBOX_FILES_BASE_URL: ${DIFY_AGENT_SANDBOX_FILES_BASE_URL:-http://api:5001}
# This is security-sensitive: it derives the JWE encryption key for Agent Stub bearer tokens.
# Replace this development default in production.
# Generate one with: python -c 'import secrets; print(secrets.token_urlsafe(32))'
DIFY_AGENT_SERVER_SECRET_KEY: ${DIFY_AGENT_SERVER_SECRET_KEY:-MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWY}
DIFY_AGENT_API_TOKEN: ${DIFY_AGENT_API_TOKEN:-dify-agent-run-token-for-dev-only}
- ./envs/core-services/dify-agent.defaults
depends_on:
redis:
condition: service_started
@@ -875,11 +759,10 @@ services:
"-c",
"cp /docker-entrypoint-mount.sh /docker-entrypoint.sh && sed -i 's/\r$$//' /docker-entrypoint.sh && chmod +x /docker-entrypoint.sh && /docker-entrypoint.sh",
]
environment:
HTTP_PORT: ${SSRF_HTTP_PORT:-3128}
COREDUMP_DIR: ${SSRF_COREDUMP_DIR:-/var/spool/squid}
SSRF_PROXY_ALLOW_PRIVATE_IPS: ${SSRF_PROXY_ALLOW_PRIVATE_IPS:-}
SSRF_PROXY_ALLOW_PRIVATE_DOMAINS: ${SSRF_PROXY_ALLOW_PRIVATE_DOMAINS:-}
env_file:
- path: ./envs/infrastructure/ssrf-proxy.env
required: false
- ./envs/infrastructure/ssrf-proxy.defaults
networks:
# Needs to reach api and agent_backend as forward-proxy destinations.
- default
@@ -891,6 +774,10 @@ services:
# for more information, please refer to
# https://docs.dify.ai/en/self-host/deploy/troubleshooting/docker-issues#why-is-ssrf-proxy-needed
ssrf_proxy:
env_file:
- path: ./envs/infrastructure/ssrf-proxy.env
required: false
- ./envs/infrastructure/ssrf-proxy.defaults
image: ubuntu/squid:latest
restart: always
volumes:
@@ -903,12 +790,6 @@ services:
"-c",
"cp /docker-entrypoint-mount.sh /docker-entrypoint.sh && sed -i 's/\r$$//' /docker-entrypoint.sh && chmod +x /docker-entrypoint.sh && /docker-entrypoint.sh",
]
environment:
# pls clearly modify the squid env vars to fit your network environment.
HTTP_PORT: ${SSRF_HTTP_PORT:-3128}
COREDUMP_DIR: ${SSRF_COREDUMP_DIR:-/var/spool/squid}
SSRF_PROXY_ALLOW_PRIVATE_IPS: ${SSRF_PROXY_ALLOW_PRIVATE_IPS:-}
SSRF_PROXY_ALLOW_PRIVATE_DOMAINS: ${SSRF_PROXY_ALLOW_PRIVATE_DOMAINS:-}
networks:
- ssrf_proxy_network
- default
@@ -916,6 +797,10 @@ services:
# Certbot service
# use `docker-compose --profile certbot up` to start the certbot service.
certbot:
env_file:
- path: ./envs/infrastructure/certbot.env
required: false
- ./envs/infrastructure/certbot.defaults
image: certbot/certbot
profiles:
- certbot
@@ -926,16 +811,16 @@ services:
- ./volumes/certbot/conf/live:/etc/letsencrypt/live
- ./certbot/update-cert.template.txt:/update-cert.template.txt
- ./certbot/docker-entrypoint.sh:/docker-entrypoint.sh
environment:
- CERTBOT_EMAIL=${CERTBOT_EMAIL:-}
- CERTBOT_DOMAIN=${CERTBOT_DOMAIN:-}
- CERTBOT_OPTIONS=${CERTBOT_OPTIONS:-}
entrypoint: ["/docker-entrypoint.sh"]
command: ["tail", "-f", "/dev/null"]
# The nginx reverse proxy.
# used for reverse proxying the API service and Web service.
nginx:
env_file:
- path: ./envs/infrastructure/nginx.env
required: false
- ./envs/infrastructure/nginx.defaults
image: nginx:latest
restart: always
volumes:
@@ -955,23 +840,8 @@ services:
"cp /docker-entrypoint-mount.sh /docker-entrypoint.sh && sed -i 's/\r$$//' /docker-entrypoint.sh && chmod +x /docker-entrypoint.sh && /docker-entrypoint.sh",
]
environment:
NGINX_SERVER_NAME: ${NGINX_SERVER_NAME:-_}
NGINX_HTTPS_ENABLED: ${NGINX_HTTPS_ENABLED:-false}
NGINX_SSL_PORT: ${NGINX_SSL_PORT:-443}
NGINX_PORT: ${NGINX_PORT:-80}
# You're required to add your own SSL certificates/keys to the `./nginx/ssl` directory
# and modify the env vars below in .env if HTTPS_ENABLED is true.
NGINX_SSL_CERT_FILENAME: ${NGINX_SSL_CERT_FILENAME:-dify.crt}
NGINX_SSL_CERT_KEY_FILENAME: ${NGINX_SSL_CERT_KEY_FILENAME:-dify.key}
NGINX_SSL_PROTOCOLS: ${NGINX_SSL_PROTOCOLS:-TLSv1.2 TLSv1.3}
NGINX_WORKER_PROCESSES: ${NGINX_WORKER_PROCESSES:-auto}
NGINX_CLIENT_MAX_BODY_SIZE: ${NGINX_CLIENT_MAX_BODY_SIZE:-100M}
NGINX_KEEPALIVE_TIMEOUT: ${NGINX_KEEPALIVE_TIMEOUT:-65}
NGINX_PROXY_READ_TIMEOUT: ${NGINX_PROXY_READ_TIMEOUT:-3600s}
NGINX_PROXY_SEND_TIMEOUT: ${NGINX_PROXY_SEND_TIMEOUT:-3600s}
NGINX_ENABLE_CERTBOT_CHALLENGE: ${NGINX_ENABLE_CERTBOT_CHALLENGE:-false}
NGINX_SOCKET_IO_UPSTREAM: ${NGINX_SOCKET_IO_UPSTREAM:-api_websocket:5001}
CERTBOT_DOMAIN: ${CERTBOT_DOMAIN:-}
depends_on:
- api
- web
@@ -981,6 +851,10 @@ services:
# The Weaviate vector store.
weaviate:
env_file:
- path: ./envs/vectorstores/weaviate.env
required: false
- ./envs/vectorstores/weaviate.defaults
image: cr.weaviate.io/semitechnologies/weaviate:1.39.13
profiles:
- weaviate
@@ -988,26 +862,12 @@ services:
volumes:
# Mount the Weaviate data directory to the con tainer.
- ./volumes/weaviate:/var/lib/weaviate
environment:
# The Weaviate configurations
# You can refer to the [Weaviate](https://weaviate.io/developers/weaviate/config-refs/env-vars) documentation for more information.
PERSISTENCE_DATA_PATH: ${WEAVIATE_PERSISTENCE_DATA_PATH:-/var/lib/weaviate}
QUERY_DEFAULTS_LIMIT: ${WEAVIATE_QUERY_DEFAULTS_LIMIT:-25}
AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: ${WEAVIATE_AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED:-false}
DEFAULT_VECTORIZER_MODULE: ${WEAVIATE_DEFAULT_VECTORIZER_MODULE:-none}
CLUSTER_HOSTNAME: ${WEAVIATE_CLUSTER_HOSTNAME:-node1}
AUTHENTICATION_APIKEY_ENABLED: ${WEAVIATE_AUTHENTICATION_APIKEY_ENABLED:-true}
AUTHENTICATION_APIKEY_ALLOWED_KEYS: ${WEAVIATE_AUTHENTICATION_APIKEY_ALLOWED_KEYS:-WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih}
AUTHENTICATION_APIKEY_USERS: ${WEAVIATE_AUTHENTICATION_APIKEY_USERS:-hello@dify.ai}
AUTHORIZATION_ADMINLIST_ENABLED: ${WEAVIATE_AUTHORIZATION_ADMINLIST_ENABLED:-true}
AUTHORIZATION_ADMINLIST_USERS: ${WEAVIATE_AUTHORIZATION_ADMINLIST_USERS:-hello@dify.ai}
DISABLE_TELEMETRY: ${WEAVIATE_DISABLE_TELEMETRY:-false}
ENABLE_TOKENIZER_GSE: ${WEAVIATE_ENABLE_TOKENIZER_GSE:-false}
ENABLE_TOKENIZER_KAGOME_JA: ${WEAVIATE_ENABLE_TOKENIZER_KAGOME_JA:-false}
ENABLE_TOKENIZER_KAGOME_KR: ${WEAVIATE_ENABLE_TOKENIZER_KAGOME_KR:-false}
# OceanBase vector database
oceanbase:
env_file:
- path: ./envs/vectorstores/oceanbase.env
required: false
- ./envs/vectorstores/oceanbase.defaults
image: oceanbase/oceanbase-ce:4.3.5-lts
container_name: oceanbase
profiles:
@@ -1018,10 +878,6 @@ services:
- ./volumes/oceanbase/conf:/root/.obd/cluster
- ./volumes/oceanbase/init.d:/root/boot/init.d
environment:
OB_MEMORY_LIMIT: ${OCEANBASE_MEMORY_LIMIT:-6G}
OB_SYS_PASSWORD: ${OCEANBASE_VECTOR_PASSWORD:-difyai123456}
OB_TENANT_PASSWORD: ${OCEANBASE_VECTOR_PASSWORD:-difyai123456}
OB_CLUSTER_NAME: ${OCEANBASE_CLUSTER_NAME:-difyai}
OB_SERVER_IP: 127.0.0.1
MODE: mini
LANG: C.UTF-8
@@ -1032,7 +888,7 @@ services:
test:
[
"CMD-SHELL",
'obclient -h127.0.0.1 -P2881 -uroot@test -p${OCEANBASE_VECTOR_PASSWORD:-difyai123456} -e "SELECT 1;"',
'obclient -h127.0.0.1 -P2881 -uroot@test -p"$$OB_TENANT_PASSWORD" -e "SELECT 1;"',
]
interval: 10s
retries: 30
@@ -1041,6 +897,10 @@ services:
# seekdb vector database
seekdb:
env_file:
- path: ./envs/vectorstores/seekdb.env
required: false
- ./envs/vectorstores/seekdb.defaults
image: oceanbase/seekdb:latest
container_name: seekdb
profiles:
@@ -1049,8 +909,6 @@ services:
volumes:
- ./volumes/seekdb:/var/lib/oceanbase
environment:
ROOT_PASSWORD: ${OCEANBASE_VECTOR_PASSWORD:-difyai123456}
MEMORY_LIMIT: ${SEEKDB_MEMORY_LIMIT:-2G}
REPORTER: dify-ai-seekdb
ports:
- "${OCEANBASE_VECTOR_PORT:-2881}:2881"
@@ -1058,7 +916,7 @@ services:
test:
[
"CMD-SHELL",
'mysql -h127.0.0.1 -P2881 -uroot -p${OCEANBASE_VECTOR_PASSWORD:-difyai123456} -e "SELECT 1;"',
'mysql -h127.0.0.1 -P2881 -uroot -p"$$ROOT_PASSWORD" -e "SELECT 1;"',
]
interval: 5s
retries: 60
@@ -1067,26 +925,29 @@ services:
# Qdrant vector store.
# (if used, you need to set VECTOR_STORE to qdrant in the api & worker service.)
qdrant:
env_file:
- path: ./envs/vectorstores/qdrant.env
required: false
- ./envs/vectorstores/qdrant.defaults
image: langgenius/qdrant:v1.8.3
profiles:
- qdrant
restart: always
volumes:
- ./volumes/qdrant:/qdrant/storage
environment:
QDRANT_API_KEY: ${QDRANT_API_KEY:-difyai123456}
# The Couchbase vector store.
couchbase-server:
env_file:
- path: ./envs/vectorstores/couchbase.env
required: false
- ./envs/vectorstores/couchbase.defaults
build: ./couchbase-server
profiles:
- couchbase
restart: always
environment:
- CLUSTER_NAME=dify_search
- COUCHBASE_ADMINISTRATOR_USERNAME=${COUCHBASE_USER:-Administrator}
- COUCHBASE_ADMINISTRATOR_PASSWORD=${COUCHBASE_PASSWORD:-password}
- COUCHBASE_BUCKET=${COUCHBASE_BUCKET_NAME:-Embeddings}
- COUCHBASE_BUCKET_RAMSIZE=512
- COUCHBASE_RAM_SIZE=2048
- COUCHBASE_EVENTING_RAM_SIZE=512
@@ -1106,7 +967,7 @@ services:
test:
[
"CMD-SHELL",
"curl -s -f -u Administrator:password http://localhost:8091/pools/default/buckets | grep -q '\\[{' || exit 1",
"curl -s -f -u \"$$COUCHBASE_ADMINISTRATOR_USERNAME:$$COUCHBASE_ADMINISTRATOR_PASSWORD\" http://localhost:8091/pools/default/buckets | grep -q '\\[{' || exit 1",
]
interval: 10s
retries: 10
@@ -1115,21 +976,14 @@ services:
# The pgvector vector database.
pgvector:
env_file:
- path: ./envs/vectorstores/pgvector.env
required: false
- ./envs/vectorstores/pgvector.defaults
image: pgvector/pgvector:pg16
profiles:
- pgvector
restart: always
environment:
PGUSER: ${PGVECTOR_PGUSER:-postgres}
# The password for the default postgres user.
POSTGRES_PASSWORD: ${PGVECTOR_POSTGRES_PASSWORD:-difyai123456}
# The name of the default postgres database.
POSTGRES_DB: ${PGVECTOR_POSTGRES_DB:-dify}
# postgres data directory
PGDATA: ${PGVECTOR_PGDATA:-/var/lib/postgresql/data/pgdata}
# pg_bigm module for full text search
PG_BIGM: ${PGVECTOR_PG_BIGM:-false}
PG_BIGM_VERSION: ${PGVECTOR_PG_BIGM_VERSION:-1.2-20240606}
volumes:
- ./volumes/pgvector/data:/var/lib/postgresql/data
- ./pgvector/docker-entrypoint.sh:/docker-entrypoint.sh
@@ -1166,18 +1020,14 @@ services:
# pgvecto-rs vector store
pgvecto-rs:
env_file:
- path: ./envs/vectorstores/pgvecto-rs.env
required: false
- ./envs/vectorstores/pgvecto-rs.defaults
image: tensorchord/pgvecto-rs:pg16-v0.3.0
profiles:
- pgvecto-rs
restart: always
environment:
PGUSER: ${PGVECTOR_PGUSER:-postgres}
# The password for the default postgres user.
POSTGRES_PASSWORD: ${PGVECTOR_POSTGRES_PASSWORD:-difyai123456}
# The name of the default postgres database.
POSTGRES_DB: ${PGVECTOR_POSTGRES_DB:-dify}
# postgres data directory
PGDATA: ${PGVECTOR_PGDATA:-/var/lib/postgresql/data/pgdata}
volumes:
- ./volumes/pgvecto_rs/data:/var/lib/postgresql/data
healthcheck:
@@ -1188,19 +1038,23 @@ services:
# Chroma vector database
chroma:
env_file:
- path: ./envs/vectorstores/chroma.env
required: false
- ./envs/vectorstores/chroma.defaults
image: ghcr.io/chroma-core/chroma:0.5.20
profiles:
- chroma
restart: always
volumes:
- ./volumes/chroma:/chroma/chroma
environment:
CHROMA_SERVER_AUTHN_CREDENTIALS: ${CHROMA_SERVER_AUTHN_CREDENTIALS:-difyai123456}
CHROMA_SERVER_AUTHN_PROVIDER: ${CHROMA_SERVER_AUTHN_PROVIDER:-chromadb.auth.token_authn.TokenAuthenticationServerProvider}
IS_PERSISTENT: ${CHROMA_IS_PERSISTENT:-TRUE}
# InterSystems IRIS vector database
iris:
env_file:
- path: ./envs/vectorstores/iris.env
required: false
- ./envs/vectorstores/iris.defaults
image: containers.intersystems.com/intersystems/iris-community:2025.3
profiles:
- iris
@@ -1217,11 +1071,14 @@ services:
entrypoint: ["/custom-entrypoint.sh"]
tty: true
environment:
TZ: ${IRIS_TIMEZONE:-UTC}
ISC_DATA_DIRECTORY: /durable/iris
# Oracle vector database
oracle:
env_file:
- path: ./envs/vectorstores/oracle.env
required: false
- ./envs/vectorstores/oracle.defaults
image: container-registry.oracle.com/database/free:latest
profiles:
- oracle
@@ -1231,21 +1088,19 @@ services:
type: volume
target: /opt/oracle/oradata
- ./startupscripts:/opt/oracle/scripts/startup
environment:
ORACLE_PWD: ${ORACLE_PWD:-Dify123456}
ORACLE_CHARACTERSET: ${ORACLE_CHARACTERSET:-AL32UTF8}
# Milvus vector database services
etcd:
env_file:
- path: ./envs/vectorstores/milvus.env
required: false
- path: ./envs/infrastructure/etcd.env
required: false
- ./envs/infrastructure/etcd.defaults
container_name: milvus-etcd
image: quay.io/coreos/etcd:v3.5.5
profiles:
- milvus
environment:
ETCD_AUTO_COMPACTION_MODE: ${ETCD_AUTO_COMPACTION_MODE:-revision}
ETCD_AUTO_COMPACTION_RETENTION: ${ETCD_AUTO_COMPACTION_RETENTION:-1000}
ETCD_QUOTA_BACKEND_BYTES: ${ETCD_QUOTA_BACKEND_BYTES:-4294967296}
ETCD_SNAPSHOT_COUNT: ${ETCD_SNAPSHOT_COUNT:-50000}
volumes:
- ./volumes/milvus/etcd:/etcd
command: etcd -advertise-client-urls=http://127.0.0.1:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcd
@@ -1258,13 +1113,16 @@ services:
- milvus
minio:
env_file:
- path: ./envs/vectorstores/milvus.env
required: false
- path: ./envs/infrastructure/minio.env
required: false
- ./envs/infrastructure/minio.defaults
container_name: milvus-minio
image: minio/minio:RELEASE.2023-03-20T20-16-18Z
profiles:
- milvus
environment:
MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY:-minioadmin}
MINIO_SECRET_KEY: ${MINIO_SECRET_KEY:-minioadmin}
volumes:
- ./volumes/milvus/minio:/minio_data
command: minio server /minio_data --console-address ":9001"
@@ -1277,15 +1135,17 @@ services:
- milvus
milvus-standalone:
env_file:
- path: ./envs/vectorstores/milvus.env
required: false
- path: ./envs/infrastructure/milvus-standalone.env
required: false
- ./envs/infrastructure/milvus-standalone.defaults
container_name: milvus-standalone
image: milvusdb/milvus:v2.6.3
profiles:
- milvus
command: ["milvus", "run", "standalone"]
environment:
ETCD_ENDPOINTS: ${ETCD_ENDPOINTS:-etcd:2379}
MINIO_ADDRESS: ${MINIO_ADDRESS:-minio:9000}
common.security.authorizationEnabled: ${MILVUS_AUTHORIZATION_ENABLED:-true}
volumes:
- ./volumes/milvus/milvus:/var/lib/milvus
healthcheck:
@@ -1305,15 +1165,14 @@ services:
# Opensearch vector database
opensearch:
env_file:
- path: ./envs/vectorstores/opensearch.env
required: false
- ./envs/vectorstores/opensearch.defaults
container_name: opensearch
image: opensearchproject/opensearch:latest
profiles:
- opensearch
environment:
discovery.type: ${OPENSEARCH_DISCOVERY_TYPE:-single-node}
bootstrap.memory_lock: ${OPENSEARCH_BOOTSTRAP_MEMORY_LOCK:-true}
OPENSEARCH_JAVA_OPTS: -Xms${OPENSEARCH_JAVA_OPTS_MIN:-512m} -Xmx${OPENSEARCH_JAVA_OPTS_MAX:-1024m}
OPENSEARCH_INITIAL_ADMIN_PASSWORD: ${OPENSEARCH_INITIAL_ADMIN_PASSWORD:-Qazwsxedc!@#123}
ulimits:
memlock:
soft: ${OPENSEARCH_MEMLOCK_SOFT:--1}
@@ -1342,16 +1201,17 @@ services:
# opengauss vector database.
opengauss:
env_file:
- path: ./envs/vectorstores/opengauss.env
required: false
- ./envs/vectorstores/opengauss.defaults
image: opengauss/opengauss:7.0.0-RC1
profiles:
- opengauss
privileged: true
restart: always
environment:
GS_USERNAME: ${OPENGAUSS_USER:-postgres}
GS_PASSWORD: ${OPENGAUSS_PASSWORD:-Dify@123}
GS_PORT: ${OPENGAUSS_PORT:-6600}
GS_DB: ${OPENGAUSS_DATABASE:-dify}
volumes:
- ./volumes/opengauss/data:/var/lib/opengauss/data
healthcheck:
@@ -1392,18 +1252,17 @@ services:
# https://www.elastic.co/guide/en/elasticsearch/reference/current/settings.html
# https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html#docker-prod-prerequisites
elasticsearch:
env_file:
- path: ./envs/vectorstores/elasticsearch.env
required: false
- ./envs/vectorstores/elasticsearch.defaults
image: docker.elastic.co/elasticsearch/elasticsearch:8.14.3
container_name: elasticsearch
profiles:
- elasticsearch
- elasticsearch-ja
restart: always
volumes:
- ./elasticsearch/docker-entrypoint.sh:/docker-entrypoint-mount.sh
- dify_es01_data:/usr/share/elasticsearch/data
environment:
ELASTIC_PASSWORD: ${ELASTICSEARCH_PASSWORD:-elastic}
VECTOR_STORE: ${VECTOR_STORE:-}
cluster.name: dify-es-cluster
node.name: dify-es0
discovery.type: single-node
@@ -1411,6 +1270,11 @@ services:
xpack.security.enabled: "true"
xpack.security.enrollment.enabled: "false"
xpack.security.http.ssl.enabled: "false"
# Backend selection also controls the Japanese analyzer installed by the entrypoint.
VECTOR_STORE: ${VECTOR_STORE:-}
volumes:
- ./elasticsearch/docker-entrypoint.sh:/docker-entrypoint-mount.sh
- dify_es01_data:/usr/share/elasticsearch/data
ports:
- ${ELASTICSEARCH_PORT:-9200}:9200
deploy:
-2
View File
@@ -26,8 +26,6 @@ services:
dockerfile: dify-agent/Dockerfile
environment:
DIFY_AGENT_RUNTIME_BACKEND: e2b
DIFY_AGENT_E2B_API_KEY: ${DIFY_AGENT_E2B_API_KEY:-${E2B_API_KEY:-${E2B_API_TOKEN:-}}}
DIFY_AGENT_E2B_TEMPLATE: ${DIFY_AGENT_E2B_TEMPLATE:-difys-default-team/dify-agent-local-sandbox}
ports:
- "${EXPOSE_AGENT_BACKEND_PORT:-15050}:5050"
+171 -307
View File
@@ -5,13 +5,10 @@
# ==================================================================
# Shared configuration using YAML anchors and env_file
x-shared-api-worker-config: &shared-api-worker-config
x-shared-api-config: &shared-api-config
env_file:
- ./envs/core-services/shared.defaults
- path: ./envs/core-services/shared.env
required: false
- path: ./envs/core-services/api.env
required: false
- path: ./envs/security.env
required: false
- path: ./envs/databases/db-postgres.env
@@ -66,7 +63,11 @@ x-shared-api-worker-config: &shared-api-worker-config
required: false
- path: ./envs/infrastructure/milvus-standalone.env
required: false
- path: ./envs/core-services/api.env
required: false
- ./.env
- ./envs/core-services/shared.defaults
- ./envs/core-services/api.defaults
networks:
- ssrf_proxy_network
- default
@@ -74,11 +75,8 @@ x-shared-api-worker-config: &shared-api-worker-config
x-shared-worker-config: &shared-worker-config
env_file:
- ./envs/core-services/shared.defaults
- path: ./envs/core-services/shared.env
required: false
- path: ./envs/core-services/worker.env
required: false
- path: ./envs/security.env
required: false
- path: ./envs/databases/db-postgres.env
@@ -133,7 +131,11 @@ x-shared-worker-config: &shared-worker-config
required: false
- path: ./envs/infrastructure/milvus-standalone.env
required: false
- path: ./envs/core-services/worker.env
required: false
- ./.env
- ./envs/core-services/shared.defaults
- ./envs/core-services/worker.defaults
networks:
- ssrf_proxy_network
- default
@@ -149,11 +151,8 @@ x-knowledge-fs-celery-worker: &knowledge-fs-celery-worker
# Match the two-hour default task deadline plus shutdown margin for long document jobs.
stop_grace_period: 125m
env_file:
- ./envs/core-services/shared.defaults
- path: ./envs/core-services/shared.env
required: false
- path: ./envs/core-services/worker.env
required: false
- path: ./envs/security.env
required: false
- path: ./envs/databases/db-postgres.env
@@ -166,7 +165,11 @@ x-knowledge-fs-celery-worker: &knowledge-fs-celery-worker
required: false
- path: ./envs/core-services/knowledge-fs-worker.env
required: false
- path: ./envs/core-services/worker.env
required: false
- ./.env
- ./envs/core-services/shared.defaults
- ./envs/core-services/worker.defaults
environment: &knowledge-fs-celery-environment
MODE: worker
MIGRATION_ENABLED: "false"
@@ -187,11 +190,8 @@ x-knowledge-fs-celery-worker: &knowledge-fs-celery-worker
x-shared-worker-beat-config: &shared-worker-beat-config
env_file:
- ./envs/core-services/shared.defaults
- path: ./envs/core-services/shared.env
required: false
- path: ./envs/core-services/worker-beat.env
required: false
- path: ./envs/security.env
required: false
- path: ./envs/databases/db-postgres.env
@@ -246,7 +246,11 @@ x-shared-worker-beat-config: &shared-worker-beat-config
required: false
- path: ./envs/infrastructure/milvus-standalone.env
required: false
- path: ./envs/core-services/worker-beat.env
required: false
- ./.env
- ./envs/core-services/shared.defaults
- ./envs/core-services/worker-beat.defaults
networks:
- ssrf_proxy_network
- default
@@ -274,22 +278,10 @@ services:
# API service
api:
<<: *shared-api-worker-config
<<: *shared-api-config
image: langgenius/dify-api:1.18.0
environment:
MODE: api
# The bundled Nginx supplies a verified client IP; keep direct API callers trusted.
RESPECT_XFORWARD_HEADERS_ENABLED: ${RESPECT_XFORWARD_HEADERS_ENABLED:-true}
SENTRY_DSN: ${API_SENTRY_DSN:-}
SENTRY_TRACES_SAMPLE_RATE: ${API_SENTRY_TRACES_SAMPLE_RATE:-1.0}
SENTRY_PROFILES_SAMPLE_RATE: ${API_SENTRY_PROFILES_SAMPLE_RATE:-1.0}
PLUGIN_REMOTE_INSTALL_HOST: ${EXPOSE_PLUGIN_DEBUGGING_HOST:-localhost}
PLUGIN_REMOTE_INSTALL_PORT: ${EXPOSE_PLUGIN_DEBUGGING_PORT:-5003}
PLUGIN_MAX_PACKAGE_SIZE: ${PLUGIN_MAX_PACKAGE_SIZE:-52428800}
PLUGIN_DAEMON_TIMEOUT: ${PLUGIN_DAEMON_TIMEOUT:-600.0}
INNER_API_KEY_FOR_PLUGIN: ${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1}
AGENT_BACKEND_BASE_URL: ${AGENT_BACKEND_BASE_URL:-http://agent_backend:5050}
AGENT_BACKEND_API_TOKEN: ${DIFY_AGENT_API_TOKEN:-dify-agent-run-token-for-dev-only}
depends_on:
init_permissions:
condition: service_completed_successfully
@@ -324,17 +316,22 @@ services:
# WebSocket service for workflow collaboration.
api_websocket:
<<: *shared-api-worker-config
<<: *shared-api-config
image: langgenius/dify-api:1.18.0
profiles:
- collaboration
environment:
MODE: api
RESPECT_XFORWARD_HEADERS_ENABLED: ${RESPECT_XFORWARD_HEADERS_ENABLED:-true}
SERVER_WORKER_AMOUNT: ${API_WEBSOCKET_WORKER_AMOUNT:-1}
SERVER_WORKER_CLASS: ${API_WEBSOCKET_WORKER_CLASS:-geventwebsocket.gunicorn.workers.GeventWebSocketWorker}
SERVER_WORKER_CONNECTIONS: ${API_WEBSOCKET_WORKER_CONNECTIONS:-1000}
GUNICORN_TIMEOUT: ${API_WEBSOCKET_GUNICORN_TIMEOUT:-360}
# Resolve websocket settings after loading the shared/API service files.
entrypoint:
- /bin/bash
- -c
- |
export SERVER_WORKER_AMOUNT="$${API_WEBSOCKET_WORKER_AMOUNT:-1}"
export SERVER_WORKER_CLASS="$${API_WEBSOCKET_WORKER_CLASS:-geventwebsocket.gunicorn.workers.GeventWebSocketWorker}"
export SERVER_WORKER_CONNECTIONS="$${API_WEBSOCKET_WORKER_CONNECTIONS:-1000}"
export GUNICORN_TIMEOUT="$${API_WEBSOCKET_GUNICORN_TIMEOUT:-360}"
exec /bin/bash /entrypoint.sh
depends_on:
init_permissions:
condition: service_completed_successfully
@@ -353,20 +350,12 @@ services:
- ssrf_proxy_network
- default
# worker service
# The Celery worker for processing all queues (dataset, workflow, mail, etc.)
worker:
<<: *shared-worker-config
image: langgenius/dify-api:1.18.0
environment:
MODE: worker
SENTRY_DSN: ${API_SENTRY_DSN:-}
SENTRY_TRACES_SAMPLE_RATE: ${API_SENTRY_TRACES_SAMPLE_RATE:-1.0}
SENTRY_PROFILES_SAMPLE_RATE: ${API_SENTRY_PROFILES_SAMPLE_RATE:-1.0}
PLUGIN_MAX_PACKAGE_SIZE: ${PLUGIN_MAX_PACKAGE_SIZE:-52428800}
INNER_API_KEY_FOR_PLUGIN: ${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1}
AGENT_BACKEND_BASE_URL: ${AGENT_BACKEND_BASE_URL:-http://agent_backend:5050}
AGENT_BACKEND_API_TOKEN: ${DIFY_AGENT_API_TOKEN:-dify-agent-run-token-for-dev-only}
depends_on:
init_permissions:
condition: service_completed_successfully
@@ -413,9 +402,6 @@ services:
CELERY_WORKER_POOL: prefork
CELERY_WORKER_CONCURRENCY: ${KNOWLEDGE_FS_UPGRADE_WORKER_AMOUNT:-2}
CELERY_PREFETCH_MULTIPLIER: 1
SENTRY_DSN: ${API_SENTRY_DSN:-}
SENTRY_TRACES_SAMPLE_RATE: ${API_SENTRY_TRACES_SAMPLE_RATE:-1.0}
SENTRY_PROFILES_SAMPLE_RATE: ${API_SENTRY_PROFILES_SAMPLE_RATE:-1.0}
depends_on:
init_permissions:
condition: service_completed_successfully
@@ -473,123 +459,91 @@ services:
image: langgenius/dify-web:1.18.0
restart: always
env_file:
- ./envs/core-services/shared.defaults
- path: ./envs/core-services/web.env
required: false
- path: ./envs/security.env
required: false
- ./.env
environment:
CONSOLE_API_URL: ${CONSOLE_API_URL:-}
SERVER_CONSOLE_API_URL: ${SERVER_CONSOLE_API_URL:-http://api:5001}
APP_API_URL: ${APP_API_URL:-}
AMPLITUDE_API_KEY: ${AMPLITUDE_API_KEY:-}
TURNSTILE_SITE_KEY: ${TURNSTILE_SITE_KEY:-}
NEXT_PUBLIC_COOKIE_DOMAIN: ${NEXT_PUBLIC_COOKIE_DOMAIN:-}
NEXT_PUBLIC_SOCKET_URL: ${NEXT_PUBLIC_SOCKET_URL:-ws://localhost}
SENTRY_DSN: ${WEB_SENTRY_DSN:-}
NEXT_TELEMETRY_DISABLED: ${NEXT_TELEMETRY_DISABLED:-0}
EXPERIMENTAL_ENABLE_VINEXT: ${EXPERIMENTAL_ENABLE_VINEXT:-false}
TEXT_GENERATION_TIMEOUT_MS: ${TEXT_GENERATION_TIMEOUT_MS:-60000}
CSP_WHITELIST: ${CSP_WHITELIST:-}
ALLOW_EMBED: ${ALLOW_EMBED:-false}
ALLOW_UNSAFE_DATA_SCHEME: ${ALLOW_UNSAFE_DATA_SCHEME:-false}
MARKETPLACE_API_URL: ${MARKETPLACE_API_URL:-https://marketplace.dify.ai}
MARKETPLACE_URL: ${MARKETPLACE_URL:-https://marketplace.dify.ai}
TOP_K_MAX_VALUE: ${TOP_K_MAX_VALUE:-10}
INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH: ${INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH:-4000}
LOOP_NODE_MAX_COUNT: ${LOOP_NODE_MAX_COUNT:-100}
MAX_TOOLS_NUM: ${MAX_TOOLS_NUM:-10}
MAX_PARALLEL_LIMIT: ${MAX_PARALLEL_LIMIT:-10}
MAX_ITERATIONS_NUM: ${MAX_ITERATIONS_NUM:-99}
MAX_TREE_DEPTH: ${MAX_TREE_DEPTH:-50}
ENABLE_WEBSITE_JINAREADER: ${ENABLE_WEBSITE_JINAREADER:-true}
ENABLE_WEBSITE_FIRECRAWL: ${ENABLE_WEBSITE_FIRECRAWL:-true}
ENABLE_WEBSITE_WATERCRAWL: ${ENABLE_WEBSITE_WATERCRAWL:-true}
- ./envs/core-services/web.defaults
# The PostgreSQL database.
db_postgres:
env_file:
- path: ./envs/databases/db-postgres.env
required: false
- ./envs/databases/db-postgres.defaults
image: postgres:15-alpine
profiles:
- postgresql
restart: always
environment:
POSTGRES_USER: ${DB_USERNAME:-postgres}
POSTGRES_PASSWORD: ${DB_PASSWORD:-difyai123456}
POSTGRES_DB: ${DB_DATABASE:-dify}
PGDATA: ${PGDATA:-/var/lib/postgresql/data/pgdata}
command: >
postgres -c 'max_connections=${POSTGRES_MAX_CONNECTIONS:-200}'
-c 'shared_buffers=${POSTGRES_SHARED_BUFFERS:-128MB}'
-c 'work_mem=${POSTGRES_WORK_MEM:-4MB}'
-c 'maintenance_work_mem=${POSTGRES_MAINTENANCE_WORK_MEM:-64MB}'
-c 'effective_cache_size=${POSTGRES_EFFECTIVE_CACHE_SIZE:-4096MB}'
-c 'statement_timeout=${POSTGRES_STATEMENT_TIMEOUT:-0}'
-c 'idle_in_transaction_session_timeout=${POSTGRES_IDLE_IN_TRANSACTION_SESSION_TIMEOUT:-0}'
# Expand service-file settings inside the container, preserving the image's initialization.
command:
- sh
- -c
- >-
exec docker-entrypoint.sh postgres
-c "max_connections=$$POSTGRES_MAX_CONNECTIONS"
-c "shared_buffers=$$POSTGRES_SHARED_BUFFERS"
-c "work_mem=$$POSTGRES_WORK_MEM"
-c "maintenance_work_mem=$$POSTGRES_MAINTENANCE_WORK_MEM"
-c "effective_cache_size=$$POSTGRES_EFFECTIVE_CACHE_SIZE"
-c "statement_timeout=$$POSTGRES_STATEMENT_TIMEOUT"
-c "idle_in_transaction_session_timeout=$$POSTGRES_IDLE_IN_TRANSACTION_SESSION_TIMEOUT"
volumes:
- ./volumes/db/data:/var/lib/postgresql/data
healthcheck:
test:
[
"CMD",
"pg_isready",
"-h",
"db_postgres",
"-U",
"${DB_USERNAME:-postgres}",
"-d",
"${DB_DATABASE:-dify}",
]
test: ["CMD-SHELL", 'pg_isready -h db_postgres -U "$$POSTGRES_USER" -d "$$POSTGRES_DB"']
interval: 1s
timeout: 3s
retries: 60
# The mysql database.
db_mysql:
env_file:
- path: ./envs/databases/db-postgres.env
required: false
- path: ./envs/databases/db-mysql.env
required: false
- ./envs/databases/db-mysql.defaults
image: mysql:8.0
profiles:
- mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD:-difyai123456}
MYSQL_DATABASE: ${DB_DATABASE:-dify}
command: >
--max_connections=${MYSQL_MAX_CONNECTIONS:-1000}
--innodb_buffer_pool_size=${MYSQL_INNODB_BUFFER_POOL_SIZE:-512M}
--innodb_log_file_size=${MYSQL_INNODB_LOG_FILE_SIZE:-128M}
--innodb_flush_log_at_trx_commit=${MYSQL_INNODB_FLUSH_LOG_AT_TRX_COMMIT:-2}
command:
- sh
- -c
- >-
exec docker-entrypoint.sh mysqld
"--max_connections=$$MYSQL_MAX_CONNECTIONS"
"--innodb_buffer_pool_size=$$MYSQL_INNODB_BUFFER_POOL_SIZE"
"--innodb_log_file_size=$$MYSQL_INNODB_LOG_FILE_SIZE"
"--innodb_flush_log_at_trx_commit=$$MYSQL_INNODB_FLUSH_LOG_AT_TRX_COMMIT"
volumes:
- ${MYSQL_HOST_VOLUME:-./volumes/mysql/data}:/var/lib/mysql
healthcheck:
test:
[
"CMD",
"mysqladmin",
"ping",
"-u",
"root",
"-p${DB_PASSWORD:-difyai123456}",
]
test: ["CMD-SHELL", 'mysqladmin ping -u root -p"$$MYSQL_ROOT_PASSWORD"']
interval: 1s
timeout: 3s
retries: 30
# The redis cache.
redis:
env_file:
- path: ./envs/databases/redis.env
required: false
- ./envs/databases/redis.defaults
image: redis:6-alpine
restart: always
environment:
REDISCLI_AUTH: ${REDIS_PASSWORD:-difyai123456}
volumes:
# Mount the redis data directory to the container.
- ./volumes/redis/data:/data
# Set the redis password when startup redis server.
command: redis-server --requirepass ${REDIS_PASSWORD:-difyai123456}
command: ["sh", "-c", 'exec docker-entrypoint.sh redis-server --requirepass "$$REDIS_PASSWORD"']
healthcheck:
test:
[
"CMD-SHELL",
"redis-cli -a ${REDIS_PASSWORD:-difyai123456} ping | grep -q PONG",
"redis-cli ping | grep -q PONG",
]
# The DifySandbox
@@ -602,23 +556,12 @@ services:
- path: ./envs/security.env
required: false
- ./.env
environment:
# The DifySandbox configurations
# Make sure you are changing this key for your deployment with a strong key.
# You can generate a strong key using `openssl rand -base64 42`.
API_KEY: ${SANDBOX_API_KEY:-dify-sandbox}
GIN_MODE: ${SANDBOX_GIN_MODE:-release}
WORKER_TIMEOUT: ${SANDBOX_WORKER_TIMEOUT:-15}
ENABLE_NETWORK: ${SANDBOX_ENABLE_NETWORK:-true}
HTTP_PROXY: ${SANDBOX_HTTP_PROXY:-http://ssrf_proxy:3128}
HTTPS_PROXY: ${SANDBOX_HTTPS_PROXY:-http://ssrf_proxy:3128}
SANDBOX_PORT: ${SANDBOX_PORT:-8194}
PIP_MIRROR_URL: ${PIP_MIRROR_URL:-}
- ./envs/core-services/sandbox.defaults
volumes:
- ./volumes/sandbox/dependencies:/dependencies
- ./volumes/sandbox/conf:/conf
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8194/health"]
test: ["CMD-SHELL", 'curl -f "http://localhost:$$SANDBOX_PORT/health"']
networks:
- ssrf_proxy_network
@@ -674,57 +617,13 @@ services:
- path: ./envs/databases/redis.env
required: false
- ./.env
- ./envs/core-services/shared.defaults
- ./envs/core-services/plugin-daemon.defaults
networks:
- ssrf_proxy_network
- default
environment:
DB_DATABASE: ${DB_PLUGIN_DATABASE:-dify_plugin}
DB_SSL_MODE: ${DB_SSL_MODE:-disable}
SERVER_PORT: ${PLUGIN_DAEMON_PORT:-5002}
SERVER_KEY: ${PLUGIN_DAEMON_KEY:-lYkiYYT6owG+71oLerGzA7GXCgOT++6ovaezWAjpCjf+Sjc3ZtU+qUEi}
MAX_PLUGIN_PACKAGE_SIZE: ${PLUGIN_MAX_PACKAGE_SIZE:-52428800}
PPROF_ENABLED: ${PLUGIN_PPROF_ENABLED:-false}
DIFY_INNER_API_URL: ${PLUGIN_DIFY_INNER_API_URL:-http://api:5001}
DIFY_INNER_API_KEY: ${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1}
PLUGIN_REMOTE_INSTALLING_HOST: ${PLUGIN_DEBUGGING_HOST:-0.0.0.0}
PLUGIN_REMOTE_INSTALLING_PORT: ${PLUGIN_DEBUGGING_PORT:-5003}
PLUGIN_WORKING_PATH: ${PLUGIN_WORKING_PATH:-/app/storage/cwd}
FORCE_VERIFYING_SIGNATURE: ${FORCE_VERIFYING_SIGNATURE:-true}
PYTHON_ENV_INIT_TIMEOUT: ${PLUGIN_PYTHON_ENV_INIT_TIMEOUT:-120}
PLUGIN_MAX_EXECUTION_TIMEOUT: ${PLUGIN_MAX_EXECUTION_TIMEOUT:-600}
PLUGIN_STDIO_BUFFER_SIZE: ${PLUGIN_STDIO_BUFFER_SIZE:-1024}
PLUGIN_STDIO_MAX_BUFFER_SIZE: ${PLUGIN_STDIO_MAX_BUFFER_SIZE:-5242880}
PIP_MIRROR_URL: ${PIP_MIRROR_URL:-}
PLUGIN_STORAGE_TYPE: ${PLUGIN_STORAGE_TYPE:-local}
PLUGIN_STORAGE_LOCAL_ROOT: ${PLUGIN_STORAGE_LOCAL_ROOT:-/app/storage}
PLUGIN_INSTALLED_PATH: ${PLUGIN_INSTALLED_PATH:-plugin}
PLUGIN_PACKAGE_CACHE_PATH: ${PLUGIN_PACKAGE_CACHE_PATH:-plugin_packages}
PLUGIN_MEDIA_CACHE_PATH: ${PLUGIN_MEDIA_CACHE_PATH:-assets}
PLUGIN_STORAGE_OSS_BUCKET: ${PLUGIN_STORAGE_OSS_BUCKET:-}
S3_USE_AWS_MANAGED_IAM: ${PLUGIN_S3_USE_AWS_MANAGED_IAM:-false}
S3_USE_AWS: ${PLUGIN_S3_USE_AWS:-false}
S3_ENDPOINT: ${PLUGIN_S3_ENDPOINT:-}
S3_USE_PATH_STYLE: ${PLUGIN_S3_USE_PATH_STYLE:-false}
AWS_ACCESS_KEY: ${PLUGIN_AWS_ACCESS_KEY:-}
AWS_SECRET_KEY: ${PLUGIN_AWS_SECRET_KEY:-}
AWS_REGION: ${PLUGIN_AWS_REGION:-}
AZURE_BLOB_STORAGE_CONNECTION_STRING: ${PLUGIN_AZURE_BLOB_STORAGE_CONNECTION_STRING:-}
AZURE_BLOB_STORAGE_CONTAINER_NAME: ${PLUGIN_AZURE_BLOB_STORAGE_CONTAINER_NAME:-}
TENCENT_COS_SECRET_KEY: ${PLUGIN_TENCENT_COS_SECRET_KEY:-}
TENCENT_COS_SECRET_ID: ${PLUGIN_TENCENT_COS_SECRET_ID:-}
TENCENT_COS_REGION: ${PLUGIN_TENCENT_COS_REGION:-}
ALIYUN_OSS_REGION: ${PLUGIN_ALIYUN_OSS_REGION:-}
ALIYUN_OSS_ENDPOINT: ${PLUGIN_ALIYUN_OSS_ENDPOINT:-}
ALIYUN_OSS_ACCESS_KEY_ID: ${PLUGIN_ALIYUN_OSS_ACCESS_KEY_ID:-}
ALIYUN_OSS_ACCESS_KEY_SECRET: ${PLUGIN_ALIYUN_OSS_ACCESS_KEY_SECRET:-}
ALIYUN_OSS_AUTH_VERSION: ${PLUGIN_ALIYUN_OSS_AUTH_VERSION:-v4}
ALIYUN_OSS_PATH: ${PLUGIN_ALIYUN_OSS_PATH:-}
VOLCENGINE_TOS_ENDPOINT: ${PLUGIN_VOLCENGINE_TOS_ENDPOINT:-}
VOLCENGINE_TOS_ACCESS_KEY: ${PLUGIN_VOLCENGINE_TOS_ACCESS_KEY:-}
VOLCENGINE_TOS_SECRET_KEY: ${PLUGIN_VOLCENGINE_TOS_SECRET_KEY:-}
VOLCENGINE_TOS_REGION: ${PLUGIN_VOLCENGINE_TOS_REGION:-}
SENTRY_ENABLED: ${PLUGIN_SENTRY_ENABLED:-false}
SENTRY_DSN: ${PLUGIN_SENTRY_DSN:-}
ports:
- "${EXPOSE_PLUGIN_DEBUGGING_PORT:-5003}:${PLUGIN_DEBUGGING_PORT:-5003}"
volumes:
@@ -833,29 +732,14 @@ services:
image: langgenius/dify-agent-backend:1.18.0
restart: always
env_file:
- path: ./envs/core-services/dify-agent.env
required: false
- path: ./envs/security.env
required: false
- path: ./envs/databases/redis.env
required: false
- path: ./envs/core-services/dify-agent.env
required: false
- ./.env
environment:
DIFY_AGENT_REDIS_URL: ${DIFY_AGENT_REDIS_URL:-redis://:${REDIS_PASSWORD:-difyai123456}@redis:6379/2}
DIFY_AGENT_PLUGIN_DAEMON_URL: ${DIFY_AGENT_PLUGIN_DAEMON_URL:-${PLUGIN_DAEMON_URL:-http://plugin_daemon:5002}}
DIFY_AGENT_PLUGIN_DAEMON_API_KEY: ${DIFY_AGENT_PLUGIN_DAEMON_API_KEY:-${PLUGIN_DAEMON_KEY:-lYkiYYT6owG+71oLerGzA7GXCgOT++6ovaezWAjpCjf+Sjc3ZtU+qUEi}}
DIFY_AGENT_INNER_API_URL: ${DIFY_AGENT_INNER_API_URL:-${PLUGIN_DIFY_INNER_API_URL:-http://api:5001}}
DIFY_AGENT_INNER_API_KEY: ${DIFY_AGENT_INNER_API_KEY:-${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1}}
DIFY_AGENT_RUNTIME_BACKEND: ${DIFY_AGENT_RUNTIME_BACKEND:-local}
DIFY_AGENT_LOCAL_SANDBOX_ENDPOINT: ${DIFY_AGENT_LOCAL_SANDBOX_ENDPOINT:-${DIFY_AGENT_SHELLCTL_ENTRYPOINT:-http://local_sandbox:5004}}
DIFY_AGENT_LOCAL_SANDBOX_AUTH_TOKEN: ${DIFY_AGENT_LOCAL_SANDBOX_AUTH_TOKEN:-${DIFY_AGENT_SHELLCTL_AUTH_TOKEN:-}}
DIFY_AGENT_STUB_API_BASE_URL: ${DIFY_AGENT_STUB_API_BASE_URL:-http://agent_backend:5050/agent-stub}
DIFY_AGENT_SANDBOX_FILES_BASE_URL: ${DIFY_AGENT_SANDBOX_FILES_BASE_URL:-http://api:5001}
# This is security-sensitive: it derives the JWE encryption key for Agent Stub bearer tokens.
# Replace this development default in production.
# Generate one with: python -c 'import secrets; print(secrets.token_urlsafe(32))'
DIFY_AGENT_SERVER_SECRET_KEY: ${DIFY_AGENT_SERVER_SECRET_KEY:-MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWY}
DIFY_AGENT_API_TOKEN: ${DIFY_AGENT_API_TOKEN:-dify-agent-run-token-for-dev-only}
- ./envs/core-services/dify-agent.defaults
depends_on:
redis:
condition: service_started
@@ -881,11 +765,10 @@ services:
"-c",
"cp /docker-entrypoint-mount.sh /docker-entrypoint.sh && sed -i 's/\r$$//' /docker-entrypoint.sh && chmod +x /docker-entrypoint.sh && /docker-entrypoint.sh",
]
environment:
HTTP_PORT: ${SSRF_HTTP_PORT:-3128}
COREDUMP_DIR: ${SSRF_COREDUMP_DIR:-/var/spool/squid}
SSRF_PROXY_ALLOW_PRIVATE_IPS: ${SSRF_PROXY_ALLOW_PRIVATE_IPS:-}
SSRF_PROXY_ALLOW_PRIVATE_DOMAINS: ${SSRF_PROXY_ALLOW_PRIVATE_DOMAINS:-}
env_file:
- path: ./envs/infrastructure/ssrf-proxy.env
required: false
- ./envs/infrastructure/ssrf-proxy.defaults
networks:
# Needs to reach api and agent_backend as forward-proxy destinations.
- default
@@ -897,6 +780,10 @@ services:
# for more information, please refer to
# https://docs.dify.ai/en/self-host/deploy/troubleshooting/docker-issues#why-is-ssrf-proxy-needed
ssrf_proxy:
env_file:
- path: ./envs/infrastructure/ssrf-proxy.env
required: false
- ./envs/infrastructure/ssrf-proxy.defaults
image: ubuntu/squid:latest
restart: always
volumes:
@@ -909,12 +796,6 @@ services:
"-c",
"cp /docker-entrypoint-mount.sh /docker-entrypoint.sh && sed -i 's/\r$$//' /docker-entrypoint.sh && chmod +x /docker-entrypoint.sh && /docker-entrypoint.sh",
]
environment:
# pls clearly modify the squid env vars to fit your network environment.
HTTP_PORT: ${SSRF_HTTP_PORT:-3128}
COREDUMP_DIR: ${SSRF_COREDUMP_DIR:-/var/spool/squid}
SSRF_PROXY_ALLOW_PRIVATE_IPS: ${SSRF_PROXY_ALLOW_PRIVATE_IPS:-}
SSRF_PROXY_ALLOW_PRIVATE_DOMAINS: ${SSRF_PROXY_ALLOW_PRIVATE_DOMAINS:-}
networks:
- ssrf_proxy_network
- default
@@ -922,6 +803,10 @@ services:
# Certbot service
# use `docker-compose --profile certbot up` to start the certbot service.
certbot:
env_file:
- path: ./envs/infrastructure/certbot.env
required: false
- ./envs/infrastructure/certbot.defaults
image: certbot/certbot
profiles:
- certbot
@@ -932,16 +817,16 @@ services:
- ./volumes/certbot/conf/live:/etc/letsencrypt/live
- ./certbot/update-cert.template.txt:/update-cert.template.txt
- ./certbot/docker-entrypoint.sh:/docker-entrypoint.sh
environment:
- CERTBOT_EMAIL=${CERTBOT_EMAIL:-}
- CERTBOT_DOMAIN=${CERTBOT_DOMAIN:-}
- CERTBOT_OPTIONS=${CERTBOT_OPTIONS:-}
entrypoint: ["/docker-entrypoint.sh"]
command: ["tail", "-f", "/dev/null"]
# The nginx reverse proxy.
# used for reverse proxying the API service and Web service.
nginx:
env_file:
- path: ./envs/infrastructure/nginx.env
required: false
- ./envs/infrastructure/nginx.defaults
image: nginx:latest
restart: always
volumes:
@@ -961,23 +846,8 @@ services:
"cp /docker-entrypoint-mount.sh /docker-entrypoint.sh && sed -i 's/\r$$//' /docker-entrypoint.sh && chmod +x /docker-entrypoint.sh && /docker-entrypoint.sh",
]
environment:
NGINX_SERVER_NAME: ${NGINX_SERVER_NAME:-_}
NGINX_HTTPS_ENABLED: ${NGINX_HTTPS_ENABLED:-false}
NGINX_SSL_PORT: ${NGINX_SSL_PORT:-443}
NGINX_PORT: ${NGINX_PORT:-80}
# You're required to add your own SSL certificates/keys to the `./nginx/ssl` directory
# and modify the env vars below in .env if HTTPS_ENABLED is true.
NGINX_SSL_CERT_FILENAME: ${NGINX_SSL_CERT_FILENAME:-dify.crt}
NGINX_SSL_CERT_KEY_FILENAME: ${NGINX_SSL_CERT_KEY_FILENAME:-dify.key}
NGINX_SSL_PROTOCOLS: ${NGINX_SSL_PROTOCOLS:-TLSv1.2 TLSv1.3}
NGINX_WORKER_PROCESSES: ${NGINX_WORKER_PROCESSES:-auto}
NGINX_CLIENT_MAX_BODY_SIZE: ${NGINX_CLIENT_MAX_BODY_SIZE:-100M}
NGINX_KEEPALIVE_TIMEOUT: ${NGINX_KEEPALIVE_TIMEOUT:-65}
NGINX_PROXY_READ_TIMEOUT: ${NGINX_PROXY_READ_TIMEOUT:-3600s}
NGINX_PROXY_SEND_TIMEOUT: ${NGINX_PROXY_SEND_TIMEOUT:-3600s}
NGINX_ENABLE_CERTBOT_CHALLENGE: ${NGINX_ENABLE_CERTBOT_CHALLENGE:-false}
NGINX_SOCKET_IO_UPSTREAM: ${NGINX_SOCKET_IO_UPSTREAM:-api_websocket:5001}
CERTBOT_DOMAIN: ${CERTBOT_DOMAIN:-}
depends_on:
- api
- web
@@ -987,6 +857,10 @@ services:
# The Weaviate vector store.
weaviate:
env_file:
- path: ./envs/vectorstores/weaviate.env
required: false
- ./envs/vectorstores/weaviate.defaults
image: cr.weaviate.io/semitechnologies/weaviate:1.39.13
profiles:
- weaviate
@@ -994,26 +868,12 @@ services:
volumes:
# Mount the Weaviate data directory to the con tainer.
- ./volumes/weaviate:/var/lib/weaviate
environment:
# The Weaviate configurations
# You can refer to the [Weaviate](https://weaviate.io/developers/weaviate/config-refs/env-vars) documentation for more information.
PERSISTENCE_DATA_PATH: ${WEAVIATE_PERSISTENCE_DATA_PATH:-/var/lib/weaviate}
QUERY_DEFAULTS_LIMIT: ${WEAVIATE_QUERY_DEFAULTS_LIMIT:-25}
AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: ${WEAVIATE_AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED:-false}
DEFAULT_VECTORIZER_MODULE: ${WEAVIATE_DEFAULT_VECTORIZER_MODULE:-none}
CLUSTER_HOSTNAME: ${WEAVIATE_CLUSTER_HOSTNAME:-node1}
AUTHENTICATION_APIKEY_ENABLED: ${WEAVIATE_AUTHENTICATION_APIKEY_ENABLED:-true}
AUTHENTICATION_APIKEY_ALLOWED_KEYS: ${WEAVIATE_AUTHENTICATION_APIKEY_ALLOWED_KEYS:-WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih}
AUTHENTICATION_APIKEY_USERS: ${WEAVIATE_AUTHENTICATION_APIKEY_USERS:-hello@dify.ai}
AUTHORIZATION_ADMINLIST_ENABLED: ${WEAVIATE_AUTHORIZATION_ADMINLIST_ENABLED:-true}
AUTHORIZATION_ADMINLIST_USERS: ${WEAVIATE_AUTHORIZATION_ADMINLIST_USERS:-hello@dify.ai}
DISABLE_TELEMETRY: ${WEAVIATE_DISABLE_TELEMETRY:-false}
ENABLE_TOKENIZER_GSE: ${WEAVIATE_ENABLE_TOKENIZER_GSE:-false}
ENABLE_TOKENIZER_KAGOME_JA: ${WEAVIATE_ENABLE_TOKENIZER_KAGOME_JA:-false}
ENABLE_TOKENIZER_KAGOME_KR: ${WEAVIATE_ENABLE_TOKENIZER_KAGOME_KR:-false}
# OceanBase vector database
oceanbase:
env_file:
- path: ./envs/vectorstores/oceanbase.env
required: false
- ./envs/vectorstores/oceanbase.defaults
image: oceanbase/oceanbase-ce:4.3.5-lts
container_name: oceanbase
profiles:
@@ -1024,10 +884,6 @@ services:
- ./volumes/oceanbase/conf:/root/.obd/cluster
- ./volumes/oceanbase/init.d:/root/boot/init.d
environment:
OB_MEMORY_LIMIT: ${OCEANBASE_MEMORY_LIMIT:-6G}
OB_SYS_PASSWORD: ${OCEANBASE_VECTOR_PASSWORD:-difyai123456}
OB_TENANT_PASSWORD: ${OCEANBASE_VECTOR_PASSWORD:-difyai123456}
OB_CLUSTER_NAME: ${OCEANBASE_CLUSTER_NAME:-difyai}
OB_SERVER_IP: 127.0.0.1
MODE: mini
LANG: C.UTF-8
@@ -1038,7 +894,7 @@ services:
test:
[
"CMD-SHELL",
'obclient -h127.0.0.1 -P2881 -uroot@test -p${OCEANBASE_VECTOR_PASSWORD:-difyai123456} -e "SELECT 1;"',
'obclient -h127.0.0.1 -P2881 -uroot@test -p"$$OB_TENANT_PASSWORD" -e "SELECT 1;"',
]
interval: 10s
retries: 30
@@ -1047,6 +903,10 @@ services:
# seekdb vector database
seekdb:
env_file:
- path: ./envs/vectorstores/seekdb.env
required: false
- ./envs/vectorstores/seekdb.defaults
image: oceanbase/seekdb:latest
container_name: seekdb
profiles:
@@ -1055,8 +915,6 @@ services:
volumes:
- ./volumes/seekdb:/var/lib/oceanbase
environment:
ROOT_PASSWORD: ${OCEANBASE_VECTOR_PASSWORD:-difyai123456}
MEMORY_LIMIT: ${SEEKDB_MEMORY_LIMIT:-2G}
REPORTER: dify-ai-seekdb
ports:
- "${OCEANBASE_VECTOR_PORT:-2881}:2881"
@@ -1064,7 +922,7 @@ services:
test:
[
"CMD-SHELL",
'mysql -h127.0.0.1 -P2881 -uroot -p${OCEANBASE_VECTOR_PASSWORD:-difyai123456} -e "SELECT 1;"',
'mysql -h127.0.0.1 -P2881 -uroot -p"$$ROOT_PASSWORD" -e "SELECT 1;"',
]
interval: 5s
retries: 60
@@ -1073,26 +931,29 @@ services:
# Qdrant vector store.
# (if used, you need to set VECTOR_STORE to qdrant in the api & worker service.)
qdrant:
env_file:
- path: ./envs/vectorstores/qdrant.env
required: false
- ./envs/vectorstores/qdrant.defaults
image: langgenius/qdrant:v1.8.3
profiles:
- qdrant
restart: always
volumes:
- ./volumes/qdrant:/qdrant/storage
environment:
QDRANT_API_KEY: ${QDRANT_API_KEY:-difyai123456}
# The Couchbase vector store.
couchbase-server:
env_file:
- path: ./envs/vectorstores/couchbase.env
required: false
- ./envs/vectorstores/couchbase.defaults
build: ./couchbase-server
profiles:
- couchbase
restart: always
environment:
- CLUSTER_NAME=dify_search
- COUCHBASE_ADMINISTRATOR_USERNAME=${COUCHBASE_USER:-Administrator}
- COUCHBASE_ADMINISTRATOR_PASSWORD=${COUCHBASE_PASSWORD:-password}
- COUCHBASE_BUCKET=${COUCHBASE_BUCKET_NAME:-Embeddings}
- COUCHBASE_BUCKET_RAMSIZE=512
- COUCHBASE_RAM_SIZE=2048
- COUCHBASE_EVENTING_RAM_SIZE=512
@@ -1112,7 +973,7 @@ services:
test:
[
"CMD-SHELL",
"curl -s -f -u Administrator:password http://localhost:8091/pools/default/buckets | grep -q '\\[{' || exit 1",
"curl -s -f -u \"$$COUCHBASE_ADMINISTRATOR_USERNAME:$$COUCHBASE_ADMINISTRATOR_PASSWORD\" http://localhost:8091/pools/default/buckets | grep -q '\\[{' || exit 1",
]
interval: 10s
retries: 10
@@ -1121,21 +982,14 @@ services:
# The pgvector vector database.
pgvector:
env_file:
- path: ./envs/vectorstores/pgvector.env
required: false
- ./envs/vectorstores/pgvector.defaults
image: pgvector/pgvector:pg16
profiles:
- pgvector
restart: always
environment:
PGUSER: ${PGVECTOR_PGUSER:-postgres}
# The password for the default postgres user.
POSTGRES_PASSWORD: ${PGVECTOR_POSTGRES_PASSWORD:-difyai123456}
# The name of the default postgres database.
POSTGRES_DB: ${PGVECTOR_POSTGRES_DB:-dify}
# postgres data directory
PGDATA: ${PGVECTOR_PGDATA:-/var/lib/postgresql/data/pgdata}
# pg_bigm module for full text search
PG_BIGM: ${PGVECTOR_PG_BIGM:-false}
PG_BIGM_VERSION: ${PGVECTOR_PG_BIGM_VERSION:-1.2-20240606}
volumes:
- ./volumes/pgvector/data:/var/lib/postgresql/data
- ./pgvector/docker-entrypoint.sh:/docker-entrypoint.sh
@@ -1172,18 +1026,14 @@ services:
# pgvecto-rs vector store
pgvecto-rs:
env_file:
- path: ./envs/vectorstores/pgvecto-rs.env
required: false
- ./envs/vectorstores/pgvecto-rs.defaults
image: tensorchord/pgvecto-rs:pg16-v0.3.0
profiles:
- pgvecto-rs
restart: always
environment:
PGUSER: ${PGVECTOR_PGUSER:-postgres}
# The password for the default postgres user.
POSTGRES_PASSWORD: ${PGVECTOR_POSTGRES_PASSWORD:-difyai123456}
# The name of the default postgres database.
POSTGRES_DB: ${PGVECTOR_POSTGRES_DB:-dify}
# postgres data directory
PGDATA: ${PGVECTOR_PGDATA:-/var/lib/postgresql/data/pgdata}
volumes:
- ./volumes/pgvecto_rs/data:/var/lib/postgresql/data
healthcheck:
@@ -1194,19 +1044,23 @@ services:
# Chroma vector database
chroma:
env_file:
- path: ./envs/vectorstores/chroma.env
required: false
- ./envs/vectorstores/chroma.defaults
image: ghcr.io/chroma-core/chroma:0.5.20
profiles:
- chroma
restart: always
volumes:
- ./volumes/chroma:/chroma/chroma
environment:
CHROMA_SERVER_AUTHN_CREDENTIALS: ${CHROMA_SERVER_AUTHN_CREDENTIALS:-difyai123456}
CHROMA_SERVER_AUTHN_PROVIDER: ${CHROMA_SERVER_AUTHN_PROVIDER:-chromadb.auth.token_authn.TokenAuthenticationServerProvider}
IS_PERSISTENT: ${CHROMA_IS_PERSISTENT:-TRUE}
# InterSystems IRIS vector database
iris:
env_file:
- path: ./envs/vectorstores/iris.env
required: false
- ./envs/vectorstores/iris.defaults
image: containers.intersystems.com/intersystems/iris-community:2025.3
profiles:
- iris
@@ -1223,11 +1077,14 @@ services:
entrypoint: ["/custom-entrypoint.sh"]
tty: true
environment:
TZ: ${IRIS_TIMEZONE:-UTC}
ISC_DATA_DIRECTORY: /durable/iris
# Oracle vector database
oracle:
env_file:
- path: ./envs/vectorstores/oracle.env
required: false
- ./envs/vectorstores/oracle.defaults
image: container-registry.oracle.com/database/free:latest
profiles:
- oracle
@@ -1237,21 +1094,19 @@ services:
type: volume
target: /opt/oracle/oradata
- ./startupscripts:/opt/oracle/scripts/startup
environment:
ORACLE_PWD: ${ORACLE_PWD:-Dify123456}
ORACLE_CHARACTERSET: ${ORACLE_CHARACTERSET:-AL32UTF8}
# Milvus vector database services
etcd:
env_file:
- path: ./envs/vectorstores/milvus.env
required: false
- path: ./envs/infrastructure/etcd.env
required: false
- ./envs/infrastructure/etcd.defaults
container_name: milvus-etcd
image: quay.io/coreos/etcd:v3.5.5
profiles:
- milvus
environment:
ETCD_AUTO_COMPACTION_MODE: ${ETCD_AUTO_COMPACTION_MODE:-revision}
ETCD_AUTO_COMPACTION_RETENTION: ${ETCD_AUTO_COMPACTION_RETENTION:-1000}
ETCD_QUOTA_BACKEND_BYTES: ${ETCD_QUOTA_BACKEND_BYTES:-4294967296}
ETCD_SNAPSHOT_COUNT: ${ETCD_SNAPSHOT_COUNT:-50000}
volumes:
- ./volumes/milvus/etcd:/etcd
command: etcd -advertise-client-urls=http://127.0.0.1:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcd
@@ -1264,13 +1119,16 @@ services:
- milvus
minio:
env_file:
- path: ./envs/vectorstores/milvus.env
required: false
- path: ./envs/infrastructure/minio.env
required: false
- ./envs/infrastructure/minio.defaults
container_name: milvus-minio
image: minio/minio:RELEASE.2023-03-20T20-16-18Z
profiles:
- milvus
environment:
MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY:-minioadmin}
MINIO_SECRET_KEY: ${MINIO_SECRET_KEY:-minioadmin}
volumes:
- ./volumes/milvus/minio:/minio_data
command: minio server /minio_data --console-address ":9001"
@@ -1283,15 +1141,17 @@ services:
- milvus
milvus-standalone:
env_file:
- path: ./envs/vectorstores/milvus.env
required: false
- path: ./envs/infrastructure/milvus-standalone.env
required: false
- ./envs/infrastructure/milvus-standalone.defaults
container_name: milvus-standalone
image: milvusdb/milvus:v2.6.3
profiles:
- milvus
command: ["milvus", "run", "standalone"]
environment:
ETCD_ENDPOINTS: ${ETCD_ENDPOINTS:-etcd:2379}
MINIO_ADDRESS: ${MINIO_ADDRESS:-minio:9000}
common.security.authorizationEnabled: ${MILVUS_AUTHORIZATION_ENABLED:-true}
volumes:
- ./volumes/milvus/milvus:/var/lib/milvus
healthcheck:
@@ -1311,15 +1171,14 @@ services:
# Opensearch vector database
opensearch:
env_file:
- path: ./envs/vectorstores/opensearch.env
required: false
- ./envs/vectorstores/opensearch.defaults
container_name: opensearch
image: opensearchproject/opensearch:latest
profiles:
- opensearch
environment:
discovery.type: ${OPENSEARCH_DISCOVERY_TYPE:-single-node}
bootstrap.memory_lock: ${OPENSEARCH_BOOTSTRAP_MEMORY_LOCK:-true}
OPENSEARCH_JAVA_OPTS: -Xms${OPENSEARCH_JAVA_OPTS_MIN:-512m} -Xmx${OPENSEARCH_JAVA_OPTS_MAX:-1024m}
OPENSEARCH_INITIAL_ADMIN_PASSWORD: ${OPENSEARCH_INITIAL_ADMIN_PASSWORD:-Qazwsxedc!@#123}
ulimits:
memlock:
soft: ${OPENSEARCH_MEMLOCK_SOFT:--1}
@@ -1348,16 +1207,17 @@ services:
# opengauss vector database.
opengauss:
env_file:
- path: ./envs/vectorstores/opengauss.env
required: false
- ./envs/vectorstores/opengauss.defaults
image: opengauss/opengauss:7.0.0-RC1
profiles:
- opengauss
privileged: true
restart: always
environment:
GS_USERNAME: ${OPENGAUSS_USER:-postgres}
GS_PASSWORD: ${OPENGAUSS_PASSWORD:-Dify@123}
GS_PORT: ${OPENGAUSS_PORT:-6600}
GS_DB: ${OPENGAUSS_DATABASE:-dify}
volumes:
- ./volumes/opengauss/data:/var/lib/opengauss/data
healthcheck:
@@ -1398,18 +1258,17 @@ services:
# https://www.elastic.co/guide/en/elasticsearch/reference/current/settings.html
# https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html#docker-prod-prerequisites
elasticsearch:
env_file:
- path: ./envs/vectorstores/elasticsearch.env
required: false
- ./envs/vectorstores/elasticsearch.defaults
image: docker.elastic.co/elasticsearch/elasticsearch:8.14.3
container_name: elasticsearch
profiles:
- elasticsearch
- elasticsearch-ja
restart: always
volumes:
- ./elasticsearch/docker-entrypoint.sh:/docker-entrypoint-mount.sh
- dify_es01_data:/usr/share/elasticsearch/data
environment:
ELASTIC_PASSWORD: ${ELASTICSEARCH_PASSWORD:-elastic}
VECTOR_STORE: ${VECTOR_STORE:-}
cluster.name: dify-es-cluster
node.name: dify-es0
discovery.type: single-node
@@ -1417,6 +1276,11 @@ services:
xpack.security.enabled: "true"
xpack.security.enrollment.enabled: "false"
xpack.security.http.ssl.enabled: "false"
# Backend selection also controls the Japanese analyzer installed by the entrypoint.
VECTOR_STORE: ${VECTOR_STORE:-}
volumes:
- ./elasticsearch/docker-entrypoint.sh:/docker-entrypoint-mount.sh
- dify_es01_data:/usr/share/elasticsearch/data
ports:
- ${ELASTICSEARCH_PORT:-9200}:9200
deploy:
+101
View File
@@ -0,0 +1,101 @@
# Defaults for api. Copy this file to api.env to customize it.
# Edit the settings below in the copy; docker/.env takes precedence.
# Optional application settings are commented to retain their application defaults.
# MODE is selected by the Compose service.
# Optional SaaS network-policy control plane and current-IP preview trust.
# NETWORK_ACCESS_API_URL=
# Comma-separated proxy CIDRs; empty disables Cloud IP previews. The edge
# must sanitize/append XFF and the trust boundary must match Gateway.
# NETWORK_ACCESS_TRUSTED_PROXY_CIDRS=
API_SENTRY_DSN=${API_SENTRY_DSN:-}
API_SENTRY_TRACES_SAMPLE_RATE=${API_SENTRY_TRACES_SAMPLE_RATE:-1.0}
API_SENTRY_PROFILES_SAMPLE_RATE=${API_SENTRY_PROFILES_SAMPLE_RATE:-1.0}
API_WEBSOCKET_WORKER_AMOUNT=${API_WEBSOCKET_WORKER_AMOUNT:-1}
API_WEBSOCKET_WORKER_CLASS=${API_WEBSOCKET_WORKER_CLASS:-geventwebsocket.gunicorn.workers.GeventWebSocketWorker}
API_WEBSOCKET_WORKER_CONNECTIONS=${API_WEBSOCKET_WORKER_CONNECTIONS:-1000}
API_WEBSOCKET_GUNICORN_TIMEOUT=${API_WEBSOCKET_GUNICORN_TIMEOUT:-360}
# Set EXPOSE_PLUGIN_DEBUGGING_HOST and EXPOSE_PLUGIN_DEBUGGING_PORT in docker/.env
# so the API connection and Compose port mapping use the same address.
PLUGIN_MAX_PACKAGE_SIZE=${PLUGIN_MAX_PACKAGE_SIZE:-52428800}
PLUGIN_DAEMON_TIMEOUT=${PLUGIN_DAEMON_TIMEOUT:-600.0}
# Set PLUGIN_DIFY_INNER_API_KEY in docker/.env; all callers must share the API's inner credential.
# Optional server-side secret mixed into account password hashes. Leave empty to keep the legacy hashing.
# WARNING: setting, changing, or removing this value changes every password hash and existing passwords
# will stop working. Do not change it casually.
# Use a high-entropy random value, e.g. generate one with `openssl rand -base64 32`.
# Keep it in this file rather than docker/.env, which is also loaded by plugin_daemon and agent_backend.
# PASSWORD_PEPPER=
# Client deadline for converting a Binding file to a ToolFile through the Agent backend.
# AGENT_BACKEND_BINDING_FILE_DOWNLOAD_TIMEOUT_SECONDS=240
# KNOWLEDGE_FS_ENABLED=${KNOWLEDGE_FS_ENABLED:-false}
# Explicitly bypass the Community edition gate for development deployments.
# KNOWLEDGE_FS_COMMUNITY_DEV_ENABLED=${KNOWLEDGE_FS_COMMUNITY_DEV_ENABLED:-false}
# Production deployments require HTTPS; plain HTTP is limited to non-production or loopback.
# KNOWLEDGE_FS_BASE_URL=
# Optional trusted direct origin for KnowledgeFS internal requests.
# KNOWLEDGE_FS_DIRECT_ORIGIN=
# KNOWLEDGE_FS_LIFECYCLE_WORKER_ENABLED=false
# KNOWLEDGE_FS_INTEGRATED_PROVISION_READY=false
# KNOWLEDGE_FS_LEGACY_ACL_FREEZE_READY=false
# KNOWLEDGE_FS_LIFECYCLE_POLL_INTERVAL_SECONDS=15
# KNOWLEDGE_FS_LIFECYCLE_LEASE_SECONDS=60
# KNOWLEDGE_FS_LIFECYCLE_BATCH_SIZE=25
# KNOWLEDGE_FS_CAPABILITY_V2_ENABLED=false
# KNOWLEDGE_FS_CAPABILITY_V2_SIGNING_KID=
# KNOWLEDGE_FS_CAPABILITY_V2_PRIVATE_KEY_PEM=
# KNOWLEDGE_FS_CAPABILITY_V2_PREVIOUS_PUBLIC_JWKS=
# KNOWLEDGE_FS_CAPABILITY_V2_ISSUER=dify-control-plane
# KNOWLEDGE_FS_CAPABILITY_V2_AUDIENCE=knowledge-fs
# KNOWLEDGE_FS_CAPABILITY_V2_MAX_TTL_SECONDS=60
# KNOWLEDGE_FS_JWKS_CACHE_MAX_AGE_SECONDS=300
# KNOWLEDGE_FS_PRODUCT_MAX_RESPONSE_BYTES=4194304
# KNOWLEDGE_FS_TIMEOUT_SECONDS=10
# Retrieval tests have a 60-second KnowledgeFS execution budget and need transport headroom.
# KNOWLEDGE_FS_RETRIEVAL_TEST_TIMEOUT_SECONDS=75
# Lifetime in days of difyctl (OAuth device flow) tokens, 1-365; out-of-range values are clamped
# OAUTH_TTL_DAYS=14
# Cloudflare Turnstile server-side verification for Dify Cloud sign-in
# TURNSTILE_SECRET_KEY=
# TURNSTILE_ALLOWED_HOSTNAMES=
# TURNSTILE_EMAIL_CODE_VERIFY_REQUIRED=false
DIFY_AGENT_API_TOKEN=${DIFY_AGENT_API_TOKEN:-dify-agent-run-token-for-dev-only}
AGENT_BACKEND_BASE_URL=${AGENT_BACKEND_BASE_URL:-http://agent_backend:5050}
# The bundled Nginx supplies a verified client IP; keep direct API callers trusted.
# Compose enables forwarded headers here; the bare application default is false.
# Override in api.env or docker/.env. See docker/README.md#client-ip-and-trusted-proxies
# before exposing the API directly.
RESPECT_XFORWARD_HEADERS_ENABLED=${RESPECT_XFORWARD_HEADERS_ENABLED:-true}
CELERY_BROKER_URL=${CELERY_BROKER_URL:-redis://:${REDIS_PASSWORD:-difyai123456}@${REDIS_HOST:-redis}:${REDIS_PORT:-6379}/1}
# API server and OpenAPI settings
# DIFY_BIND_ADDRESS=0.0.0.0
# DIFY_PORT=5001
# SERVER_WORKER_AMOUNT=1
# SERVER_WORKER_CONNECTIONS=10
# Must stay above the idle connection reuse window of the HTTP clients that
# pool connections to this server. Node's global fetch (undici) keeps a socket
# idle for 4s before dropping it, so a shorter value here lets the server close
# a connection the client still considers reusable, which surfaces as
# intermittent ECONNRESET on server-side rendering. 0 disables keep-alive.
# GUNICORN_KEEP_ALIVE=10
# WEBSOCKET_MAX_HTTP_BUFFER_SIZE=10485760
# SWAGGER_UI_ENABLED=false
# SWAGGER_UI_PATH=/swagger-ui.html
# OPENAPI_ENABLED=false
# OPENAPI_CORS_ALLOW_ORIGINS=
# OPENAPI_KNOWN_CLIENT_IDS=difyctl
# OPENAPI_RATE_LIMIT_PER_TOKEN=60
# DEVICE_FLOW_APPROVE_RATE_LIMIT_PER_HOUR=10
# ENABLE_OAUTH_BEARER=false
# Container variable mappings; keep these expressions unchanged in the copy.
AGENT_BACKEND_API_TOKEN=${DIFY_AGENT_API_TOKEN:-dify-agent-run-token-for-dev-only}
INNER_API_KEY_FOR_PLUGIN=${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1}
PLUGIN_REMOTE_INSTALL_HOST=${EXPOSE_PLUGIN_DEBUGGING_HOST:-localhost}
PLUGIN_REMOTE_INSTALL_PORT=${EXPOSE_PLUGIN_DEBUGGING_PORT:-5003}
SENTRY_DSN=${API_SENTRY_DSN:-}
SENTRY_PROFILES_SAMPLE_RATE=${API_SENTRY_PROFILES_SAMPLE_RATE:-1.0}
SENTRY_TRACES_SAMPLE_RATE=${API_SENTRY_TRACES_SAMPLE_RATE:-1.0}
-59
View File
@@ -1,59 +0,0 @@
# ------------------------------
# Api Configuration
# ------------------------------
MODE=api
# Optional SaaS network-policy control plane and current-IP preview trust.
NETWORK_ACCESS_API_URL=
# Comma-separated proxy CIDRs; empty disables Cloud IP previews. The edge
# must sanitize/append XFF and the trust boundary must match Gateway.
NETWORK_ACCESS_TRUSTED_PROXY_CIDRS=
SENTRY_DSN=
SENTRY_TRACES_SAMPLE_RATE=1.0
SENTRY_PROFILES_SAMPLE_RATE=1.0
PLUGIN_REMOTE_INSTALL_HOST=localhost
PLUGIN_REMOTE_INSTALL_PORT=5003
PLUGIN_MAX_PACKAGE_SIZE=52428800
PLUGIN_DAEMON_TIMEOUT=600.0
INNER_API_KEY_FOR_PLUGIN=QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1
# Optional server-side secret mixed into account password hashes. Leave empty to keep the legacy hashing.
# WARNING: setting, changing, or removing this value changes every password hash and existing passwords
# will stop working. Do not change it casually.
# Use a high-entropy random value, e.g. generate one with `openssl rand -base64 32`.
# Keep it in this file rather than docker/.env, which is also loaded by plugin_daemon and agent_backend.
PASSWORD_PEPPER=
# Client deadline for converting a Binding file to a ToolFile through the Agent backend.
AGENT_BACKEND_BINDING_FILE_DOWNLOAD_TIMEOUT_SECONDS=240
KNOWLEDGE_FS_ENABLED=${KNOWLEDGE_FS_ENABLED:-false}
# Explicitly bypass the Community edition gate for development deployments.
KNOWLEDGE_FS_COMMUNITY_DEV_ENABLED=${KNOWLEDGE_FS_COMMUNITY_DEV_ENABLED:-false}
# Production deployments require HTTPS; plain HTTP is limited to non-production or loopback.
KNOWLEDGE_FS_BASE_URL=
# Optional trusted direct origin for KnowledgeFS internal requests.
KNOWLEDGE_FS_DIRECT_ORIGIN=
KNOWLEDGE_FS_LIFECYCLE_WORKER_ENABLED=false
KNOWLEDGE_FS_INTEGRATED_PROVISION_READY=false
KNOWLEDGE_FS_LEGACY_ACL_FREEZE_READY=false
KNOWLEDGE_FS_LIFECYCLE_POLL_INTERVAL_SECONDS=15
KNOWLEDGE_FS_LIFECYCLE_LEASE_SECONDS=60
KNOWLEDGE_FS_LIFECYCLE_BATCH_SIZE=25
KNOWLEDGE_FS_CAPABILITY_V2_ENABLED=false
KNOWLEDGE_FS_CAPABILITY_V2_SIGNING_KID=
KNOWLEDGE_FS_CAPABILITY_V2_PRIVATE_KEY_PEM=
KNOWLEDGE_FS_CAPABILITY_V2_PREVIOUS_PUBLIC_JWKS=
KNOWLEDGE_FS_CAPABILITY_V2_ISSUER=dify-control-plane
KNOWLEDGE_FS_CAPABILITY_V2_AUDIENCE=knowledge-fs
KNOWLEDGE_FS_CAPABILITY_V2_MAX_TTL_SECONDS=60
KNOWLEDGE_FS_JWKS_CACHE_MAX_AGE_SECONDS=300
KNOWLEDGE_FS_PRODUCT_MAX_RESPONSE_BYTES=4194304
KNOWLEDGE_FS_TIMEOUT_SECONDS=10
# Retrieval tests have a 60-second KnowledgeFS execution budget and need transport headroom.
KNOWLEDGE_FS_RETRIEVAL_TEST_TIMEOUT_SECONDS=75
# Lifetime in days of difyctl (OAuth device flow) tokens, 1-365; out-of-range values are clamped
# OAUTH_TTL_DAYS=14
# Cloudflare Turnstile server-side verification for Dify Cloud sign-in
TURNSTILE_SECRET_KEY=
TURNSTILE_ALLOWED_HOSTNAMES=
TURNSTILE_EMAIL_CODE_VERIFY_REQUIRED=false
@@ -0,0 +1,132 @@
# Defaults for agent_backend. Copy this file to dify-agent.env to customize it.
# Edit the settings below in the copy; docker/.env takes precedence.
# Optional application settings are commented to retain their application defaults.
# AGENT_BACKEND_BASE_URL=http://agent_backend:5050
# Set this in docker/.env to share the same control-plane token with API and workers.
# Replace the development default in production.
# Generate one with: python -c 'import secrets; print(secrets.token_urlsafe(32))'
DIFY_AGENT_API_TOKEN=${DIFY_AGENT_API_TOKEN:-dify-agent-run-token-for-dev-only}
# Leave empty to derive from REDIS_PASSWORD in Docker Compose.
DIFY_AGENT_REDIS_URL=${DIFY_AGENT_REDIS_URL:-redis://:${REDIS_PASSWORD:-difyai123456}@redis:6379/2}
# DIFY_AGENT_REDIS_PREFIX=dify-agent
# DIFY_AGENT_SHUTDOWN_GRACE_SECONDS=30
# DIFY_AGENT_RUN_RETENTION_SECONDS=7200
# DIFY_AGENT_RUN_EVENT_STREAM_MAX_LENGTH=5000
# DIFY_AGENT_STREAM_TEXT_DELTA_COALESCING_ENABLED=true
# DIFY_AGENT_STREAM_TEXT_DELTA_FLUSH_INTERVAL_MS=100
# DIFY_AGENT_STREAM_TEXT_DELTA_MAX_CHARS=4096
# Internal deadline for the Agent Backend model/tool loop. The effective run
# limit is whichever expires first: this value or the relevant API/Workflow
# outer execution limit. To allow every path to run for one hour, also set
# APP_MAX_EXECUTION_TIME and WORKFLOW_MAX_EXECUTION_TIME to at least 3600.
# DIFY_AGENT_RUN_TIMEOUT_SECONDS=3600
# DIFY_AGENT_BINDING_FILE_DOWNLOAD_COMMAND_TIMEOUT_SECONDS=210
# Shared outbound HTTP client timeouts and connection limits.
# DIFY_AGENT_OUTBOUND_HTTP_CONNECT_TIMEOUT=10
# DIFY_AGENT_OUTBOUND_HTTP_READ_TIMEOUT=600
# DIFY_AGENT_OUTBOUND_HTTP_WRITE_TIMEOUT=30
# DIFY_AGENT_OUTBOUND_HTTP_POOL_TIMEOUT=10
# DIFY_AGENT_OUTBOUND_HTTP_MAX_CONNECTIONS=100
# DIFY_AGENT_OUTBOUND_HTTP_MAX_KEEPALIVE_CONNECTIONS=20
# DIFY_AGENT_OUTBOUND_HTTP_KEEPALIVE_EXPIRY=30
# DIFY_AGENT_TRAJECTORY_ENABLED=false
# Collect API-issued application traces into the Dify inner API inbox.
# DIFY_AGENT_APPLICATION_TRACING_ENABLED=false
# DIFY_AGENT_TRAJECTORY_OTLP_TRACES_ENDPOINT=
# DIFY_AGENT_TRAJECTORY_OTLP_HEADERS={}
# DIFY_AGENT_TRAJECTORY_SERVICE_NAME=dify-agent-trajectory
# DIFY_AGENT_TRAJECTORY_INCLUDE_CONTENT=false
# DIFY_AGENT_TRAJECTORY_TRACE_CONTEXT_MODE=isolated
# DIFY_AGENT_TRAJECTORY_MAX_QUEUE_SIZE=2048
# DIFY_AGENT_TRAJECTORY_MAX_EXPORT_BATCH_SIZE=512
# DIFY_AGENT_TRAJECTORY_SCHEDULE_DELAY_MS=5000
# DIFY_AGENT_TRAJECTORY_EXPORT_TIMEOUT_MS=5000
# LOGFIRE_CONSOLE=false
# Leave empty to derive from PLUGIN_DAEMON_URL and PLUGIN_DAEMON_KEY in Docker Compose.
# Set PLUGIN_DAEMON_KEY in docker/.env when using the bundled daemon; keep the key expression below unchanged.
DIFY_AGENT_PLUGIN_DAEMON_URL=${DIFY_AGENT_PLUGIN_DAEMON_URL:-${PLUGIN_DAEMON_URL:-http://plugin_daemon:5002}}
DIFY_AGENT_PLUGIN_DAEMON_API_KEY=${DIFY_AGENT_PLUGIN_DAEMON_API_KEY:-${PLUGIN_DAEMON_KEY:-lYkiYYT6owG+71oLerGzA7GXCgOT++6ovaezWAjpCjf+Sjc3ZtU+qUEi}}
# Leave empty to derive from PLUGIN_DIFY_INNER_API_URL and PLUGIN_DIFY_INNER_API_KEY in Docker Compose.
# DIFY_AGENT_INNER_API_KEY must match API/worker INNER_API_KEY_FOR_PLUGIN, not INNER_API_KEY.
# Set PLUGIN_DIFY_INNER_API_KEY in docker/.env; keep the key expression below unchanged for the bundled API.
DIFY_AGENT_INNER_API_URL=${DIFY_AGENT_INNER_API_URL:-${PLUGIN_DIFY_INNER_API_URL:-http://api:5001}}
DIFY_AGENT_INNER_API_KEY=${DIFY_AGENT_INNER_API_KEY:-${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1}}
# Select exactly one coherent Home Snapshot + Sandbox backend.
DIFY_AGENT_RUNTIME_BACKEND=${DIFY_AGENT_RUNTIME_BACKEND:-local}
DIFY_AGENT_LOCAL_SANDBOX_ENDPOINT=${DIFY_AGENT_LOCAL_SANDBOX_ENDPOINT:-${DIFY_AGENT_SHELLCTL_ENTRYPOINT:-http://local_sandbox:5004}}
# Required nonblank secret for Local. Set in docker/.env to also configure shellctl.
DIFY_AGENT_LOCAL_SANDBOX_AUTH_TOKEN=${DIFY_AGENT_LOCAL_SANDBOX_AUTH_TOKEN:-${DIFY_AGENT_SHELLCTL_AUTH_TOKEN:-}}
# E2B_API_KEY and E2B_API_TOKEN remain accepted as deployment-level fallbacks.
DIFY_AGENT_E2B_API_KEY=${DIFY_AGENT_E2B_API_KEY:-${E2B_API_KEY:-${E2B_API_TOKEN:-}}}
DIFY_AGENT_E2B_TEMPLATE=${DIFY_AGENT_E2B_TEMPLATE:-difys-default-team/dify-agent-local-sandbox}
# RuntimeLease active limit; its default matches the independently configurable Agent run deadline.
# DIFY_AGENT_E2B_ACTIVE_TIMEOUT_SECONDS=3600
# DIFY_AGENT_E2B_SHELLCTL_PORT=5004
# Independent sandbox usage ledger. API owns fixed activation time T0; no backfill.
# Enable only with matching API metering project settings and events API access.
# Celery Beat in the API triggers a protected one-shot collection endpoint.
# No operation logging, Agent polling loop, or collector Redis leader.
# Collection requires the existing DIFY_AGENT_API_TOKEN to be configured.
# DIFY_AGENT_SANDBOX_METERING_ENABLED=false
# DIFY_AGENT_E2B_PROJECT_ID=
# DIFY_AGENT_SANDBOX_METERING_OVERLAP_SECONDS=900
# DIFY_AGENT_SANDBOX_METERING_FULL_SCAN_INTERVAL_SECONDS=3600
# DIFY_AGENT_SANDBOX_METERING_MAX_PAGES=1000
# OpenShell backend (DIFY_AGENT_RUNTIME_BACKEND=openshell): sandboxes run on a
# self-hosted NVIDIA OpenShell gateway. Setup and validation:
# dify-agent/docs/dify-agent/guide/openshell.md
# gRPC endpoint as host:port (no scheme), e.g. localhost:17670.
# DIFY_AGENT_OPENSHELL_GATEWAY_ENDPOINT=
# One workspace and one dedicated shared volume per tenant in production.
# DIFY_AGENT_OPENSHELL_WORKSPACE=default
# Auth: an OIDC bearer token, or mTLS bundle paths mounted into agent_backend.
# DIFY_AGENT_OPENSHELL_BEARER_TOKEN=
# DIFY_AGENT_OPENSHELL_TLS_CA_PATH=
# DIFY_AGENT_OPENSHELL_TLS_CLIENT_CERT_PATH=
# DIFY_AGENT_OPENSHELL_TLS_CLIENT_KEY_PATH=
# Set true only for plaintext local-dev gateways.
# DIFY_AGENT_OPENSHELL_INSECURE=false
# Required: build the runtime image yourself from this checkout; do not rely on a published latest tag.
# From the repository root (the directory containing dify-agent-runtime/):
# docker build -f dify-agent-runtime/docker/Dockerfile -t dify-agent-runtime:latest dify-agent-runtime
# The image must include shellctl and iproute2. This value must match the built image tag.
# Build into the gateway's Docker daemon, or push to a registry it can pull from and use that image reference.
# DIFY_AGENT_OPENSHELL_SANDBOX_IMAGE=docker.io/library/dify-agent-runtime:latest
# Required JSON driver_config mounting the operator-owned shared volume;
# one-time volume initialization and driver examples live in the guide.
# DIFY_AGENT_OPENSHELL_DRIVER_CONFIG=
# DIFY_AGENT_OPENSHELL_SHARED_MOUNT_PATH=/mnt/dify-agent-shared
# Optional comma-separated host:port egress allowlist (no scheme or path).
# Empty sends no network policy (gateway/driver default egress); when set,
# sandbox egress is enforced to exactly these endpoints — include the Agent
# Stub and files endpoints, e.g. agent.example.com:443,dify.example.com:443.
# DIFY_AGENT_OPENSHELL_EGRESS_ALLOW=
# Required. shellctl path isolation stays off (sandbox Landlock is authoritative).
# DIFY_AGENT_OPENSHELL_SHELLCTL_AUTH_TOKEN=
# DIFY_AGENT_OPENSHELL_SHELLCTL_PORT=5004
# DIFY_AGENT_OPENSHELL_READY_TIMEOUT_SECONDS=300
# DIFY_AGENT_OPENSHELL_EXEC_TIMEOUT_SECONDS=120
# Sandbox-reachable Dify API base for signed /files/* transfers.
DIFY_AGENT_SANDBOX_FILES_BASE_URL=${DIFY_AGENT_SANDBOX_FILES_BASE_URL:-http://api:5001}
# Maximum Agent Stub upload size in MiB; forwarded to Dify API as a signed byte limit.
# DIFY_AGENT_STUB_UPLOAD_FILE_SIZE_LIMIT=50
DIFY_AGENT_STUB_API_BASE_URL=${DIFY_AGENT_STUB_API_BASE_URL:-http://agent_backend:5050/agent-stub}
# This is security-sensitive: it derives the JWE encryption key for Agent Stub bearer tokens.
# Replace this development default in production.
# Generate one with: python -c 'import secrets; print(secrets.token_urlsafe(32))'
DIFY_AGENT_SERVER_SECRET_KEY=${DIFY_AGENT_SERVER_SECRET_KEY:-MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWY}
# JSON array of regex patterns to redact from shell output shown to the agent.
# The JWE token value is always redacted regardless of this setting.
# Example: DIFY_AGENT_SHELL_REDACT_PATTERNS=["sk-[A-Za-z0-9]+","ghp_[A-Za-z0-9]{36}"]
# DIFY_AGENT_SHELL_REDACT_PATTERNS=
@@ -1,132 +0,0 @@
# ------------------------------
# Dify Agent Backend Configuration
# ------------------------------
AGENT_BACKEND_BASE_URL=http://agent_backend:5050
# Set this in docker/.env to share the same control-plane token with API and workers.
# Replace the development default in production.
# Generate one with: python -c 'import secrets; print(secrets.token_urlsafe(32))'
# DIFY_AGENT_API_TOKEN=dify-agent-run-token-for-dev-only
# Leave empty to derive from REDIS_PASSWORD in Docker Compose.
DIFY_AGENT_REDIS_URL=
DIFY_AGENT_REDIS_PREFIX=dify-agent
DIFY_AGENT_SHUTDOWN_GRACE_SECONDS=30
DIFY_AGENT_RUN_RETENTION_SECONDS=7200
DIFY_AGENT_RUN_EVENT_STREAM_MAX_LENGTH=5000
DIFY_AGENT_STREAM_TEXT_DELTA_COALESCING_ENABLED=true
DIFY_AGENT_STREAM_TEXT_DELTA_FLUSH_INTERVAL_MS=100
DIFY_AGENT_STREAM_TEXT_DELTA_MAX_CHARS=4096
# Internal deadline for the Agent Backend model/tool loop. The effective run
# limit is whichever expires first: this value or the relevant API/Workflow
# outer execution limit. To allow every path to run for one hour, also set
# APP_MAX_EXECUTION_TIME and WORKFLOW_MAX_EXECUTION_TIME to at least 3600.
DIFY_AGENT_RUN_TIMEOUT_SECONDS=3600
DIFY_AGENT_BINDING_FILE_DOWNLOAD_COMMAND_TIMEOUT_SECONDS=210
# Shared outbound HTTP client timeouts and connection limits.
DIFY_AGENT_OUTBOUND_HTTP_CONNECT_TIMEOUT=10
DIFY_AGENT_OUTBOUND_HTTP_READ_TIMEOUT=600
DIFY_AGENT_OUTBOUND_HTTP_WRITE_TIMEOUT=30
DIFY_AGENT_OUTBOUND_HTTP_POOL_TIMEOUT=10
DIFY_AGENT_OUTBOUND_HTTP_MAX_CONNECTIONS=100
DIFY_AGENT_OUTBOUND_HTTP_MAX_KEEPALIVE_CONNECTIONS=20
DIFY_AGENT_OUTBOUND_HTTP_KEEPALIVE_EXPIRY=30
DIFY_AGENT_TRAJECTORY_ENABLED=false
# Collect API-issued application traces into the Dify inner API inbox.
DIFY_AGENT_APPLICATION_TRACING_ENABLED=false
DIFY_AGENT_TRAJECTORY_OTLP_TRACES_ENDPOINT=
DIFY_AGENT_TRAJECTORY_OTLP_HEADERS={}
DIFY_AGENT_TRAJECTORY_SERVICE_NAME=dify-agent-trajectory
DIFY_AGENT_TRAJECTORY_INCLUDE_CONTENT=false
DIFY_AGENT_TRAJECTORY_TRACE_CONTEXT_MODE=isolated
DIFY_AGENT_TRAJECTORY_MAX_QUEUE_SIZE=2048
DIFY_AGENT_TRAJECTORY_MAX_EXPORT_BATCH_SIZE=512
DIFY_AGENT_TRAJECTORY_SCHEDULE_DELAY_MS=5000
DIFY_AGENT_TRAJECTORY_EXPORT_TIMEOUT_MS=5000
LOGFIRE_CONSOLE=false
# Leave empty to derive from PLUGIN_DAEMON_URL and PLUGIN_DAEMON_KEY in Docker Compose.
DIFY_AGENT_PLUGIN_DAEMON_URL=
DIFY_AGENT_PLUGIN_DAEMON_API_KEY=
# Leave empty to derive from PLUGIN_DIFY_INNER_API_URL and PLUGIN_DIFY_INNER_API_KEY in Docker Compose.
# DIFY_AGENT_INNER_API_KEY must match API/worker INNER_API_KEY_FOR_PLUGIN, not INNER_API_KEY.
DIFY_AGENT_INNER_API_URL=
DIFY_AGENT_INNER_API_KEY=
# Select exactly one coherent Home Snapshot + Sandbox backend.
DIFY_AGENT_RUNTIME_BACKEND=local
DIFY_AGENT_LOCAL_SANDBOX_ENDPOINT=http://local_sandbox:5004
# Required nonblank secret for Local. Set in the shared Compose interpolation source: shell,
# docker/.env, or --env-file. Setting only this service env file is overridden
# by Compose's explicit environment value and does not configure shellctl.
DIFY_AGENT_LOCAL_SANDBOX_AUTH_TOKEN=
# E2B_API_KEY and E2B_API_TOKEN remain accepted as deployment-level fallbacks.
DIFY_AGENT_E2B_API_KEY=${DIFY_AGENT_E2B_API_KEY:-${E2B_API_KEY:-${E2B_API_TOKEN:-}}}
DIFY_AGENT_E2B_TEMPLATE=difys-default-team/dify-agent-local-sandbox
# RuntimeLease active limit; its default matches the independently configurable Agent run deadline.
DIFY_AGENT_E2B_ACTIVE_TIMEOUT_SECONDS=3600
DIFY_AGENT_E2B_SHELLCTL_PORT=5004
# Independent sandbox usage ledger. API owns fixed activation time T0; no backfill.
# Enable only with matching API metering project settings and events API access.
# Celery Beat in the API triggers a protected one-shot collection endpoint.
# No operation logging, Agent polling loop, or collector Redis leader.
# Collection requires the existing DIFY_AGENT_API_TOKEN to be configured.
DIFY_AGENT_SANDBOX_METERING_ENABLED=false
DIFY_AGENT_E2B_PROJECT_ID=
DIFY_AGENT_SANDBOX_METERING_OVERLAP_SECONDS=900
DIFY_AGENT_SANDBOX_METERING_FULL_SCAN_INTERVAL_SECONDS=3600
DIFY_AGENT_SANDBOX_METERING_MAX_PAGES=1000
# OpenShell backend (DIFY_AGENT_RUNTIME_BACKEND=openshell): sandboxes run on a
# self-hosted NVIDIA OpenShell gateway. Setup and validation:
# dify-agent/docs/dify-agent/guide/openshell.md
# gRPC endpoint as host:port (no scheme), e.g. localhost:17670.
DIFY_AGENT_OPENSHELL_GATEWAY_ENDPOINT=
# One workspace and one dedicated shared volume per tenant in production.
DIFY_AGENT_OPENSHELL_WORKSPACE=default
# Auth: an OIDC bearer token, or mTLS bundle paths mounted into agent_backend.
DIFY_AGENT_OPENSHELL_BEARER_TOKEN=
DIFY_AGENT_OPENSHELL_TLS_CA_PATH=
DIFY_AGENT_OPENSHELL_TLS_CLIENT_CERT_PATH=
DIFY_AGENT_OPENSHELL_TLS_CLIENT_KEY_PATH=
# Set true only for plaintext local-dev gateways.
DIFY_AGENT_OPENSHELL_INSECURE=false
# Required: build the runtime image yourself from this checkout; do not rely on a published latest tag.
# From the repository root (the directory containing dify-agent-runtime/):
# docker build -f dify-agent-runtime/docker/Dockerfile -t dify-agent-runtime:latest dify-agent-runtime
# The image must include shellctl and iproute2. This value must match the built image tag.
# Build into the gateway's Docker daemon, or push to a registry it can pull from and use that image reference.
DIFY_AGENT_OPENSHELL_SANDBOX_IMAGE=docker.io/library/dify-agent-runtime:latest
# Required JSON driver_config mounting the operator-owned shared volume;
# one-time volume initialization and driver examples live in the guide.
DIFY_AGENT_OPENSHELL_DRIVER_CONFIG=
DIFY_AGENT_OPENSHELL_SHARED_MOUNT_PATH=/mnt/dify-agent-shared
# Optional comma-separated host:port egress allowlist (no scheme or path).
# Empty sends no network policy (gateway/driver default egress); when set,
# sandbox egress is enforced to exactly these endpoints — include the Agent
# Stub and files endpoints, e.g. agent.example.com:443,dify.example.com:443.
DIFY_AGENT_OPENSHELL_EGRESS_ALLOW=
# Required. shellctl path isolation stays off (sandbox Landlock is authoritative).
DIFY_AGENT_OPENSHELL_SHELLCTL_AUTH_TOKEN=
DIFY_AGENT_OPENSHELL_SHELLCTL_PORT=5004
DIFY_AGENT_OPENSHELL_READY_TIMEOUT_SECONDS=300
DIFY_AGENT_OPENSHELL_EXEC_TIMEOUT_SECONDS=120
# Sandbox-reachable Dify API base for signed /files/* transfers.
DIFY_AGENT_SANDBOX_FILES_BASE_URL=http://api:5001
# Maximum Agent Stub upload size in MiB; forwarded to Dify API as a signed byte limit.
DIFY_AGENT_STUB_UPLOAD_FILE_SIZE_LIMIT=50
DIFY_AGENT_STUB_API_BASE_URL=http://agent_backend:5050/agent-stub
# This is security-sensitive: it derives the JWE encryption key for Agent Stub bearer tokens.
# Replace this development default in production.
# Generate one with: python -c 'import secrets; print(secrets.token_urlsafe(32))'
DIFY_AGENT_SERVER_SECRET_KEY=MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWY
# JSON array of regex patterns to redact from shell output shown to the agent.
# The JWE token value is always redacted regardless of this setting.
# Example: DIFY_AGENT_SHELL_REDACT_PATTERNS=["sk-[A-Za-z0-9]+","ghp_[A-Za-z0-9]{36}"]
DIFY_AGENT_SHELL_REDACT_PATTERNS=
@@ -0,0 +1,89 @@
# Defaults for plugin_daemon. Copy this file to plugin-daemon.env to customize it.
# Edit the settings below in the copy; docker/.env takes precedence.
# Optional application settings are commented to retain their application defaults.
DB_PLUGIN_DATABASE=${DB_PLUGIN_DATABASE:-dify_plugin}
# PLUGIN_DAEMON_URL=http://plugin_daemon:5002
PLUGIN_PPROF_ENABLED=${PLUGIN_PPROF_ENABLED:-false}
PLUGIN_DIFY_INNER_API_URL=${PLUGIN_DIFY_INNER_API_URL:-http://api:5001}
FORCE_VERIFYING_SIGNATURE=${FORCE_VERIFYING_SIGNATURE:-true}
PLUGIN_STDIO_BUFFER_SIZE=${PLUGIN_STDIO_BUFFER_SIZE:-1024}
PLUGIN_STDIO_MAX_BUFFER_SIZE=${PLUGIN_STDIO_MAX_BUFFER_SIZE:-5242880}
PLUGIN_PYTHON_ENV_INIT_TIMEOUT=${PLUGIN_PYTHON_ENV_INIT_TIMEOUT:-120}
PLUGIN_MAX_EXECUTION_TIMEOUT=${PLUGIN_MAX_EXECUTION_TIMEOUT:-600}
PLUGIN_DEBUGGING_HOST=${PLUGIN_DEBUGGING_HOST:-0.0.0.0}
# Set PLUGIN_DEBUGGING_PORT in docker/.env; Compose needs it before loading service files.
# Set PLUGIN_DAEMON_KEY in docker/.env; API, workers, and Agent must share the daemon's credential.
# Set PLUGIN_DIFY_INNER_API_KEY in docker/.env; all callers must share the API's inner credential.
PLUGIN_DAEMON_PORT=${PLUGIN_DAEMON_PORT:-5002}
PLUGIN_STORAGE_TYPE=${PLUGIN_STORAGE_TYPE:-local}
PLUGIN_STORAGE_LOCAL_ROOT=${PLUGIN_STORAGE_LOCAL_ROOT:-/app/storage}
PLUGIN_WORKING_PATH=${PLUGIN_WORKING_PATH:-/app/storage/cwd}
# Optional: set in docker/.env for Docker/WSL bind-mount permission errors (langgenius/dify#42433).
# UV_CACHE_DIR=/tmp/.uv-cache
PLUGIN_STORAGE_OSS_BUCKET=${PLUGIN_STORAGE_OSS_BUCKET:-}
PLUGIN_ALIYUN_OSS_ACCESS_KEY_ID=${PLUGIN_ALIYUN_OSS_ACCESS_KEY_ID:-}
PLUGIN_ALIYUN_OSS_ACCESS_KEY_SECRET=${PLUGIN_ALIYUN_OSS_ACCESS_KEY_SECRET:-}
PLUGIN_ALIYUN_OSS_AUTH_VERSION=${PLUGIN_ALIYUN_OSS_AUTH_VERSION:-v4}
PLUGIN_ALIYUN_OSS_ENDPOINT=${PLUGIN_ALIYUN_OSS_ENDPOINT:-}
PLUGIN_ALIYUN_OSS_PATH=${PLUGIN_ALIYUN_OSS_PATH:-}
PLUGIN_ALIYUN_OSS_REGION=${PLUGIN_ALIYUN_OSS_REGION:-}
PLUGIN_AWS_ACCESS_KEY=${PLUGIN_AWS_ACCESS_KEY:-}
PLUGIN_AWS_REGION=${PLUGIN_AWS_REGION:-}
PLUGIN_AWS_SECRET_KEY=${PLUGIN_AWS_SECRET_KEY:-}
PLUGIN_AZURE_BLOB_STORAGE_CONNECTION_STRING=${PLUGIN_AZURE_BLOB_STORAGE_CONNECTION_STRING:-}
PLUGIN_AZURE_BLOB_STORAGE_CONTAINER_NAME=${PLUGIN_AZURE_BLOB_STORAGE_CONTAINER_NAME:-}
DB_SSL_MODE=${DB_SSL_MODE:-disable}
PLUGIN_MAX_PACKAGE_SIZE=${PLUGIN_MAX_PACKAGE_SIZE:-52428800}
PIP_MIRROR_URL=${PIP_MIRROR_URL:-}
PLUGIN_INSTALLED_PATH=${PLUGIN_INSTALLED_PATH:-plugin}
PLUGIN_MEDIA_CACHE_PATH=${PLUGIN_MEDIA_CACHE_PATH:-assets}
PLUGIN_PACKAGE_CACHE_PATH=${PLUGIN_PACKAGE_CACHE_PATH:-plugin_packages}
PLUGIN_S3_ENDPOINT=${PLUGIN_S3_ENDPOINT:-}
PLUGIN_S3_USE_AWS=${PLUGIN_S3_USE_AWS:-false}
PLUGIN_S3_USE_AWS_MANAGED_IAM=${PLUGIN_S3_USE_AWS_MANAGED_IAM:-false}
PLUGIN_S3_USE_PATH_STYLE=${PLUGIN_S3_USE_PATH_STYLE:-false}
PLUGIN_SENTRY_DSN=${PLUGIN_SENTRY_DSN:-}
PLUGIN_SENTRY_ENABLED=${PLUGIN_SENTRY_ENABLED:-false}
PLUGIN_TENCENT_COS_REGION=${PLUGIN_TENCENT_COS_REGION:-}
PLUGIN_TENCENT_COS_SECRET_ID=${PLUGIN_TENCENT_COS_SECRET_ID:-}
PLUGIN_TENCENT_COS_SECRET_KEY=${PLUGIN_TENCENT_COS_SECRET_KEY:-}
PLUGIN_VOLCENGINE_TOS_ACCESS_KEY=${PLUGIN_VOLCENGINE_TOS_ACCESS_KEY:-}
PLUGIN_VOLCENGINE_TOS_ENDPOINT=${PLUGIN_VOLCENGINE_TOS_ENDPOINT:-}
PLUGIN_VOLCENGINE_TOS_REGION=${PLUGIN_VOLCENGINE_TOS_REGION:-}
PLUGIN_VOLCENGINE_TOS_SECRET_KEY=${PLUGIN_VOLCENGINE_TOS_SECRET_KEY:-}
# Container variable mappings; keep these expressions unchanged in the copy.
ALIYUN_OSS_ACCESS_KEY_ID=${PLUGIN_ALIYUN_OSS_ACCESS_KEY_ID:-}
ALIYUN_OSS_ACCESS_KEY_SECRET=${PLUGIN_ALIYUN_OSS_ACCESS_KEY_SECRET:-}
ALIYUN_OSS_AUTH_VERSION=${PLUGIN_ALIYUN_OSS_AUTH_VERSION:-v4}
ALIYUN_OSS_ENDPOINT=${PLUGIN_ALIYUN_OSS_ENDPOINT:-}
ALIYUN_OSS_PATH=${PLUGIN_ALIYUN_OSS_PATH:-}
ALIYUN_OSS_REGION=${PLUGIN_ALIYUN_OSS_REGION:-}
AWS_ACCESS_KEY=${PLUGIN_AWS_ACCESS_KEY:-}
AWS_REGION=${PLUGIN_AWS_REGION:-}
AWS_SECRET_KEY=${PLUGIN_AWS_SECRET_KEY:-}
AZURE_BLOB_STORAGE_CONNECTION_STRING=${PLUGIN_AZURE_BLOB_STORAGE_CONNECTION_STRING:-}
AZURE_BLOB_STORAGE_CONTAINER_NAME=${PLUGIN_AZURE_BLOB_STORAGE_CONTAINER_NAME:-}
DB_DATABASE=${DB_PLUGIN_DATABASE:-dify_plugin}
DIFY_INNER_API_KEY=${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1}
DIFY_INNER_API_URL=${PLUGIN_DIFY_INNER_API_URL:-http://api:5001}
MAX_PLUGIN_PACKAGE_SIZE=${PLUGIN_MAX_PACKAGE_SIZE:-52428800}
PLUGIN_REMOTE_INSTALLING_HOST=${PLUGIN_DEBUGGING_HOST:-0.0.0.0}
PPROF_ENABLED=${PLUGIN_PPROF_ENABLED:-false}
PYTHON_ENV_INIT_TIMEOUT=${PLUGIN_PYTHON_ENV_INIT_TIMEOUT:-120}
S3_ENDPOINT=${PLUGIN_S3_ENDPOINT:-}
S3_USE_AWS=${PLUGIN_S3_USE_AWS:-false}
S3_USE_AWS_MANAGED_IAM=${PLUGIN_S3_USE_AWS_MANAGED_IAM:-false}
S3_USE_PATH_STYLE=${PLUGIN_S3_USE_PATH_STYLE:-false}
SENTRY_DSN=${PLUGIN_SENTRY_DSN:-}
SENTRY_ENABLED=${PLUGIN_SENTRY_ENABLED:-false}
SERVER_KEY=${PLUGIN_DAEMON_KEY:-lYkiYYT6owG+71oLerGzA7GXCgOT++6ovaezWAjpCjf+Sjc3ZtU+qUEi}
SERVER_PORT=${PLUGIN_DAEMON_PORT:-5002}
TENCENT_COS_REGION=${PLUGIN_TENCENT_COS_REGION:-}
TENCENT_COS_SECRET_ID=${PLUGIN_TENCENT_COS_SECRET_ID:-}
TENCENT_COS_SECRET_KEY=${PLUGIN_TENCENT_COS_SECRET_KEY:-}
VOLCENGINE_TOS_ACCESS_KEY=${PLUGIN_VOLCENGINE_TOS_ACCESS_KEY:-}
VOLCENGINE_TOS_ENDPOINT=${PLUGIN_VOLCENGINE_TOS_ENDPOINT:-}
VOLCENGINE_TOS_REGION=${PLUGIN_VOLCENGINE_TOS_REGION:-}
VOLCENGINE_TOS_SECRET_KEY=${PLUGIN_VOLCENGINE_TOS_SECRET_KEY:-}
@@ -1,25 +0,0 @@
# ------------------------------
# Plugin Daemon Configuration
# ------------------------------
DB_PLUGIN_DATABASE=dify_plugin
PLUGIN_DAEMON_URL=http://plugin_daemon:5002
PLUGIN_PPROF_ENABLED=false
PLUGIN_DIFY_INNER_API_URL=http://api:5001
FORCE_VERIFYING_SIGNATURE=true
PLUGIN_STDIO_BUFFER_SIZE=1024
PLUGIN_STDIO_MAX_BUFFER_SIZE=5242880
PLUGIN_PYTHON_ENV_INIT_TIMEOUT=120
PLUGIN_MAX_EXECUTION_TIMEOUT=600
PLUGIN_DEBUGGING_HOST=0.0.0.0
PLUGIN_DEBUGGING_PORT=5003
PLUGIN_DAEMON_KEY=lYkiYYT6owG+71oLerGzA7GXCgOT++6ovaezWAjpCjf+Sjc3ZtU+qUEi
PLUGIN_DIFY_INNER_API_KEY=QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1
PLUGIN_DAEMON_PORT=5002
CELERY_WORKER_CLASS=
PLUGIN_STORAGE_TYPE=local
PLUGIN_STORAGE_LOCAL_ROOT=/app/storage
PLUGIN_WORKING_PATH=/app/storage/cwd
# Optional: set in docker/.env for Docker/WSL bind-mount permission errors (langgenius/dify#42433).
# UV_CACHE_DIR=/tmp/.uv-cache
PLUGIN_STORAGE_OSS_BUCKET=
@@ -0,0 +1,26 @@
# Defaults for sandbox. Copy this file to sandbox.env to customize it.
# Edit the settings below in the copy; docker/.env takes precedence.
# Optional application settings are commented to retain their application defaults.
SANDBOX_HTTP_PROXY=${SANDBOX_HTTP_PROXY:-http://ssrf_proxy:3128}
SANDBOX_HTTPS_PROXY=${SANDBOX_HTTPS_PROXY:-http://ssrf_proxy:3128}
SANDBOX_PORT=${SANDBOX_PORT:-8194}
PIP_MIRROR_URL=${PIP_MIRROR_URL:-}
# Use a strong key for your deployment, generated with `openssl rand -base64 42`.
# Set the same value for CODE_EXECUTION_API_KEY in the API/worker configuration.
SANDBOX_API_KEY=${SANDBOX_API_KEY:-dify-sandbox}
SANDBOX_GIN_MODE=${SANDBOX_GIN_MODE:-release}
SANDBOX_WORKER_TIMEOUT=${SANDBOX_WORKER_TIMEOUT:-15}
# Dify's code executor requests networking; false rejects those requests.
# Sandbox 0.2.15 on ARM64 can also fail with "operation not permitted" for
# requests with enable_network=false, even without network operations:
# the runtime needs epoll_pwait, which is only allowed with networking enabled.
SANDBOX_ENABLE_NETWORK=${SANDBOX_ENABLE_NETWORK:-true}
# Container variable mappings; keep these expressions unchanged in the copy.
API_KEY=${SANDBOX_API_KEY:-dify-sandbox}
ENABLE_NETWORK=${SANDBOX_ENABLE_NETWORK:-true}
GIN_MODE=${SANDBOX_GIN_MODE:-release}
HTTPS_PROXY=${SANDBOX_HTTPS_PROXY:-http://ssrf_proxy:3128}
HTTP_PROXY=${SANDBOX_HTTP_PROXY:-http://ssrf_proxy:3128}
WORKER_TIMEOUT=${SANDBOX_WORKER_TIMEOUT:-15}
@@ -1,17 +0,0 @@
# ------------------------------
# Sandbox Configuration
# ------------------------------
SANDBOX_HTTP_PROXY=http://ssrf_proxy:3128
SANDBOX_HTTPS_PROXY=http://ssrf_proxy:3128
SANDBOX_PORT=8194
PIP_MIRROR_URL=
SANDBOX_API_KEY=dify-sandbox
SANDBOX_GIN_MODE=release
SANDBOX_WORKER_TIMEOUT=15
SANDBOX_ENABLE_NETWORK=true
SANDBOX_EXPIRED_RECORDS_CLEAN_GRACEFUL_PERIOD=21
SANDBOX_EXPIRED_RECORDS_CLEAN_BATCH_SIZE=1000
SANDBOX_EXPIRED_RECORDS_CLEAN_BATCH_MAX_INTERVAL=200
SANDBOX_EXPIRED_RECORDS_RETENTION_DAYS=30
SANDBOX_EXPIRED_RECORDS_CLEAN_TASK_LOCK_TTL=90000
+567 -28
View File
@@ -1,28 +1,567 @@
# Docker-specific defaults, loaded before optional env files and docker/.env.
# Keep runtime defaults in the application or Compose; only Docker overrides belong here.
# Override these values in docker/.env or the matching envs/*.env file, not here.
CONSOLE_CORS_ALLOW_ORIGINS=*
TRIGGER_URL=http://localhost
ENDPOINT_URL_TEMPLATE=http://localhost/e/{hook_id}
MIGRATION_ENABLED=true
LOG_FILE=/app/logs/server.log
LOG_DATEFORMAT=%Y-%m-%d %H:%M:%S
CELERY_WORKER_AMOUNT=4
DB_HOST=db_postgres
DB_PASSWORD=difyai123456
REDIS_HOST=redis
REDIS_PASSWORD=difyai123456
REDIS_KEEPALIVE=true
CELERY_BROKER_URL=redis://:${REDIS_PASSWORD:-difyai123456}@${REDIS_HOST:-redis}:${REDIS_PORT:-6379}/1
OPENDAL_FS_ROOT=storage
VECTOR_STORE=weaviate
WEAVIATE_ENDPOINT=http://weaviate:8080
WEAVIATE_API_KEY=WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih
WEAVIATE_GRPC_ENDPOINT=grpc://weaviate:50051
SSRF_PROXY_HTTP_URL=http://ssrf_proxy:3128
SSRF_PROXY_HTTPS_URL=http://ssrf_proxy:3128
PLUGIN_DAEMON_URL=http://plugin_daemon:5002
PLUGIN_DAEMON_KEY=lYkiYYT6owG+71oLerGzA7GXCgOT++6ovaezWAjpCjf+Sjc3ZtU+qUEi
PLUGIN_MAX_PACKAGE_SIZE=52428800
AGENT_BACKEND_BASE_URL=http://agent_backend:5050
NEXT_PUBLIC_ENABLE_AGENT_V2=true
# Shared API, worker and Beat configuration. Copy this file to shared.env to customize it.
# Edit the copy; docker/.env takes precedence. Existing shared.env files remain supported.
# Active assignments preserve Docker defaults and explicit overrides, including empty values.
# Optional application/provider settings are commented examples: uncomment only what you need.
# Do not uncomment empty values or placeholders unless you intend to set them.
# Remove accidental empty overrides (especially CELERY_WORKER_AMOUNT=) to restore defaults.
# API process settings: api.defaults. Worker process settings: worker.defaults.
# Sentry mappings: api.defaults and worker.defaults. Web and plugin-daemon settings stay in their files.
# Shared secrets and token lifetimes: copy ../security.env.example to ../security.env.
# Set COMPOSE_PROFILES in docker/.env; Compose reads it before service env files.
# Set EXPOSE_NGINX_PORT in docker/.env; Compose reads published ports before service env files.
# Set EXPOSE_NGINX_SSL_PORT in docker/.env; Compose reads published ports before service env files.
# Set EXPOSE_PLUGIN_DEBUGGING_HOST in docker/.env; the API and daemon must use the published address.
# Set EXPOSE_PLUGIN_DEBUGGING_PORT in docker/.env; the API and daemon must use the published port.
# ------------------------------
# URLs, deployment and locale
# ------------------------------
# CONSOLE_WEB_URL=
# SERVICE_API_URL=
TRIGGER_URL=${TRIGGER_URL-http://localhost}
# APP_WEB_URL=
# FILES_URL=
# INTERNAL_FILES_URL=
ENDPOINT_URL_TEMPLATE=${ENDPOINT_URL_TEMPLATE-http://localhost/e/{hook_id}}
# DEPLOY_ENV=PRODUCTION
# DEPLOYMENT_EDITION=COMMUNITY
MIGRATION_ENABLED=${MIGRATION_ENABLED-true}
# LANG=C.UTF-8
# LC_ALL=C.UTF-8
# PYTHONIOENCODING=utf-8
# CHECK_UPDATE_URL=https://updates.dify.ai
# OPENAI_API_BASE=https://api.openai.com/v1
# Nacos remote settings source HTTP timeouts (seconds).
# Bound how long requests to the Nacos endpoint wait before failing, so a slow or
# unresponsive Nacos server cannot stall API startup or token refresh.
# DIFY_ENV_NACOS_REQUEST_TIMEOUT=10.0
# DIFY_ENV_NACOS_CONNECT_TIMEOUT=3.0
# ------------------------------
# System features and account access
# ------------------------------
# MARKETPLACE_ENABLED=true
# ENABLE_EMAIL_CODE_LOGIN=false
# EMAIL_CODE_LOGIN_TOKEN_EXPIRY_MINUTES=5
# EMAIL_CODE_LOGIN_MAX_ATTEMPTS=5
# ENABLE_EMAIL_PASSWORD_LOGIN=true
# ENABLE_SOCIAL_OAUTH_LOGIN=false
# Remove `collaboration` from COMPOSE_PROFILES to stop the dedicated websocket service.
# ENABLE_COLLABORATION_MODE=true
# ALLOW_REGISTER=false
# ALLOW_CREATE_WORKSPACE=false
# ENABLE_CHANGE_EMAIL=true
# ENABLE_TRIAL_APP=false
# ENABLE_EXPLORE_BANNER=false
# ENABLE_LEARN_APP=true
# ENABLE_STEP_BY_STEP_TOUR=false
# ENABLE_SKILL=true
# RBAC_ENABLED=false
# ENABLE_LICENSE_EXPIRY_NOTICE=true
# ACCESS_TOKEN_EXPIRE_MINUTES=60
# REFRESH_TOKEN_EXPIRE_DAYS=30
# INVITE_EXPIRY_HOURS=72
# WEB_API_CORS_ALLOW_ORIGINS=*
CONSOLE_CORS_ALLOW_ORIGINS=${CONSOLE_CORS_ALLOW_ORIGINS-*}
# COOKIE_DOMAIN=
# ------------------------------
# API and Celery Docker defaults
# ------------------------------
# Unset values use these Docker defaults; an explicit empty value remains an override.
SERVER_WORKER_CLASS=${SERVER_WORKER_CLASS-gevent}
GUNICORN_TIMEOUT=${GUNICORN_TIMEOUT-360}
CELERY_WORKER_AMOUNT=${CELERY_WORKER_AMOUNT-4}
# ------------------------------
# Celery broker and KnowledgeFS dispatch
# ------------------------------
# Broker URL defaults/mappings live in api.defaults, worker.defaults and worker-beat.defaults.
# Set a common CELERY_BROKER_URL override in shared.env or docker/.env for every producer/consumer.
# Optional long-running KnowledgeFS Celery rollout: set identically in every API, worker and Beat
# process sharing this Redis broker. It must exceed the KnowledgeFS hard task limit (7230s by
# default). Keep unset to preserve Celery's existing default when this rollout is disabled.
# CELERY_BROKER_VISIBILITY_TIMEOUT=10800
# CELERY_TASK_ANNOTATIONS=null
# CELERY_SENTINEL_PASSWORD=
# CELERY_BACKEND=redis
# CELERY_USE_SENTINEL=false
# CELERY_SENTINEL_MASTER_NAME=
# CELERY_SENTINEL_SOCKET_TIMEOUT=0.1
# KNOWLEDGE_FS_BACKGROUND_WORKER_ENABLED=true
# KNOWLEDGE_FS_BACKGROUND_POLL_INTERVAL_SECONDS=5
# ------------------------------
# Database and Redis connections
# ------------------------------
DB_HOST=${DB_HOST-db_postgres}
DB_USERNAME=${DB_USERNAME-postgres}
DB_PASSWORD=${DB_PASSWORD-difyai123456}
DB_PORT=${DB_PORT-5432}
REDIS_HOST=${REDIS_HOST-redis}
REDIS_PASSWORD=${REDIS_PASSWORD-difyai123456}
REDIS_PORT=${REDIS_PORT-6379}
REDIS_KEEPALIVE=${REDIS_KEEPALIVE-true}
# ------------------------------
# Logging, traces and telemetry
# ------------------------------
# LOG_LEVEL=INFO
# LOG_OUTPUT_FORMAT=text
LOG_FILE=${LOG_FILE-/app/logs/server.log}
# LOG_FILE_MAX_SIZE=20
# LOG_FILE_BACKUP_COUNT=5
LOG_DATEFORMAT=${LOG_DATEFORMAT-%Y-%m-%d %H:%M:%S}
# LOG_TZ=UTC
# DEBUG=false
# FLASK_DEBUG=false
# ENABLE_REQUEST_LOGGING=False
# Application-level Agent tracing; also enable the collector in dify-agent.env.
# OPS_AGENT_TRACE_ENABLED=false
# ENABLE_APPLICATION_TRACE_RECONCILE_TASK=true
# Shared by API, workers, and Beat. Keep separate from legacy ops_trace during upgrades.
# OPS_TRACE_QUEUE=ops_trace_v2
# Attempts to send one trace while its provider is temporarily unavailable.
# OPS_TRACE_EXPORT_MAX_ATTEMPTS=6
# Daily cleanup of trace payloads an interrupted delivery left in storage.
# ENABLE_TRACE_PAYLOAD_SWEEP_TASK=true
# ENABLE_OTEL=false
# OTLP_TRACE_ENDPOINT=
# OTLP_METRIC_ENDPOINT=
# OTLP_BASE_ENDPOINT=http://localhost:4318
# OTEL_EXPORTER_OTLP_PROTOCOL=
# OTEL_EXPORTER_TYPE=otlp
# OTEL_SAMPLING_RATE=0.1
# OTEL_BATCH_EXPORT_SCHEDULE_DELAY=5000
# OTEL_MAX_QUEUE_SIZE=2048
# OTEL_MAX_EXPORT_BATCH_SIZE=512
# OTEL_METRIC_EXPORT_INTERVAL=60000
# OTEL_BATCH_EXPORT_TIMEOUT=10000
# OTEL_METRIC_EXPORT_TIMEOUT=30000
# ------------------------------
# Uploads, parsing and package limits
# ------------------------------
# These parser settings are for Dify; knowledge-fs.env configures the separate KnowledgeFS parser client.
# FILES_ACCESS_TIMEOUT=300
# UPLOAD_FILE_SIZE_LIMIT=15
# KNOWLEDGE_UPLOAD_FILE_SIZE_LIMIT_FOR_PAID_PLAN=15
# UPLOAD_FILE_BATCH_LIMIT=5
# UPLOAD_FILE_EXTENSION_BLACKLIST=
# SINGLE_CHUNK_ATTACHMENT_LIMIT=10
# IMAGE_FILE_BATCH_LIMIT=10
# ATTACHMENT_IMAGE_FILE_SIZE_LIMIT=2
# ATTACHMENT_IMAGE_DOWNLOAD_TIMEOUT=60
# ETL_TYPE=dify
# UNSTRUCTURED_API_URL=
# MULTIMODAL_SEND_FORMAT=base64
# UPLOAD_IMAGE_FILE_SIZE_LIMIT=10
# UPLOAD_VIDEO_FILE_SIZE_LIMIT=100
# UPLOAD_AUDIO_FILE_SIZE_LIMIT=50
# UPLOAD_SKILL_FILE_SIZE_LIMIT=50
# SKILL_PACKAGE_MAX_UNCOMPRESSED_BYTES=209715200
# SKILL_PACKAGE_MAX_ENTRIES=5000
# SKILL_PACKAGE_MAX_SKILL_MD_BYTES=1048576
# AGENT_PACKAGE_MAX_BYTES=536870912
# AGENT_PACKAGE_MAX_MANIFEST_BYTES=5242880
# AGENT_PACKAGE_MAX_ENTRIES=5000
# APP_PACKAGE_MAX_WORKFLOW_TOOLS=20
# SCARF_NO_ANALYTICS=true
# ANNOTATION_IMPORT_FILE_SIZE_LIMIT=2
# ANNOTATION_IMPORT_MAX_RECORDS=10000
# ANNOTATION_IMPORT_MIN_RECORDS=1
# ANNOTATION_IMPORT_RATE_LIMIT_PER_MINUTE=5
# ANNOTATION_IMPORT_RATE_LIMIT_PER_HOUR=20
# ANNOTATION_IMPORT_MAX_CONCURRENT=5
# ------------------------------
# Plugin clients and marketplace
# ------------------------------
# Set PLUGIN_DAEMON_KEY in docker/.env; the daemon, API, workers, and Agent must use the same key.
# Set PLUGIN_DIFY_INNER_API_KEY in docker/.env; the API, daemon, workers, Agent and KnowledgeFS share it.
# Keep the PLUGIN_DAEMON_KEY expression below unchanged in the copy.
PLUGIN_DAEMON_URL=${PLUGIN_DAEMON_URL-http://plugin_daemon:5002}
PLUGIN_DAEMON_KEY=${PLUGIN_DAEMON_KEY-lYkiYYT6owG+71oLerGzA7GXCgOT++6ovaezWAjpCjf+Sjc3ZtU+qUEi}
PLUGIN_MAX_PACKAGE_SIZE=${PLUGIN_MAX_PACKAGE_SIZE-52428800}
# PLUGIN_MAX_FILE_SIZE=52428800
# PLUGIN_MODEL_SCHEMA_CACHE_TTL=3600
# PLUGIN_MODEL_PROVIDERS_CACHE_ENABLED=true
# PLUGIN_MODEL_PROVIDERS_CACHE_TTL=86400
# Comma-separated marketplace plugin IDs whose latest versions are installed for newly registered users.
# Example: langgenius/openai,langgenius/gemini
# NEW_USER_DEFAULT_PLUGIN_IDS=
# Comma-separated model_type:provider:model entries assigned after default plugins finish installing.
# Example: llm:langgenius/openai/openai:gpt-4o-mini,text-embedding:langgenius/openai/openai:text-embedding-3-small
# NEW_USER_DEFAULT_MODELS=
# POSITION_TOOL_PINS=
# POSITION_TOOL_INCLUDES=
# POSITION_TOOL_EXCLUDES=
# POSITION_PROVIDER_PINS=
# POSITION_PROVIDER_INCLUDES=
# POSITION_PROVIDER_EXCLUDES=
# CREATORS_PLATFORM_FEATURES_ENABLED=true
# CREATORS_PLATFORM_API_URL=https://creators.dify.ai
# CREATORS_PLATFORM_OAUTH_CLIENT_ID=
# ------------------------------
# Agent clients and execution
# ------------------------------
AGENT_BACKEND_BASE_URL=${AGENT_BACKEND_BASE_URL-http://agent_backend:5050}
NEXT_PUBLIC_ENABLE_AGENT_V2=${NEXT_PUBLIC_ENABLE_AGENT_V2-true}
# Agent backend client settings shared by API and worker processes.
# AGENT_BACKEND_STREAM_READ_TIMEOUT_SECONDS=30
# AGENT_BACKEND_STREAM_MAX_RECONNECTS=3
# Client timeout for Agent backend calls that may carry a Home Snapshot transfer.
# Must stay above DIFY_AGENT_ENTERPRISE_SANDBOX_SNAPSHOT_TIMEOUT on the Agent backend.
# AGENT_BACKEND_HOME_SNAPSHOT_TIMEOUT_SECONDS=45
# Independent E2B accounting, collected only by API Celery Beat/workers.
# Uses OPS_TRACE_QUEUE; business binding operations never call metering.
# Enable after migrations. START_AT is an immutable, whole-second UTC T0.
# AGENT_SANDBOX_METERING_ENABLED=false
# AGENT_SANDBOX_METERING_PROJECT_ID=
# AGENT_SANDBOX_METERING_START_AT=
# AGENT_SANDBOX_METERING_INTERVAL_SECONDS=60
# APP_DEFAULT_ACTIVE_REQUESTS=0
# APP_MAX_ACTIVE_REQUESTS=0
# Outer execution limit for Agent Apps. Agent Backend may stop the internal
# model/tool loop sooner when DIFY_AGENT_RUN_TIMEOUT_SECONDS is lower.
# APP_MAX_EXECUTION_TIME=3600
# ------------------------------
# Code execution and template transformation
# ------------------------------
# CODE_EXECUTION_ENDPOINT=http://sandbox:8194
# CODE_EXECUTION_SSL_VERIFY=True
# CODE_EXECUTION_POOL_MAX_CONNECTIONS=100
# CODE_EXECUTION_POOL_MAX_KEEPALIVE_CONNECTIONS=20
# CODE_EXECUTION_POOL_KEEPALIVE_EXPIRY=5.0
# CODE_MAX_NUMBER=9223372036854775807
# CODE_MIN_NUMBER=-9223372036854775808
# CODE_MAX_DEPTH=5
# CODE_MAX_PRECISION=20
# CODE_MAX_STRING_LENGTH=400000
# CODE_MAX_STRING_ARRAY_LENGTH=30
# CODE_MAX_OBJECT_ARRAY_LENGTH=30
# CODE_MAX_NUMBER_ARRAY_LENGTH=1000
# CODE_EXECUTION_CONNECT_TIMEOUT=10
# CODE_EXECUTION_READ_TIMEOUT=60
# CODE_EXECUTION_WRITE_TIMEOUT=10
# TEMPLATE_TRANSFORM_MAX_LENGTH=400000
# ------------------------------
# Workflow and HTTP request limits
# ------------------------------
# WORKFLOW_MAX_EXECUTION_STEPS=500
# Outer execution limit for Workflow and Chatflow callers. Agent Backend may
# stop the internal model/tool loop sooner when its run timeout is lower.
# To allow all Agent call paths to run for one hour, set this value,
# APP_MAX_EXECUTION_TIME, and DIFY_AGENT_RUN_TIMEOUT_SECONDS to at least 3600.
# WORKFLOW_MAX_EXECUTION_TIME=3600
# WORKFLOW_CALL_MAX_DEPTH=5
# MAX_VARIABLE_SIZE=204800
# WORKFLOW_GENERATOR_NODE_BUILDER_MAX_WORKERS=6
# WORKFLOW_FILE_UPLOAD_LIMIT=10
# GRAPH_ENGINE_MAX_WORKERS=10
# API_TOOL_DEFAULT_CONNECT_TIMEOUT=10
# API_TOOL_DEFAULT_READ_TIMEOUT=60
# WEBHOOK_REQUEST_BODY_MAX_SIZE=10485760
# HTTP_REQUEST_NODE_MAX_BINARY_SIZE=10485760
# HTTP_REQUEST_NODE_MAX_TEXT_SIZE=1048576
# HTTP_REQUEST_NODE_SSL_VERIFY=True
# HTTP_REQUEST_MAX_CONNECT_TIMEOUT=10
# HTTP_REQUEST_MAX_READ_TIMEOUT=600
# HTTP_REQUEST_MAX_WRITE_TIMEOUT=600
# DSL_EXPORT_ENCRYPT_DATASET_ID=true
# DATASET_MAX_SEGMENTS_PER_REQUEST=0
# ------------------------------
# Workflow storage and retention
# ------------------------------
# WORKFLOW_NODE_EXECUTION_STORAGE=rdbms
# CORE_WORKFLOW_EXECUTION_REPOSITORY=core.repositories.sqlalchemy_workflow_execution_repository.SQLAlchemyWorkflowExecutionRepository
# CORE_WORKFLOW_NODE_EXECUTION_REPOSITORY=core.repositories.sqlalchemy_workflow_node_execution_repository.SQLAlchemyWorkflowNodeExecutionRepository
# API_WORKFLOW_RUN_REPOSITORY=repositories.sqlalchemy_api_workflow_run_repository.DifyAPISQLAlchemyWorkflowRunRepository
# API_WORKFLOW_NODE_EXECUTION_REPOSITORY=repositories.sqlalchemy_api_workflow_node_execution_repository.DifyAPISQLAlchemyWorkflowNodeExecutionRepository
# WORKFLOW_LOG_CLEANUP_ENABLED=false
# WORKFLOW_LOG_RETENTION_DAYS=30
# WORKFLOW_LOG_CLEANUP_BATCH_SIZE=100
# WORKFLOW_LOG_CLEANUP_SPECIFIC_WORKFLOW_IDS=
# ALIYUN_SLS_ENDPOINT=
# ALIYUN_SLS_REGION=
# ALIYUN_SLS_PROJECT_NAME=
# ALIYUN_SLS_LOGSTORE_TTL=365
# LOGSTORE_DUAL_WRITE_ENABLED=false
# LOGSTORE_DUAL_READ_ENABLED=true
# LOGSTORE_ENABLE_PUT_GRAPH_FIELD=true
# ------------------------------
# Scheduled tasks and queue monitoring (API, workers and Beat)
# ------------------------------
# ENABLE_CLEAN_EMBEDDING_CACHE_TASK=false
# ENABLE_CLEAN_UNUSED_DATASETS_TASK=false
# ENABLE_CREATE_TIDB_SERVERLESS_TASK=false
# ENABLE_UPDATE_TIDB_SERVERLESS_STATUS_TASK=false
# ENABLE_CLEAN_MESSAGES=false
# ENABLE_WORKFLOW_RUN_CLEANUP_TASK=false
# ENABLE_MAIL_CLEAN_DOCUMENT_NOTIFY_TASK=false
# ENABLE_DATASETS_QUEUE_MONITOR=false
# ENABLE_CHECK_UPGRADABLE_PLUGIN_TASK=true
# ENABLE_WORKFLOW_SCHEDULE_POLLER_TASK=true
# WORKFLOW_SCHEDULE_POLLER_INTERVAL=1
# WORKFLOW_SCHEDULE_POLLER_BATCH_SIZE=100
# WORKFLOW_SCHEDULE_MAX_DISPATCH_PER_TICK=0
# TENANT_ISOLATED_TASK_CONCURRENCY=1
# QUEUE_MONITOR_THRESHOLD=200
# QUEUE_MONITOR_ALERT_EMAILS=
# QUEUE_MONITOR_INTERVAL=30
# HUMAN_INPUT_IM_EVENT_TRANSPORT_MODE=WEBHOOK
# ENABLE_HUMAN_INPUT_TIMEOUT_TASK=true
# HUMAN_INPUT_TIMEOUT_TASK_INTERVAL=1
# ENABLE_CONVERSATION_CLEANUP_TASK=true
# CONVERSATION_CLEANUP_TASK_INTERVAL=5
# CONVERSATION_CLEANUP_BATCH_SIZE=100
# Expired sandbox records are cleaned by API/Celery, not the sandbox container.
# SANDBOX_EXPIRED_RECORDS_CLEAN_GRACEFUL_PERIOD=21
# SANDBOX_EXPIRED_RECORDS_CLEAN_BATCH_SIZE=1000
# SANDBOX_EXPIRED_RECORDS_CLEAN_BATCH_MAX_INTERVAL=200
# SANDBOX_EXPIRED_RECORDS_RETENTION_DAYS=30
# SANDBOX_EXPIRED_RECORDS_CLEAN_TASK_LOCK_TTL=90000
# CREATE_TIDB_SERVICE_JOB_ENABLED=false
# MAX_SUBMIT_COUNT=100
# ------------------------------
# Email and Notion integrations
# ------------------------------
# NOTION_INTEGRATION_TYPE=public
# NOTION_CLIENT_ID=
# MAIL_TYPE=resend
# MAIL_DEFAULT_SEND_FROM=
# RESEND_API_URL=https://api.resend.com
# SMTP_SERVER=
# SMTP_PORT=465
# SMTP_USERNAME=
# SMTP_USE_TLS=true
# SMTP_OPPORTUNISTIC_TLS=false
# SMTP_LOCAL_HOSTNAME=
# ------------------------------
# SSRF proxy clients
# ------------------------------
# Client timeouts/pool limits and Squid settings: ../infrastructure/ssrf-proxy.defaults.
SSRF_PROXY_HTTP_URL=${SSRF_PROXY_HTTP_URL-http://ssrf_proxy:3128}
SSRF_PROXY_HTTPS_URL=${SSRF_PROXY_HTTPS_URL-http://ssrf_proxy:3128}
# ------------------------------
# Storage and encryption providers
# ------------------------------
# Application storage settings below also serve workers; plugin-daemon.defaults configures plugin storage separately.
# STORAGE_TYPE=opendal
# KEY_PROVIDER_TYPE=local
# OPENDAL_SCHEME=fs
OPENDAL_FS_ROOT=${OPENDAL_FS_ROOT-storage}
# AZURE_KEYVAULT_VAULT_URL=
# AZURE_KEYVAULT_KEY_SIZE=2048
# AZURE_KEYVAULT_ROTATION_INTERVAL_DAYS=
# ------------------------------
# Amazon S3 and archive storage
# ------------------------------
# S3_ENDPOINT=
# S3_REGION=us-east-1
# S3_BUCKET_NAME=difyai
# S3_ACCESS_KEY=
# S3_SECRET_KEY=
# S3_ADDRESS_STYLE=auto
# S3_USE_AWS_MANAGED_IAM=false
# ARCHIVE_STORAGE_ENABLED=false
# ARCHIVE_STORAGE_ENDPOINT=
# ARCHIVE_STORAGE_ARCHIVE_BUCKET=
# ARCHIVE_STORAGE_EXPORT_BUCKET=
# ARCHIVE_STORAGE_REGION=auto
# ARCHIVE_STORAGE_ACCESS_KEY=
# ARCHIVE_STORAGE_SECRET_KEY=
# ARCHIVE_STORAGE_ADDRESS_STYLE=path
# ------------------------------
# Azure Blob and Google Cloud Storage
# ------------------------------
# AZURE_BLOB_ACCOUNT_URL=https://<your_account_name>.blob.core.windows.net
# AZURE_BLOB_ACCOUNT_NAME=difyai
# AZURE_BLOB_ACCOUNT_KEY=difyai
# AZURE_BLOB_CONTAINER_NAME=difyai-container
# GOOGLE_STORAGE_BUCKET_NAME=your-bucket-name
# GOOGLE_STORAGE_SERVICE_ACCOUNT_JSON_BASE64=
# ------------------------------
# Aliyun OSS, Tencent COS and Volcengine TOS
# ------------------------------
# ALIYUN_OSS_BUCKET_NAME=your-bucket-name
# ALIYUN_OSS_ENDPOINT=https://oss-ap-southeast-1-internal.aliyuncs.com
# ALIYUN_OSS_REGION=ap-southeast-1
# ALIYUN_OSS_ACCESS_KEY=your-access-key
# ALIYUN_OSS_SECRET_KEY=your-secret-key
# ALIYUN_OSS_AUTH_VERSION=v4
# ALIYUN_OSS_PATH=your-path
# ALIYUN_CLOUDBOX_ID=your-cloudbox-id
# TENCENT_COS_BUCKET_NAME=your-bucket-name
# TENCENT_COS_REGION=your-region
# TENCENT_COS_SECRET_KEY=your-secret-key
# TENCENT_COS_SECRET_ID=your-secret-id
# TENCENT_COS_SCHEME=your-scheme
# TENCENT_COS_CUSTOM_DOMAIN=your-custom-domain
# VOLCENGINE_TOS_BUCKET_NAME=your-bucket-name
# VOLCENGINE_TOS_ENDPOINT=your-server-url
# VOLCENGINE_TOS_REGION=your-region
# VOLCENGINE_TOS_SECRET_KEY=your-secret-key
# VOLCENGINE_TOS_ACCESS_KEY=your-access-key
# ------------------------------
# OCI, Huawei OBS, Baidu OBS and Supabase storage
# ------------------------------
# OCI_ENDPOINT=https://your-object-storage-namespace.compat.objectstorage.us-ashburn-1.oraclecloud.com
# OCI_BUCKET_NAME=your-bucket-name
# OCI_REGION=us-ashburn-1
# OCI_ACCESS_KEY=your-access-key
# OCI_SECRET_KEY=your-secret-key
# HUAWEI_OBS_BUCKET_NAME=your-bucket-name
# HUAWEI_OBS_SERVER=your-server-url
# HUAWEI_OBS_SECRET_KEY=your-secret-key
# HUAWEI_OBS_ACCESS_KEY=your-access-key
# HUAWEI_OBS_PATH_STYLE=false
# BAIDU_OBS_BUCKET_NAME=your-bucket-name
# BAIDU_OBS_ENDPOINT=your-server-url
# BAIDU_OBS_SECRET_KEY=your-secret-key
# BAIDU_OBS_ACCESS_KEY=your-access-key
# SUPABASE_URL=your-server-url
# SUPABASE_BUCKET_NAME=your-bucket-name
# SUPABASE_API_KEY=your-access-key
# ------------------------------
# ClickZetta storage and vector search
# ------------------------------
# CLICKZETTA_USERNAME=
# CLICKZETTA_PASSWORD=
# CLICKZETTA_INSTANCE=
# CLICKZETTA_SERVICE=api.clickzetta.com
# CLICKZETTA_WORKSPACE=quick_start
# CLICKZETTA_VCLUSTER=default_ap
# CLICKZETTA_SCHEMA=dify
# CLICKZETTA_BATCH_SIZE=100
# CLICKZETTA_ENABLE_INVERTED_INDEX=true
# CLICKZETTA_ANALYZER_TYPE=chinese
# CLICKZETTA_ANALYZER_MODE=smart
# CLICKZETTA_VECTOR_DISTANCE_FUNCTION=cosine_distance
# CLICKZETTA_VOLUME_TYPE=user
# CLICKZETTA_VOLUME_NAME=
# CLICKZETTA_VOLUME_TABLE_PREFIX=dataset_
# CLICKZETTA_VOLUME_DIFY_PREFIX=dify_km
# ------------------------------
# Vector store selection and Docker connection defaults
# ------------------------------
# Provider client options live in ../vectorstores/{weaviate,qdrant,oceanbase,pgvector}.defaults
# and ../vectorstores/milvus.env.example. Their .env overrides reach API, workers and Beat.
# KnowledgeFS uses the API vector bridge, not its own vector provider connection.
VECTOR_STORE=${VECTOR_STORE-weaviate}
# Prefix used to create collection names in the vector database.
# VECTOR_INDEX_NAME_PREFIX=Vector_index
WEAVIATE_ENDPOINT=${WEAVIATE_ENDPOINT-http://weaviate:8080}
WEAVIATE_API_KEY=${WEAVIATE_API_KEY-WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih}
WEAVIATE_GRPC_ENDPOINT=${WEAVIATE_GRPC_ENDPOINT-grpc://weaviate:50051}
# ------------------------------
# TiDB and TiDB on Qdrant
# ------------------------------
# TIDB_VECTOR_HOST=tidb
# TIDB_VECTOR_PORT=4000
# TIDB_VECTOR_USER=
# TIDB_VECTOR_DATABASE=dify
# TIDB_VECTOR_ENABLE_FULLTEXT_SEARCH=false
# TIDB_ON_QDRANT_URL=http://127.0.0.1
# TIDB_ON_QDRANT_CLIENT_TIMEOUT=20
# TIDB_ON_QDRANT_GRPC_ENABLED=false
# TIDB_ON_QDRANT_GRPC_PORT=6334
# TIDB_ON_QDRANT_ESTIMATED_STORAGE_LIMITS_MB=sandbox:60,professional:6400,team:25600
# TIDB_API_URL=http://127.0.0.1
# TIDB_IAM_API_URL=http://127.0.0.1
# TIDB_REGION=regions/aws-us-east-1
# TIDB_PROJECT_ID=dify
# TIDB_SPEND_LIMIT=100
# ------------------------------
# Tencent and Baidu vector databases
# ------------------------------
# TENCENT_VECTOR_DB_URL=http://127.0.0.1
# TENCENT_VECTOR_DB_TIMEOUT=30
# TENCENT_VECTOR_DB_USERNAME=dify
# TENCENT_VECTOR_DB_DATABASE=dify
# TENCENT_VECTOR_DB_SHARD=1
# TENCENT_VECTOR_DB_REPLICAS=2
# TENCENT_VECTOR_DB_ENABLE_HYBRID_SEARCH=false
# BAIDU_VECTOR_DB_ENDPOINT=http://127.0.0.1:5287
# BAIDU_VECTOR_DB_CONNECTION_TIMEOUT_MS=30000
# BAIDU_VECTOR_DB_ACCOUNT=root
# BAIDU_VECTOR_DB_DATABASE=dify
# BAIDU_VECTOR_DB_SHARD=1
# BAIDU_VECTOR_DB_REPLICAS=3
# BAIDU_VECTOR_DB_INVERTED_INDEX_ANALYZER=DEFAULT_ANALYZER
# BAIDU_VECTOR_DB_INVERTED_INDEX_PARSER_MODE=COARSE_MODE
# BAIDU_VECTOR_DB_AUTO_BUILD_ROW_COUNT_INCREMENT=500
# BAIDU_VECTOR_DB_AUTO_BUILD_ROW_COUNT_INCREMENT_RATIO=0.05
# BAIDU_VECTOR_DB_REBUILD_INDEX_TIMEOUT_IN_SECONDS=300
# ------------------------------
# Lindorm, Huawei Cloud, Upstash and Tablestore
# ------------------------------
# LINDORM_URL=http://localhost:30070
# LINDORM_USERNAME=admin
# LINDORM_USING_UGC=True
# LINDORM_QUERY_TIMEOUT=1
# HUAWEI_CLOUD_HOSTS=https://127.0.0.1:9200
# HUAWEI_CLOUD_USER=admin
# UPSTASH_VECTOR_URL=https://xxx-vector.upstash.io
# TABLESTORE_ENDPOINT=https://instance-name.cn-hangzhou.ots.aliyuncs.com
# TABLESTORE_INSTANCE_NAME=instance-name
# TABLESTORE_NORMALIZE_FULLTEXT_BM25_SCORE=false
# ------------------------------
# AnalyticDB, Alibaba Cloud MySQL and Relyt
# ------------------------------
# ANALYTICDB_REGION_ID=cn-hangzhou
# ANALYTICDB_INSTANCE_ID=gp-ab123456
# ANALYTICDB_ACCOUNT=testaccount
# ANALYTICDB_NAMESPACE=dify
# ANALYTICDB_HOST=gp-test.aliyuncs.com
# ANALYTICDB_PORT=5432
# ANALYTICDB_MIN_CONNECTION=1
# ANALYTICDB_MAX_CONNECTION=5
# ALIBABACLOUD_MYSQL_HOST=127.0.0.1
# ALIBABACLOUD_MYSQL_PORT=3306
# ALIBABACLOUD_MYSQL_USER=root
# ALIBABACLOUD_MYSQL_DATABASE=dify
# ALIBABACLOUD_MYSQL_MAX_CONNECTION=5
# ALIBABACLOUD_MYSQL_HNSW_M=6
# RELYT_HOST=db
# RELYT_PORT=5432
# RELYT_USER=postgres
# RELYT_DATABASE=postgres
# ------------------------------
# VikingDB and Hologres
# ------------------------------
# VIKINGDB_REGION=cn-shanghai
# VIKINGDB_HOST=api-vikingdb.xxx.volces.com
# VIKINGDB_SCHEME=http
# VIKINGDB_CONNECTION_TIMEOUT=30
# VIKINGDB_SOCKET_TIMEOUT=30
# HOLOGRES_HOST=
# HOLOGRES_PORT=80
# HOLOGRES_DATABASE=
# HOLOGRES_ACCESS_KEY_ID=
# HOLOGRES_ACCESS_KEY_SECRET=
# HOLOGRES_SCHEMA=public
# HOLOGRES_TOKENIZER=jieba
# HOLOGRES_DISTANCE_METHOD=Cosine
# HOLOGRES_BASE_QUANTIZATION_TYPE=rabitq
# HOLOGRES_MAX_DEGREE=64
# HOLOGRES_EF_CONSTRUCTION=400
@@ -1,574 +0,0 @@
# ------------------------------
# Shared API/Worker Configuration
# ------------------------------
CONSOLE_WEB_URL=
SERVICE_API_URL=
TRIGGER_URL=http://localhost
HUMAN_INPUT_IM_EVENT_TRANSPORT_MODE=WEBHOOK
APP_WEB_URL=
FILES_URL=
INTERNAL_FILES_URL=
LANG=C.UTF-8
LC_ALL=C.UTF-8
PYTHONIOENCODING=utf-8
CHECK_UPDATE_URL=https://updates.dify.ai
OPENAI_API_BASE=https://api.openai.com/v1
MIGRATION_ENABLED=true
FILES_ACCESS_TIMEOUT=300
# System Features
MARKETPLACE_ENABLED=true
ENABLE_EMAIL_CODE_LOGIN=false
EMAIL_CODE_LOGIN_TOKEN_EXPIRY_MINUTES=5
EMAIL_CODE_LOGIN_MAX_ATTEMPTS=5
ENABLE_EMAIL_PASSWORD_LOGIN=true
ENABLE_SOCIAL_OAUTH_LOGIN=false
# Remove `collaboration` from COMPOSE_PROFILES to stop the dedicated websocket service.
ENABLE_COLLABORATION_MODE=true
ALLOW_REGISTER=false
ALLOW_CREATE_WORKSPACE=false
ENABLE_CHANGE_EMAIL=true
ENABLE_TRIAL_APP=false
ENABLE_EXPLORE_BANNER=false
ENABLE_LEARN_APP=true
ENABLE_STEP_BY_STEP_TOUR=false
ENABLE_SKILL=true
RBAC_ENABLED=false
ENABLE_LICENSE_EXPIRY_NOTICE=true
CELERY_BROKER_URL=redis://:difyai123456@redis:6379/1
# Optional long-running KnowledgeFS Celery rollout: set identically in every API, worker and Beat
# process sharing this Redis broker. It must exceed the KnowledgeFS hard task limit (7230s by
# default). Keep unset to preserve Celery's existing default when this rollout is disabled.
# CELERY_BROKER_VISIBILITY_TIMEOUT=10800
# KNOWLEDGE_FS_BACKGROUND_WORKER_ENABLED=true
# KNOWLEDGE_FS_BACKGROUND_POLL_INTERVAL_SECONDS=5
CELERY_TASK_ANNOTATIONS=null
AZURE_BLOB_ACCOUNT_URL=https://<your_account_name>.blob.core.windows.net
SUPABASE_URL=your-server-url
TIDB_ON_QDRANT_URL=http://127.0.0.1
TIDB_ON_QDRANT_API_KEY=dify
TIDB_API_URL=http://127.0.0.1
TIDB_IAM_API_URL=http://127.0.0.1
TIDB_REGION=regions/aws-us-east-1
TIDB_PROJECT_ID=dify
TIDB_SPEND_LIMIT=100
TENCENT_VECTOR_DB_URL=http://127.0.0.1
TENCENT_VECTOR_DB_API_KEY=dify
LINDORM_URL=http://localhost:30070
LINDORM_USERNAME=admin
UPSTASH_VECTOR_URL=https://xxx-vector.upstash.io
UPLOAD_FILE_SIZE_LIMIT=15
KNOWLEDGE_UPLOAD_FILE_SIZE_LIMIT_FOR_PAID_PLAN=15
UPLOAD_FILE_BATCH_LIMIT=5
UPLOAD_FILE_EXTENSION_BLACKLIST=
SINGLE_CHUNK_ATTACHMENT_LIMIT=10
IMAGE_FILE_BATCH_LIMIT=10
ATTACHMENT_IMAGE_FILE_SIZE_LIMIT=2
ATTACHMENT_IMAGE_DOWNLOAD_TIMEOUT=60
ETL_TYPE=dify
UNSTRUCTURED_API_URL=
MULTIMODAL_SEND_FORMAT=base64
UPLOAD_IMAGE_FILE_SIZE_LIMIT=10
UPLOAD_VIDEO_FILE_SIZE_LIMIT=100
UPLOAD_AUDIO_FILE_SIZE_LIMIT=50
UPLOAD_SKILL_FILE_SIZE_LIMIT=50
SKILL_PACKAGE_MAX_UNCOMPRESSED_BYTES=209715200
SKILL_PACKAGE_MAX_ENTRIES=5000
SKILL_PACKAGE_MAX_SKILL_MD_BYTES=1048576
AGENT_PACKAGE_MAX_BYTES=536870912
AGENT_PACKAGE_MAX_MANIFEST_BYTES=5242880
AGENT_PACKAGE_MAX_ENTRIES=5000
APP_PACKAGE_MAX_WORKFLOW_TOOLS=20
API_SENTRY_DSN=
API_SENTRY_TRACES_SAMPLE_RATE=1.0
API_SENTRY_PROFILES_SAMPLE_RATE=1.0
WEB_SENTRY_DSN=
PLUGIN_SENTRY_ENABLED=false
PLUGIN_SENTRY_DSN=
NOTION_INTEGRATION_TYPE=public
RESEND_API_URL=https://api.resend.com
SSRF_PROXY_HTTP_URL=http://ssrf_proxy:3128
SSRF_PROXY_HTTPS_URL=http://ssrf_proxy:3128
PGDATA=/var/lib/postgresql/data/pgdata
PLUGIN_MAX_PACKAGE_SIZE=52428800
PLUGIN_MAX_FILE_SIZE=52428800
PLUGIN_MODEL_SCHEMA_CACHE_TTL=3600
PLUGIN_MODEL_PROVIDERS_CACHE_ENABLED=true
PLUGIN_MODEL_PROVIDERS_CACHE_TTL=86400
# Comma-separated marketplace plugin IDs whose latest versions are installed for newly registered users.
# Example: langgenius/openai,langgenius/gemini
NEW_USER_DEFAULT_PLUGIN_IDS=
# Comma-separated model_type:provider:model entries assigned after default plugins finish installing.
# Example: llm:langgenius/openai/openai:gpt-4o-mini,text-embedding:langgenius/openai/openai:text-embedding-3-small
NEW_USER_DEFAULT_MODELS=
ENDPOINT_URL_TEMPLATE=http://localhost/e/{hook_id}
LOG_LEVEL=INFO
LOG_OUTPUT_FORMAT=text
LOG_FILE=/app/logs/server.log
LOG_FILE_MAX_SIZE=20
LOG_FILE_BACKUP_COUNT=5
LOG_DATEFORMAT=%Y-%m-%d %H:%M:%S
LOG_TZ=UTC
DEBUG=false
FLASK_DEBUG=false
ENABLE_REQUEST_LOGGING=False
# Application-level Agent tracing; also enable the collector in dify-agent.env.
OPS_AGENT_TRACE_ENABLED=false
ENABLE_APPLICATION_TRACE_RECONCILE_TASK=true
# Shared by API, workers, and Beat. Keep separate from legacy ops_trace during upgrades.
OPS_TRACE_QUEUE=ops_trace_v2
# Attempts to send one trace while its provider is temporarily unavailable.
OPS_TRACE_EXPORT_MAX_ATTEMPTS=6
# Daily cleanup of trace payloads an interrupted delivery left in storage.
ENABLE_TRACE_PAYLOAD_SWEEP_TASK=true
WORKFLOW_LOG_CLEANUP_ENABLED=false
WORKFLOW_LOG_RETENTION_DAYS=30
WORKFLOW_LOG_CLEANUP_BATCH_SIZE=100
WORKFLOW_LOG_CLEANUP_SPECIFIC_WORKFLOW_IDS=
EXPOSE_PLUGIN_DEBUGGING_HOST=localhost
EXPOSE_PLUGIN_DEBUGGING_PORT=5003
DEPLOY_ENV=PRODUCTION
DEPLOYMENT_EDITION=COMMUNITY
ACCESS_TOKEN_EXPIRE_MINUTES=60
REFRESH_TOKEN_EXPIRE_DAYS=30
APP_DEFAULT_ACTIVE_REQUESTS=0
APP_MAX_ACTIVE_REQUESTS=0
# Agent backend client settings shared by API and worker processes.
AGENT_BACKEND_STREAM_READ_TIMEOUT_SECONDS=30
AGENT_BACKEND_STREAM_MAX_RECONNECTS=3
# Client timeout for Agent backend calls that may carry a Home Snapshot transfer.
# Must stay above DIFY_AGENT_ENTERPRISE_SANDBOX_SNAPSHOT_TIMEOUT on the Agent backend.
AGENT_BACKEND_HOME_SNAPSHOT_TIMEOUT_SECONDS=45
# Independent E2B accounting, collected only by API Celery Beat/workers.
# Uses OPS_TRACE_QUEUE; business binding operations never call metering.
# Enable after migrations. START_AT is an immutable, whole-second UTC T0.
AGENT_SANDBOX_METERING_ENABLED=false
AGENT_SANDBOX_METERING_PROJECT_ID=
AGENT_SANDBOX_METERING_START_AT=
AGENT_SANDBOX_METERING_INTERVAL_SECONDS=60
# Outer execution limit for Agent Apps. Agent Backend may stop the internal
# model/tool loop sooner when DIFY_AGENT_RUN_TIMEOUT_SECONDS is lower.
APP_MAX_EXECUTION_TIME=3600
DIFY_BIND_ADDRESS=0.0.0.0
DIFY_PORT=5001
SERVER_WORKER_AMOUNT=1
SERVER_WORKER_CLASS=gevent
SERVER_WORKER_CONNECTIONS=10
API_WEBSOCKET_WORKER_AMOUNT=1
API_WEBSOCKET_WORKER_CLASS=geventwebsocket.gunicorn.workers.GeventWebSocketWorker
API_WEBSOCKET_WORKER_CONNECTIONS=1000
API_WEBSOCKET_GUNICORN_TIMEOUT=360
CELERY_SENTINEL_PASSWORD=
S3_ACCESS_KEY=
S3_SECRET_KEY=
ARCHIVE_STORAGE_ACCESS_KEY=
ARCHIVE_STORAGE_SECRET_KEY=
AZURE_BLOB_ACCOUNT_KEY=difyai
ALIYUN_OSS_ACCESS_KEY=your-access-key
ALIYUN_OSS_SECRET_KEY=your-secret-key
TENCENT_COS_SECRET_KEY=your-secret-key
TENCENT_COS_SECRET_ID=your-secret-id
OCI_ACCESS_KEY=your-access-key
OCI_SECRET_KEY=your-secret-key
HUAWEI_OBS_SECRET_KEY=your-secret-key
HUAWEI_OBS_ACCESS_KEY=your-access-key
VOLCENGINE_TOS_SECRET_KEY=your-secret-key
VOLCENGINE_TOS_ACCESS_KEY=your-access-key
BAIDU_OBS_SECRET_KEY=your-secret-key
BAIDU_OBS_ACCESS_KEY=your-access-key
SUPABASE_API_KEY=your-access-key
ALIBABACLOUD_MYSQL_PASSWORD=difyai123456
RELYT_PASSWORD=difyai123456
LINDORM_PASSWORD=admin
LINDORM_USING_UGC=True
LINDORM_QUERY_TIMEOUT=1
HUAWEI_CLOUD_PASSWORD=admin
UPSTASH_VECTOR_TOKEN=dify
TABLESTORE_ACCESS_KEY_ID=xxx
TABLESTORE_ACCESS_KEY_SECRET=xxx
TABLESTORE_NORMALIZE_FULLTEXT_BM25_SCORE=false
CLICKZETTA_PASSWORD=
CLICKZETTA_INSTANCE=
CLICKZETTA_SERVICE=api.clickzetta.com
CLICKZETTA_WORKSPACE=quick_start
CLICKZETTA_VCLUSTER=default_ap
CLICKZETTA_SCHEMA=dify
CLICKZETTA_BATCH_SIZE=100
CLICKZETTA_ENABLE_INVERTED_INDEX=true
CLICKZETTA_ANALYZER_TYPE=chinese
CLICKZETTA_ANALYZER_MODE=smart
UNSTRUCTURED_API_KEY=
SCARF_NO_ANALYTICS=true
PLUGIN_BASED_TOKEN_COUNTING_ENABLED=false
NOTION_CLIENT_SECRET=
NOTION_CLIENT_ID=
NOTION_INTERNAL_SECRET=
MAIL_TYPE=resend
MAIL_DEFAULT_SEND_FROM=
RESEND_API_KEY=your-resend-api-key
SMTP_SERVER=
SMTP_PORT=465
SMTP_USERNAME=
SMTP_PASSWORD=
SMTP_USE_TLS=true
SMTP_OPPORTUNISTIC_TLS=false
SMTP_LOCAL_HOSTNAME=
SENDGRID_API_KEY=
INVITE_EXPIRY_HOURS=72
RESET_PASSWORD_TOKEN_EXPIRY_MINUTES=5
EMAIL_REGISTER_TOKEN_EXPIRY_MINUTES=5
CHANGE_EMAIL_TOKEN_EXPIRY_MINUTES=5
OWNER_TRANSFER_TOKEN_EXPIRY_MINUTES=5
CODE_EXECUTION_ENDPOINT=http://sandbox:8194
CODE_EXECUTION_API_KEY=dify-sandbox
CODE_EXECUTION_SSL_VERIFY=True
CODE_EXECUTION_POOL_MAX_CONNECTIONS=100
CODE_EXECUTION_POOL_MAX_KEEPALIVE_CONNECTIONS=20
CODE_EXECUTION_POOL_KEEPALIVE_EXPIRY=5.0
CODE_MAX_NUMBER=9223372036854775807
CODE_MIN_NUMBER=-9223372036854775808
CODE_MAX_DEPTH=5
CODE_MAX_PRECISION=20
CODE_MAX_STRING_LENGTH=400000
CODE_MAX_STRING_ARRAY_LENGTH=30
CODE_MAX_OBJECT_ARRAY_LENGTH=30
CODE_MAX_NUMBER_ARRAY_LENGTH=1000
CODE_EXECUTION_CONNECT_TIMEOUT=10
CODE_EXECUTION_READ_TIMEOUT=60
CODE_EXECUTION_WRITE_TIMEOUT=10
TEMPLATE_TRANSFORM_MAX_LENGTH=400000
WORKFLOW_MAX_EXECUTION_STEPS=500
# Outer execution limit for Workflow and Chatflow callers. Agent Backend may
# stop the internal model/tool loop sooner when its run timeout is lower.
# To allow all Agent call paths to run for one hour, set this value,
# APP_MAX_EXECUTION_TIME, and DIFY_AGENT_RUN_TIMEOUT_SECONDS to at least 3600.
WORKFLOW_MAX_EXECUTION_TIME=3600
WORKFLOW_CALL_MAX_DEPTH=5
MAX_VARIABLE_SIZE=204800
WORKFLOW_GENERATOR_NODE_BUILDER_MAX_WORKERS=6
WORKFLOW_FILE_UPLOAD_LIMIT=10
GRAPH_ENGINE_MAX_WORKERS=10
ALIYUN_SLS_ACCESS_KEY_ID=
ALIYUN_SLS_ACCESS_KEY_SECRET=
WEBHOOK_REQUEST_BODY_MAX_SIZE=10485760
# Bare API default. Compose enables this for its API services behind Nginx.
# Override Compose through docker/.env, the shell, or a Compose override, not this env_file.
# See docker/README.md#client-ip-and-trusted-proxies before exposing the API directly.
RESPECT_XFORWARD_HEADERS_ENABLED=false
SSRF_HTTP_PORT=3128
SSRF_COREDUMP_DIR=/var/spool/squid
SSRF_DEFAULT_TIME_OUT=5
SSRF_DEFAULT_CONNECT_TIME_OUT=5
SSRF_DEFAULT_READ_TIME_OUT=5
SSRF_DEFAULT_WRITE_TIME_OUT=5
SSRF_POOL_MAX_CONNECTIONS=100
SSRF_POOL_MAX_KEEPALIVE_CONNECTIONS=20
SSRF_POOL_KEEPALIVE_EXPIRY=5.0
PLUGIN_AWS_ACCESS_KEY=
PLUGIN_AWS_SECRET_KEY=
PLUGIN_AWS_REGION=
PLUGIN_TENCENT_COS_SECRET_KEY=
PLUGIN_TENCENT_COS_SECRET_ID=
PLUGIN_ALIYUN_OSS_ACCESS_KEY_ID=
PLUGIN_ALIYUN_OSS_ACCESS_KEY_SECRET=
PLUGIN_VOLCENGINE_TOS_ACCESS_KEY=
PLUGIN_VOLCENGINE_TOS_SECRET_KEY=
OTLP_API_KEY=
OTEL_EXPORTER_OTLP_PROTOCOL=
OTEL_EXPORTER_TYPE=otlp
OTEL_SAMPLING_RATE=0.1
OTEL_BATCH_EXPORT_SCHEDULE_DELAY=5000
OTEL_MAX_QUEUE_SIZE=2048
OTEL_MAX_EXPORT_BATCH_SIZE=512
OTEL_METRIC_EXPORT_INTERVAL=60000
OTEL_BATCH_EXPORT_TIMEOUT=10000
OTEL_METRIC_EXPORT_TIMEOUT=30000
QUEUE_MONITOR_THRESHOLD=200
QUEUE_MONITOR_ALERT_EMAILS=
QUEUE_MONITOR_INTERVAL=30
SWAGGER_UI_ENABLED=false
SWAGGER_UI_PATH=/swagger-ui.html
OPENAPI_ENABLED=false
OPENAPI_CORS_ALLOW_ORIGINS=
OPENAPI_KNOWN_CLIENT_IDS=difyctl
OPENAPI_RATE_LIMIT_PER_TOKEN=60
DEVICE_FLOW_APPROVE_RATE_LIMIT_PER_HOUR=10
ENABLE_OAUTH_BEARER=false
DSL_EXPORT_ENCRYPT_DATASET_ID=true
DATASET_MAX_SEGMENTS_PER_REQUEST=0
ENABLE_CLEAN_EMBEDDING_CACHE_TASK=false
ENABLE_CLEAN_UNUSED_DATASETS_TASK=false
ENABLE_CREATE_TIDB_SERVERLESS_TASK=false
ENABLE_UPDATE_TIDB_SERVERLESS_STATUS_TASK=false
ENABLE_CLEAN_MESSAGES=false
ENABLE_WORKFLOW_RUN_CLEANUP_TASK=false
ENABLE_MAIL_CLEAN_DOCUMENT_NOTIFY_TASK=false
ENABLE_DATASETS_QUEUE_MONITOR=false
ENABLE_CHECK_UPGRADABLE_PLUGIN_TASK=true
ENABLE_WORKFLOW_SCHEDULE_POLLER_TASK=true
WORKFLOW_SCHEDULE_POLLER_INTERVAL=1
WORKFLOW_SCHEDULE_POLLER_BATCH_SIZE=100
WORKFLOW_SCHEDULE_MAX_DISPATCH_PER_TICK=0
TENANT_ISOLATED_TASK_CONCURRENCY=1
ANNOTATION_IMPORT_FILE_SIZE_LIMIT=2
ANNOTATION_IMPORT_MAX_RECORDS=10000
ANNOTATION_IMPORT_MIN_RECORDS=1
ANNOTATION_IMPORT_RATE_LIMIT_PER_MINUTE=5
ANNOTATION_IMPORT_RATE_LIMIT_PER_HOUR=20
ANNOTATION_IMPORT_MAX_CONCURRENT=5
CREATORS_PLATFORM_FEATURES_ENABLED=true
CREATORS_PLATFORM_API_URL=https://creators.dify.ai
CREATORS_PLATFORM_OAUTH_CLIENT_ID=
TIDB_VECTOR_DATABASE=dify
ALIBABACLOUD_MYSQL_HOST=127.0.0.1
ALIBABACLOUD_MYSQL_PORT=3306
ALIBABACLOUD_MYSQL_USER=root
ALIBABACLOUD_MYSQL_DATABASE=dify
ALIBABACLOUD_MYSQL_MAX_CONNECTION=5
ALIBABACLOUD_MYSQL_HNSW_M=6
RELYT_DATABASE=postgres
TENCENT_VECTOR_DB_DATABASE=dify
BAIDU_VECTOR_DB_DATABASE=dify
EXPOSE_PLUGIN_DAEMON_PORT=5002
GUNICORN_TIMEOUT=360
# Must stay above the idle connection reuse window of the HTTP clients that
# pool connections to this server. Node's global fetch (undici) keeps a socket
# idle for 4s before dropping it, so a shorter value here lets the server close
# a connection the client still considers reusable, which surfaces as
# intermittent ECONNRESET on server-side rendering. 0 disables keep-alive.
GUNICORN_KEEP_ALIVE=10
CELERY_WORKER_AMOUNT=
CELERY_AUTO_SCALE=false
CELERY_MAX_WORKERS=
CELERY_MIN_WORKERS=
API_TOOL_DEFAULT_CONNECT_TIMEOUT=10
API_TOOL_DEFAULT_READ_TIMEOUT=60
CELERY_BACKEND=redis
CELERY_USE_SENTINEL=false
CELERY_SENTINEL_MASTER_NAME=
CELERY_SENTINEL_SOCKET_TIMEOUT=0.1
WEB_API_CORS_ALLOW_ORIGINS=*
CONSOLE_CORS_ALLOW_ORIGINS=*
WEBSOCKET_MAX_HTTP_BUFFER_SIZE=10485760
COOKIE_DOMAIN=
OPENDAL_SCHEME=fs
OPENDAL_FS_ROOT=storage
CLICKZETTA_VOLUME_TYPE=user
CLICKZETTA_VOLUME_NAME=
CLICKZETTA_VOLUME_TABLE_PREFIX=dataset_
CLICKZETTA_VOLUME_DIFY_PREFIX=dify_km
S3_ENDPOINT=
S3_REGION=us-east-1
S3_BUCKET_NAME=difyai
S3_ADDRESS_STYLE=auto
S3_USE_AWS_MANAGED_IAM=false
ARCHIVE_STORAGE_ENABLED=false
ARCHIVE_STORAGE_ENDPOINT=
ARCHIVE_STORAGE_ARCHIVE_BUCKET=
ARCHIVE_STORAGE_EXPORT_BUCKET=
ARCHIVE_STORAGE_REGION=auto
ARCHIVE_STORAGE_ADDRESS_STYLE=path
AZURE_BLOB_ACCOUNT_NAME=difyai
AZURE_BLOB_CONTAINER_NAME=difyai-container
AZURE_KEYVAULT_VAULT_URL=
AZURE_KEYVAULT_KEY_SIZE=2048
AZURE_KEYVAULT_ROTATION_INTERVAL_DAYS=
GOOGLE_STORAGE_BUCKET_NAME=your-bucket-name
GOOGLE_STORAGE_SERVICE_ACCOUNT_JSON_BASE64=
ALIYUN_OSS_BUCKET_NAME=your-bucket-name
ALIYUN_OSS_ENDPOINT=https://oss-ap-southeast-1-internal.aliyuncs.com
ALIYUN_OSS_REGION=ap-southeast-1
ALIYUN_OSS_AUTH_VERSION=v4
ALIYUN_OSS_PATH=your-path
ALIYUN_CLOUDBOX_ID=your-cloudbox-id
TENCENT_COS_BUCKET_NAME=your-bucket-name
TENCENT_COS_REGION=your-region
TENCENT_COS_SCHEME=your-scheme
TENCENT_COS_CUSTOM_DOMAIN=your-custom-domain
OCI_ENDPOINT=https://your-object-storage-namespace.compat.objectstorage.us-ashburn-1.oraclecloud.com
OCI_BUCKET_NAME=your-bucket-name
OCI_REGION=us-ashburn-1
HUAWEI_OBS_BUCKET_NAME=your-bucket-name
HUAWEI_OBS_SERVER=your-server-url
HUAWEI_OBS_PATH_STYLE=false
VOLCENGINE_TOS_BUCKET_NAME=your-bucket-name
VOLCENGINE_TOS_ENDPOINT=your-server-url
VOLCENGINE_TOS_REGION=your-region
BAIDU_OBS_BUCKET_NAME=your-bucket-name
BAIDU_OBS_ENDPOINT=your-server-url
SUPABASE_BUCKET_NAME=your-bucket-name
TENCENT_VECTOR_DB_TIMEOUT=30
TENCENT_VECTOR_DB_USERNAME=dify
TENCENT_VECTOR_DB_SHARD=1
TENCENT_VECTOR_DB_REPLICAS=2
TENCENT_VECTOR_DB_ENABLE_HYBRID_SEARCH=false
BAIDU_VECTOR_DB_ENDPOINT=http://127.0.0.1:5287
BAIDU_VECTOR_DB_CONNECTION_TIMEOUT_MS=30000
BAIDU_VECTOR_DB_ACCOUNT=root
BAIDU_VECTOR_DB_API_KEY=dify
BAIDU_VECTOR_DB_SHARD=1
BAIDU_VECTOR_DB_REPLICAS=3
BAIDU_VECTOR_DB_INVERTED_INDEX_ANALYZER=DEFAULT_ANALYZER
BAIDU_VECTOR_DB_INVERTED_INDEX_PARSER_MODE=COARSE_MODE
BAIDU_VECTOR_DB_AUTO_BUILD_ROW_COUNT_INCREMENT=500
BAIDU_VECTOR_DB_AUTO_BUILD_ROW_COUNT_INCREMENT_RATIO=0.05
BAIDU_VECTOR_DB_REBUILD_INDEX_TIMEOUT_IN_SECONDS=300
HUAWEI_CLOUD_HOSTS=https://127.0.0.1:9200
HUAWEI_CLOUD_USER=admin
WORKFLOW_NODE_EXECUTION_STORAGE=rdbms
CORE_WORKFLOW_EXECUTION_REPOSITORY=core.repositories.sqlalchemy_workflow_execution_repository.SQLAlchemyWorkflowExecutionRepository
CORE_WORKFLOW_NODE_EXECUTION_REPOSITORY=core.repositories.sqlalchemy_workflow_node_execution_repository.SQLAlchemyWorkflowNodeExecutionRepository
API_WORKFLOW_RUN_REPOSITORY=repositories.sqlalchemy_api_workflow_run_repository.DifyAPISQLAlchemyWorkflowRunRepository
API_WORKFLOW_NODE_EXECUTION_REPOSITORY=repositories.sqlalchemy_api_workflow_node_execution_repository.DifyAPISQLAlchemyWorkflowNodeExecutionRepository
ALIYUN_SLS_ENDPOINT=
ALIYUN_SLS_REGION=
ALIYUN_SLS_PROJECT_NAME=
ALIYUN_SLS_LOGSTORE_TTL=365
LOGSTORE_DUAL_WRITE_ENABLED=false
LOGSTORE_DUAL_READ_ENABLED=true
LOGSTORE_ENABLE_PUT_GRAPH_FIELD=true
HTTP_REQUEST_NODE_MAX_BINARY_SIZE=10485760
HTTP_REQUEST_NODE_MAX_TEXT_SIZE=1048576
HTTP_REQUEST_NODE_SSL_VERIFY=True
HTTP_REQUEST_MAX_CONNECT_TIMEOUT=10
HTTP_REQUEST_MAX_READ_TIMEOUT=600
HTTP_REQUEST_MAX_WRITE_TIMEOUT=600
PLUGIN_INSTALLED_PATH=plugin
PLUGIN_PACKAGE_CACHE_PATH=plugin_packages
PLUGIN_MEDIA_CACHE_PATH=assets
PLUGIN_S3_USE_AWS=false
PLUGIN_S3_USE_AWS_MANAGED_IAM=false
PLUGIN_S3_ENDPOINT=
PLUGIN_S3_USE_PATH_STYLE=false
PLUGIN_AZURE_BLOB_STORAGE_CONTAINER_NAME=
PLUGIN_AZURE_BLOB_STORAGE_CONNECTION_STRING=
PLUGIN_TENCENT_COS_REGION=
PLUGIN_ALIYUN_OSS_REGION=
PLUGIN_ALIYUN_OSS_ENDPOINT=
PLUGIN_ALIYUN_OSS_AUTH_VERSION=v4
PLUGIN_ALIYUN_OSS_PATH=
PLUGIN_VOLCENGINE_TOS_ENDPOINT=
PLUGIN_VOLCENGINE_TOS_REGION=
ENABLE_OTEL=false
OTLP_TRACE_ENDPOINT=
OTLP_METRIC_ENDPOINT=
# Prefix used to create collection name in vector database
OTLP_BASE_ENDPOINT=http://localhost:4318
WEAVIATE_GRPC_ENDPOINT=grpc://weaviate:50051
ANALYTICDB_KEY_ID=your-ak
ANALYTICDB_KEY_SECRET=your-sk
ANALYTICDB_REGION_ID=cn-hangzhou
ANALYTICDB_INSTANCE_ID=gp-ab123456
ANALYTICDB_ACCOUNT=testaccount
ANALYTICDB_PASSWORD=testpassword
ANALYTICDB_NAMESPACE=dify
ANALYTICDB_NAMESPACE_PASSWORD=difypassword
ANALYTICDB_HOST=gp-test.aliyuncs.com
ANALYTICDB_PORT=5432
ANALYTICDB_MIN_CONNECTION=1
ANALYTICDB_MAX_CONNECTION=5
TIDB_VECTOR_HOST=tidb
TIDB_VECTOR_PORT=4000
TIDB_VECTOR_USER=
TIDB_VECTOR_PASSWORD=
TIDB_VECTOR_ENABLE_FULLTEXT_SEARCH=false
TIDB_ON_QDRANT_CLIENT_TIMEOUT=20
TIDB_ON_QDRANT_GRPC_ENABLED=false
TIDB_ON_QDRANT_GRPC_PORT=6334
TIDB_ON_QDRANT_ESTIMATED_STORAGE_LIMITS_MB=sandbox:60,professional:6400,team:25600
TIDB_PUBLIC_KEY=dify
TIDB_PRIVATE_KEY=dify
RELYT_HOST=db
RELYT_PORT=5432
RELYT_USER=postgres
VIKINGDB_ACCESS_KEY=your-ak
VIKINGDB_SECRET_KEY=your-sk
VIKINGDB_REGION=cn-shanghai
VIKINGDB_HOST=api-vikingdb.xxx.volces.com
VIKINGDB_SCHEME=http
VIKINGDB_CONNECTION_TIMEOUT=30
VIKINGDB_SOCKET_TIMEOUT=30
TABLESTORE_ENDPOINT=https://instance-name.cn-hangzhou.ots.aliyuncs.com
TABLESTORE_INSTANCE_NAME=instance-name
CLICKZETTA_USERNAME=
CLICKZETTA_VECTOR_DISTANCE_FUNCTION=cosine_distance
COMPOSE_PROFILES=${VECTOR_STORE:-weaviate},${DB_TYPE:-postgresql},collaboration
EXPOSE_NGINX_PORT=80
EXPOSE_NGINX_SSL_PORT=443
POSITION_TOOL_PINS=
POSITION_TOOL_INCLUDES=
POSITION_TOOL_EXCLUDES=
POSITION_PROVIDER_PINS=
POSITION_PROVIDER_INCLUDES=
POSITION_PROVIDER_EXCLUDES=
CREATE_TIDB_SERVICE_JOB_ENABLED=false
MAX_SUBMIT_COUNT=100
# Vector Store Configuration
STORAGE_TYPE=opendal
KEY_PROVIDER_TYPE=local
VECTOR_STORE=weaviate
VECTOR_INDEX_NAME_PREFIX=Vector_index
WEAVIATE_ENDPOINT=http://weaviate:8080
WEAVIATE_API_KEY=WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih
WEAVIATE_TOKENIZATION=word
OCEANBASE_VECTOR_HOST=oceanbase
OCEANBASE_VECTOR_PORT=2881
OCEANBASE_VECTOR_USER=root@test
OCEANBASE_VECTOR_PASSWORD=difyai123456
OCEANBASE_VECTOR_DATABASE=test
OCEANBASE_ENABLE_HYBRID_SEARCH=false
OCEANBASE_FULLTEXT_PARSER=ik
SEEKDB_MEMORY_LIMIT=2G
QDRANT_URL=http://qdrant:6333
QDRANT_API_KEY=difyai123456
QDRANT_CLIENT_TIMEOUT=20
QDRANT_GRPC_ENABLED=false
QDRANT_GRPC_PORT=6334
QDRANT_REPLICATION_FACTOR=1
MILVUS_URI=http://host.docker.internal:19530
MILVUS_TOKEN=
MILVUS_USER=
MILVUS_PASSWORD=
MILVUS_ANALYZER_PARAMS=
PGVECTOR_HOST=pgvector
PGVECTOR_PORT=5432
PGVECTOR_USER=postgres
PGVECTOR_PASSWORD=difyai123456
PGVECTOR_DATABASE=dify
PGVECTOR_MIN_CONNECTION=1
PGVECTOR_MAX_CONNECTION=5
PGVECTOR_PG_BIGM=false
PGVECTOR_PG_BIGM_VERSION=1.2-20240606
# Hologres Configuration
HOLOGRES_HOST=
HOLOGRES_PORT=80
HOLOGRES_DATABASE=
HOLOGRES_ACCESS_KEY_ID=
HOLOGRES_ACCESS_KEY_SECRET=
HOLOGRES_SCHEMA=public
HOLOGRES_TOKENIZER=jieba
HOLOGRES_DISTANCE_METHOD=Cosine
HOLOGRES_BASE_QUANTIZATION_TYPE=rabitq
HOLOGRES_MAX_DEGREE=64
HOLOGRES_EF_CONSTRUCTION=400
# Milvus API Configuration
MILVUS_DATABASE=
MILVUS_ENABLE_HYBRID_SEARCH=False
# Human Input Task Configuration
ENABLE_HUMAN_INPUT_TIMEOUT_TASK=true
HUMAN_INPUT_TIMEOUT_TASK_INTERVAL=1
# Conversation cleanup recovery task
ENABLE_CONVERSATION_CLEANUP_TASK=true
CONVERSATION_CLEANUP_TASK_INTERVAL=5
CONVERSATION_CLEANUP_BATCH_SIZE=100
# Nacos remote settings source HTTP timeouts (seconds).
# Bound how long requests to the Nacos endpoint wait before failing, so a slow or
# unresponsive Nacos server cannot stall API startup or token refresh.
DIFY_ENV_NACOS_REQUEST_TIMEOUT=10.0
DIFY_ENV_NACOS_CONNECT_TIMEOUT=3.0
+60
View File
@@ -0,0 +1,60 @@
# Defaults for web. Copy this file to web.env to customize it.
# Edit the settings below in the copy; docker/.env takes precedence.
# Optional application settings are commented to retain their application defaults.
CONSOLE_API_URL=${CONSOLE_API_URL:-}
SERVER_CONSOLE_API_URL=${SERVER_CONSOLE_API_URL:-http://api:5001}
APP_API_URL=${APP_API_URL:-}
# Optional Cloud WebApp document admission. Enable only after the edge proxy
# overwrites both X-Dify-Webapp-Client-Ip and X-Dify-Webapp-Proxy-Secret, Web is
# private to that proxy, and the target Gateway enforces /api using trusted IPs.
# Use the complete internal Gateway endpoint, never a direct Core API URL.
# Example: http://gateway-public:8080/api/webapp/access-mode
# WEBAPP_ACCESS_PREFLIGHT_URL=
# Provision outside Git; must match the edge-injected secret. Never NEXT_PUBLIC.
# WEBAPP_ACCESS_PREFLIGHT_PROXY_SECRET=
WEB_SENTRY_DSN=${WEB_SENTRY_DSN:-}
NEXT_PUBLIC_SOCKET_URL=${NEXT_PUBLIC_SOCKET_URL:-ws://localhost}
EXPERIMENTAL_ENABLE_VINEXT=${EXPERIMENTAL_ENABLE_VINEXT:-false}
LOOP_NODE_MAX_COUNT=${LOOP_NODE_MAX_COUNT:-100}
MAX_TOOLS_NUM=${MAX_TOOLS_NUM:-10}
MAX_PARALLEL_LIMIT=${MAX_PARALLEL_LIMIT:-10}
MAX_ITERATIONS_NUM=${MAX_ITERATIONS_NUM:-99}
TEXT_GENERATION_TIMEOUT_MS=${TEXT_GENERATION_TIMEOUT_MS:-60000}
# WORKFLOW_GENERATION_TIMEOUT_MS=180000
# ALLOW_INLINE_STYLES=false
# Example: ()!*&()!*&-。.;;+=—
# MARKDOWN_FORM_FIELD_NAME_EXTRA_CHARS=
# Maximum length of Markdown form field names.
# MARKDOWN_FORM_FIELD_NAME_MAX_LENGTH=128
ALLOW_UNSAFE_DATA_SCHEME=${ALLOW_UNSAFE_DATA_SCHEME:-false}
MAX_TREE_DEPTH=${MAX_TREE_DEPTH:-50}
MARKETPLACE_API_URL=${MARKETPLACE_API_URL:-https://marketplace.dify.ai}
MARKETPLACE_URL=${MARKETPLACE_URL:-https://marketplace.dify.ai}
INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH=${INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH:-4000}
ALLOW_EMBED=${ALLOW_EMBED:-false}
AMPLITUDE_API_KEY=${AMPLITUDE_API_KEY:-}
TURNSTILE_SITE_KEY=${TURNSTILE_SITE_KEY:-}
# COOKIEYES_SITE_KEY=
ENABLE_WEBSITE_JINAREADER=${ENABLE_WEBSITE_JINAREADER:-true}
ENABLE_WEBSITE_FIRECRAWL=${ENABLE_WEBSITE_FIRECRAWL:-true}
ENABLE_WEBSITE_WATERCRAWL=${ENABLE_WEBSITE_WATERCRAWL:-true}
# NEXT_PUBLIC_ENABLE_SINGLE_DOLLAR_LATEX=false
# NEXT_PUBLIC_ENABLE_FEATURE_PREVIEW=true
# Enable HITL IM, Contacts, V2 editing/migration and approval UI. Defaults to false.
# When false, retain legacy V1 behavior and disable V2 entry points without converting saved data.
# Restart the Web service and reload the page after changing this setting.
# NEXT_PUBLIC_ENABLE_HITL_IM=false
# Show Access Token settings to workspace owners. Disabled by default.
# NEXT_PUBLIC_ENABLE_ACCESS_TOKEN=false
NEXT_PUBLIC_ENABLE_AGENT_V2=${NEXT_PUBLIC_ENABLE_AGENT_V2:-true}
# NEXT_PUBLIC_ENABLE_AGENT_V2_IN_CHATFLOW=false
NEXT_PUBLIC_COOKIE_DOMAIN=${NEXT_PUBLIC_COOKIE_DOMAIN:-}
# NEXT_PUBLIC_BATCH_CONCURRENCY=5
CSP_WHITELIST=${CSP_WHITELIST:-}
TOP_K_MAX_VALUE=${TOP_K_MAX_VALUE:-10}
NEXT_TELEMETRY_DISABLED=${NEXT_TELEMETRY_DISABLED:-0}
# Container variable mappings; keep these expressions unchanged in the copy.
SENTRY_DSN=${WEB_SENTRY_DSN:-}
-56
View File
@@ -1,56 +0,0 @@
# ------------------------------
# Web Configuration
# ------------------------------
CONSOLE_API_URL=
SERVER_CONSOLE_API_URL=http://api:5001
APP_API_URL=
# Optional Cloud WebApp document admission. Enable only after the edge proxy
# overwrites both X-Dify-Webapp-Client-Ip and X-Dify-Webapp-Proxy-Secret, Web is
# private to that proxy, and the target Gateway enforces /api using trusted IPs.
# Use the complete internal Gateway endpoint, never a direct Core API URL.
# Example: http://gateway-public:8080/api/webapp/access-mode
WEBAPP_ACCESS_PREFLIGHT_URL=
# Provision outside Git; must match the edge-injected secret. Never NEXT_PUBLIC.
WEBAPP_ACCESS_PREFLIGHT_PROXY_SECRET=
SENTRY_DSN=
NEXT_PUBLIC_SOCKET_URL=ws://localhost
EXPERIMENTAL_ENABLE_VINEXT=false
LOOP_NODE_MAX_COUNT=100
MAX_TOOLS_NUM=10
MAX_PARALLEL_LIMIT=10
MAX_ITERATIONS_NUM=99
TEXT_GENERATION_TIMEOUT_MS=60000
WORKFLOW_GENERATION_TIMEOUT_MS=180000
ALLOW_INLINE_STYLES=false
# Example: ()!*&()!*&-。.;;+=—
MARKDOWN_FORM_FIELD_NAME_EXTRA_CHARS=
# Maximum length of Markdown form field names.
MARKDOWN_FORM_FIELD_NAME_MAX_LENGTH=128
ALLOW_UNSAFE_DATA_SCHEME=false
MAX_TREE_DEPTH=50
MARKETPLACE_API_URL=https://marketplace.dify.ai
MARKETPLACE_URL=https://marketplace.dify.ai
INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH=4000
ALLOW_EMBED=false
AMPLITUDE_API_KEY=
TURNSTILE_SITE_KEY=
COOKIEYES_SITE_KEY=
ENABLE_WEBSITE_JINAREADER=true
ENABLE_WEBSITE_FIRECRAWL=true
ENABLE_WEBSITE_WATERCRAWL=true
NEXT_PUBLIC_ENABLE_SINGLE_DOLLAR_LATEX=false
NEXT_PUBLIC_ENABLE_FEATURE_PREVIEW=true
# Enable HITL IM, Contacts, V2 editing/migration and approval UI. Defaults to false.
# When false, retain legacy V1 behavior and disable V2 entry points without converting saved data.
# Restart the Web service and reload the page after changing this setting.
NEXT_PUBLIC_ENABLE_HITL_IM=false
# Show Access Token settings to workspace owners. Disabled by default.
NEXT_PUBLIC_ENABLE_ACCESS_TOKEN=false
NEXT_PUBLIC_ENABLE_AGENT_V2=true
NEXT_PUBLIC_ENABLE_AGENT_V2_IN_CHATFLOW=false
NEXT_PUBLIC_COOKIE_DOMAIN=
NEXT_PUBLIC_BATCH_CONCURRENCY=5
CSP_WHITELIST=
TOP_K_MAX_VALUE=10
@@ -0,0 +1,9 @@
# Defaults for worker_beat. Copy this file to worker-beat.env to customize it.
# Edit the settings below in the copy; docker/.env takes precedence.
# Optional application settings are commented to retain their application defaults.
# MODE is selected by the Compose service.
# Set COMPOSE_WORKER_HEALTHCHECK_DISABLED in docker/.env; Compose needs it before loading service files.
# Set COMPOSE_WORKER_HEALTHCHECK_INTERVAL in docker/.env; Compose needs it before loading service files.
# Set COMPOSE_WORKER_HEALTHCHECK_TIMEOUT in docker/.env; Compose needs it before loading service files.
CELERY_BROKER_URL=${CELERY_BROKER_URL:-redis://:${REDIS_PASSWORD:-difyai123456}@${REDIS_HOST:-redis}:${REDIS_PORT:-6379}/1}
@@ -1,8 +0,0 @@
# ------------------------------
# Worker Beat Configuration
# ------------------------------
MODE=beat
COMPOSE_WORKER_HEALTHCHECK_DISABLED=true
COMPOSE_WORKER_HEALTHCHECK_INTERVAL=30s
COMPOSE_WORKER_HEALTHCHECK_TIMEOUT=30s
+29
View File
@@ -0,0 +1,29 @@
# Defaults for worker. Copy this file to worker.env to customize it.
# Edit the settings below in the copy; docker/.env takes precedence.
# Optional application settings are commented to retain their application defaults.
# MODE is selected by the Compose service.
# CELERY_WORKER_CLASS=gevent
API_SENTRY_DSN=${API_SENTRY_DSN:-}
API_SENTRY_TRACES_SAMPLE_RATE=${API_SENTRY_TRACES_SAMPLE_RATE:-1.0}
API_SENTRY_PROFILES_SAMPLE_RATE=${API_SENTRY_PROFILES_SAMPLE_RATE:-1.0}
PLUGIN_MAX_PACKAGE_SIZE=${PLUGIN_MAX_PACKAGE_SIZE:-52428800}
# Set PLUGIN_DIFY_INNER_API_KEY in docker/.env; all callers must share the API's inner credential.
# Set COMPOSE_WORKER_HEALTHCHECK_DISABLED in docker/.env; Compose needs it before loading service files.
# Set COMPOSE_WORKER_HEALTHCHECK_INTERVAL in docker/.env; Compose needs it before loading service files.
# Set COMPOSE_WORKER_HEALTHCHECK_TIMEOUT in docker/.env; Compose needs it before loading service files.
DIFY_AGENT_API_TOKEN=${DIFY_AGENT_API_TOKEN:-dify-agent-run-token-for-dev-only}
AGENT_BACKEND_BASE_URL=${AGENT_BACKEND_BASE_URL:-http://agent_backend:5050}
CELERY_BROKER_URL=${CELERY_BROKER_URL:-redis://:${REDIS_PASSWORD:-difyai123456}@${REDIS_HOST:-redis}:${REDIS_PORT:-6379}/1}
# Worker autoscaling
# CELERY_AUTO_SCALE=false
# CELERY_MAX_WORKERS=
# CELERY_MIN_WORKERS=
# Container variable mappings; keep these expressions unchanged in the copy.
AGENT_BACKEND_API_TOKEN=${DIFY_AGENT_API_TOKEN:-dify-agent-run-token-for-dev-only}
INNER_API_KEY_FOR_PLUGIN=${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1}
SENTRY_DSN=${API_SENTRY_DSN:-}
SENTRY_PROFILES_SAMPLE_RATE=${API_SENTRY_PROFILES_SAMPLE_RATE:-1.0}
SENTRY_TRACES_SAMPLE_RATE=${API_SENTRY_TRACES_SAMPLE_RATE:-1.0}
@@ -1,13 +0,0 @@
# ------------------------------
# Worker Configuration
# ------------------------------
MODE=worker
SENTRY_DSN=
SENTRY_TRACES_SAMPLE_RATE=1.0
SENTRY_PROFILES_SAMPLE_RATE=1.0
PLUGIN_MAX_PACKAGE_SIZE=52428800
INNER_API_KEY_FOR_PLUGIN=QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1
COMPOSE_WORKER_HEALTHCHECK_DISABLED=true
COMPOSE_WORKER_HEALTHCHECK_INTERVAL=30s
COMPOSE_WORKER_HEALTHCHECK_TIMEOUT=30s
+15
View File
@@ -0,0 +1,15 @@
# Defaults for db_mysql. Copy this file to db-mysql.env to customize it.
# Edit the settings below in the copy; docker/.env takes precedence.
# Optional application settings are commented to retain their application defaults.
MYSQL_INNODB_LOG_FILE_SIZE=${MYSQL_INNODB_LOG_FILE_SIZE:-128M}
MYSQL_INNODB_FLUSH_LOG_AT_TRX_COMMIT=${MYSQL_INNODB_FLUSH_LOG_AT_TRX_COMMIT:-2}
MYSQL_MAX_CONNECTIONS=${MYSQL_MAX_CONNECTIONS:-1000}
MYSQL_INNODB_BUFFER_POOL_SIZE=${MYSQL_INNODB_BUFFER_POOL_SIZE:-512M}
# Set MYSQL_HOST_VOLUME in docker/.env; Compose needs it before loading service files.
DB_DATABASE=${DB_DATABASE:-dify}
DB_PASSWORD=${DB_PASSWORD:-difyai123456}
# Container variable mappings; keep these expressions unchanged in the copy.
MYSQL_DATABASE=${DB_DATABASE:-dify}
MYSQL_ROOT_PASSWORD=${DB_PASSWORD:-difyai123456}
@@ -1,9 +0,0 @@
# ------------------------------
# Db Mysql Configuration
# ------------------------------
MYSQL_INNODB_LOG_FILE_SIZE=128M
MYSQL_INNODB_FLUSH_LOG_AT_TRX_COMMIT=2
MYSQL_MAX_CONNECTIONS=1000
MYSQL_INNODB_BUFFER_POOL_SIZE=512M
MYSQL_HOST_VOLUME=./volumes/mysql/data
@@ -0,0 +1,31 @@
# Defaults for db_postgres. Copy this file to db-postgres.env to customize it.
# Edit the settings below in the copy; docker/.env takes precedence.
# Optional application settings are commented to retain their application defaults.
PGDATA=${PGDATA:-/var/lib/postgresql/data/pgdata}
# DB_TYPE=postgresql
DB_USERNAME=${DB_USERNAME:-postgres}
DB_PASSWORD=${DB_PASSWORD:-difyai123456}
# DB_HOST=db_postgres
# DB_PORT=5432
DB_DATABASE=${DB_DATABASE:-dify}
# SQLALCHEMY_POOL_SIZE=30
# SQLALCHEMY_MAX_OVERFLOW=10
# SQLALCHEMY_POOL_RECYCLE=3600
# SQLALCHEMY_ECHO=false
# SQLALCHEMY_POOL_PRE_PING=false
# SQLALCHEMY_POOL_USE_LIFO=false
# SQLALCHEMY_POOL_TIMEOUT=30
# SQLALCHEMY_POOL_RESET_ON_RETURN=rollback
POSTGRES_MAX_CONNECTIONS=${POSTGRES_MAX_CONNECTIONS:-200}
POSTGRES_SHARED_BUFFERS=${POSTGRES_SHARED_BUFFERS:-128MB}
POSTGRES_WORK_MEM=${POSTGRES_WORK_MEM:-4MB}
POSTGRES_MAINTENANCE_WORK_MEM=${POSTGRES_MAINTENANCE_WORK_MEM:-64MB}
POSTGRES_EFFECTIVE_CACHE_SIZE=${POSTGRES_EFFECTIVE_CACHE_SIZE:-4096MB}
POSTGRES_STATEMENT_TIMEOUT=${POSTGRES_STATEMENT_TIMEOUT:-0}
POSTGRES_IDLE_IN_TRANSACTION_SESSION_TIMEOUT=${POSTGRES_IDLE_IN_TRANSACTION_SESSION_TIMEOUT:-0}
# Container variable mappings; keep these expressions unchanged in the copy.
POSTGRES_DB=${DB_DATABASE:-dify}
POSTGRES_PASSWORD=${DB_PASSWORD:-difyai123456}
POSTGRES_USER=${DB_USERNAME:-postgres}
@@ -1,26 +0,0 @@
# ------------------------------
# Db Postgres Configuration
# ------------------------------
PGDATA=/var/lib/postgresql/data/pgdata
DB_TYPE=postgresql
DB_USERNAME=postgres
DB_PASSWORD=difyai123456
DB_HOST=db_postgres
DB_PORT=5432
DB_DATABASE=dify
SQLALCHEMY_POOL_SIZE=30
SQLALCHEMY_MAX_OVERFLOW=10
SQLALCHEMY_POOL_RECYCLE=3600
SQLALCHEMY_ECHO=false
SQLALCHEMY_POOL_PRE_PING=false
SQLALCHEMY_POOL_USE_LIFO=false
SQLALCHEMY_POOL_TIMEOUT=30
SQLALCHEMY_POOL_RESET_ON_RETURN=rollback
POSTGRES_MAX_CONNECTIONS=100
POSTGRES_SHARED_BUFFERS=128MB
POSTGRES_WORK_MEM=4MB
POSTGRES_MAINTENANCE_WORK_MEM=64MB
POSTGRES_EFFECTIVE_CACHE_SIZE=4096MB
POSTGRES_STATEMENT_TIMEOUT=0
POSTGRES_IDLE_IN_TRANSACTION_SESSION_TIMEOUT=0
+42
View File
@@ -0,0 +1,42 @@
# Defaults for redis. Copy this file to redis.env to customize it.
# Edit the settings below in the copy; docker/.env takes precedence.
# Optional application settings are commented to retain their application defaults.
# REDIS_HOST=redis
# REDIS_PORT=6379
# REDIS_USERNAME=
REDIS_PASSWORD=${REDIS_PASSWORD:-difyai123456}
# REDIS_USE_SSL=false
# REDIS_SSL_CERT_REQS=CERT_NONE
# REDIS_SSL_CA_CERTS=
# REDIS_SSL_CERTFILE=
# REDIS_SSL_KEYFILE=
# REDIS_DB=0
# REDIS_KEY_PREFIX=
# REDIS_MAX_CONNECTIONS=
# REDIS_USE_SENTINEL=false
# REDIS_SENTINELS=
# REDIS_SENTINEL_SERVICE_NAME=
# REDIS_SENTINEL_USERNAME=
# REDIS_SENTINEL_PASSWORD=
# REDIS_SENTINEL_SOCKET_TIMEOUT=0.1
# REDIS_USE_CLUSTERS=false
# REDIS_CLUSTERS=
# REDIS_CLUSTERS_PASSWORD=
# REDIS_RETRY_RETRIES=3
# REDIS_RETRY_BACKOFF_BASE=1.0
# REDIS_RETRY_BACKOFF_CAP=10.0
# REDIS_SOCKET_TIMEOUT=5.0
# REDIS_SOCKET_CONNECT_TIMEOUT=5.0
# REDIS_HEALTH_CHECK_INTERVAL=30
# REDIS_KEEPALIVE=true
# REDIS_KEEPALIVE_IDLE=30
# REDIS_KEEPALIVE_INTERVAL=10
# REDIS_KEEPALIVE_COUNT=10
# EVENT_BUS_REDIS_URL=
# EVENT_BUS_REDIS_CHANNEL_TYPE=pubsub
# EVENT_BUS_REDIS_USE_CLUSTERS=false
# BROKER_USE_SSL=false
# Container variable mappings; keep these expressions unchanged in the copy.
REDISCLI_AUTH=${REDIS_PASSWORD:-difyai123456}
-39
View File
@@ -1,39 +0,0 @@
# ------------------------------
# Redis Configuration
# ------------------------------
REDIS_HOST=redis
REDIS_PORT=6379
REDIS_USERNAME=
REDIS_PASSWORD=difyai123456
REDIS_USE_SSL=false
REDIS_SSL_CERT_REQS=CERT_NONE
REDIS_SSL_CA_CERTS=
REDIS_SSL_CERTFILE=
REDIS_SSL_KEYFILE=
REDIS_DB=0
REDIS_KEY_PREFIX=
REDIS_MAX_CONNECTIONS=
REDIS_USE_SENTINEL=false
REDIS_SENTINELS=
REDIS_SENTINEL_SERVICE_NAME=
REDIS_SENTINEL_USERNAME=
REDIS_SENTINEL_PASSWORD=
REDIS_SENTINEL_SOCKET_TIMEOUT=0.1
REDIS_USE_CLUSTERS=false
REDIS_CLUSTERS=
REDIS_CLUSTERS_PASSWORD=
REDIS_RETRY_RETRIES=3
REDIS_RETRY_BACKOFF_BASE=1.0
REDIS_RETRY_BACKOFF_CAP=10.0
REDIS_SOCKET_TIMEOUT=5.0
REDIS_SOCKET_CONNECT_TIMEOUT=5.0
REDIS_HEALTH_CHECK_INTERVAL=30
REDIS_KEEPALIVE=true
REDIS_KEEPALIVE_IDLE=30
REDIS_KEEPALIVE_INTERVAL=10
REDIS_KEEPALIVE_COUNT=10
EVENT_BUS_REDIS_URL=
EVENT_BUS_REDIS_CHANNEL_TYPE=pubsub
EVENT_BUS_REDIS_USE_CLUSTERS=false
BROKER_USE_SSL=false
@@ -0,0 +1,7 @@
# Defaults for certbot. Copy this file to certbot.env to customize it.
# Edit the settings below in the copy; docker/.env takes precedence.
# Optional application settings are commented to retain their application defaults.
CERTBOT_EMAIL=${CERTBOT_EMAIL:-}
CERTBOT_DOMAIN=${CERTBOT_DOMAIN:-}
CERTBOT_OPTIONS=${CERTBOT_OPTIONS:-}
@@ -1,7 +0,0 @@
# ------------------------------
# Certbot Configuration
# ------------------------------
CERTBOT_EMAIL=your_email@example.com
CERTBOT_DOMAIN=your_domain.com
CERTBOT_OPTIONS=
+8
View File
@@ -0,0 +1,8 @@
# Defaults for etcd. Copy this file to etcd.env to customize it.
# Edit the settings below in the copy; docker/.env takes precedence.
# Optional application settings are commented to retain their application defaults.
ETCD_AUTO_COMPACTION_MODE=${ETCD_AUTO_COMPACTION_MODE:-revision}
ETCD_AUTO_COMPACTION_RETENTION=${ETCD_AUTO_COMPACTION_RETENTION:-1000}
ETCD_QUOTA_BACKEND_BYTES=${ETCD_QUOTA_BACKEND_BYTES:-4294967296}
ETCD_SNAPSHOT_COUNT=${ETCD_SNAPSHOT_COUNT:-50000}
@@ -1,4 +0,0 @@
# ------------------------------
# Etcd Configuration
# ------------------------------
@@ -0,0 +1,10 @@
# Defaults for milvus-standalone. Copy this file to milvus-standalone.env to customize it.
# Edit the settings below in the copy; docker/.env takes precedence.
# Optional application settings are commented to retain their application defaults.
ETCD_ENDPOINTS=${ETCD_ENDPOINTS:-etcd:2379}
MINIO_ADDRESS=${MINIO_ADDRESS:-minio:9000}
MILVUS_AUTHORIZATION_ENABLED=${MILVUS_AUTHORIZATION_ENABLED:-true}
# Container variable mappings; keep these expressions unchanged in the copy.
common.security.authorizationEnabled=${MILVUS_AUTHORIZATION_ENABLED:-true}
@@ -1,4 +0,0 @@
# ------------------------------
# Milvus Standalone Configuration
# ------------------------------
@@ -0,0 +1,6 @@
# Defaults for minio. Copy this file to minio.env to customize it.
# Edit the settings below in the copy; docker/.env takes precedence.
# Optional application settings are commented to retain their application defaults.
MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY:-minioadmin}
MINIO_SECRET_KEY=${MINIO_SECRET_KEY:-minioadmin}
@@ -1,4 +0,0 @@
# ------------------------------
# Minio Configuration
# ------------------------------
+20
View File
@@ -0,0 +1,20 @@
# Defaults for nginx. Copy this file to nginx.env to customize it.
# Edit the settings below in the copy; docker/.env takes precedence.
# Optional application settings are commented to retain their application defaults.
NGINX_SERVER_NAME=${NGINX_SERVER_NAME:-_}
# Supply certificates in docker/nginx/ssl or enable the Certbot challenge before enabling HTTPS.
NGINX_HTTPS_ENABLED=${NGINX_HTTPS_ENABLED:-false}
# Set NGINX_PORT in docker/.env; Compose needs it before loading service files.
# Set NGINX_SSL_PORT in docker/.env; Compose needs it before loading service files.
NGINX_SSL_CERT_FILENAME=${NGINX_SSL_CERT_FILENAME:-dify.crt}
NGINX_SSL_CERT_KEY_FILENAME=${NGINX_SSL_CERT_KEY_FILENAME:-dify.key}
NGINX_SSL_PROTOCOLS=${NGINX_SSL_PROTOCOLS:-TLSv1.2 TLSv1.3}
NGINX_WORKER_PROCESSES=${NGINX_WORKER_PROCESSES:-auto}
NGINX_CLIENT_MAX_BODY_SIZE=${NGINX_CLIENT_MAX_BODY_SIZE:-100M}
NGINX_KEEPALIVE_TIMEOUT=${NGINX_KEEPALIVE_TIMEOUT:-65}
NGINX_PROXY_READ_TIMEOUT=${NGINX_PROXY_READ_TIMEOUT:-3600s}
NGINX_PROXY_SEND_TIMEOUT=${NGINX_PROXY_SEND_TIMEOUT:-3600s}
NGINX_ENABLE_CERTBOT_CHALLENGE=${NGINX_ENABLE_CERTBOT_CHALLENGE:-false}
NGINX_SOCKET_IO_UPSTREAM=${NGINX_SOCKET_IO_UPSTREAM:-api_websocket:5001}
CERTBOT_DOMAIN=${CERTBOT_DOMAIN:-}
@@ -1,18 +0,0 @@
# ------------------------------
# Nginx Configuration
# ------------------------------
NGINX_SERVER_NAME=_
NGINX_HTTPS_ENABLED=false
NGINX_PORT=80
NGINX_SSL_PORT=443
NGINX_SSL_CERT_FILENAME=dify.crt
NGINX_SSL_CERT_KEY_FILENAME=dify.key
NGINX_SSL_PROTOCOLS=TLSv1.2 TLSv1.3
NGINX_WORKER_PROCESSES=auto
NGINX_CLIENT_MAX_BODY_SIZE=100M
NGINX_KEEPALIVE_TIMEOUT=65
NGINX_PROXY_READ_TIMEOUT=3600s
NGINX_PROXY_SEND_TIMEOUT=3600s
NGINX_ENABLE_CERTBOT_CHALLENGE=false
NGINX_SOCKET_IO_UPSTREAM=api_websocket:5001
@@ -0,0 +1,30 @@
# Defaults for ssrf_proxy. Copy this file to ssrf-proxy.env to customize it.
# Edit the settings below in the copy; docker/.env takes precedence.
# Optional application settings are commented to retain their application defaults.
# SSRF_PROXY_HTTP_URL=http://ssrf_proxy:3128
# SSRF_PROXY_HTTPS_URL=http://ssrf_proxy:3128
SSRF_HTTP_PORT=${SSRF_HTTP_PORT:-3128}
SSRF_COREDUMP_DIR=${SSRF_COREDUMP_DIR:-/var/spool/squid}
# Comma-separated CIDR ranges that the SSRF proxy should allow even when they
# resolve to private, loopback, link-local, or otherwise non-public addresses.
# Leave empty (the default) to keep the deny-by-default policy. Required when
# Dify needs to reach internal HTTP endpoints (e.g. an internal API on
# http://172.21.x.x) from an HTTP Request node, a tool, or a plugin.
# Example: 172.21.0.0/16,10.0.0.0/8
SSRF_PROXY_ALLOW_PRIVATE_IPS=${SSRF_PROXY_ALLOW_PRIVATE_IPS:-}
# Comma-separated domain suffixes that the SSRF proxy should allow even when
# they would otherwise resolve to a denied range. Leave empty to keep the
# deny-by-default policy.
SSRF_PROXY_ALLOW_PRIVATE_DOMAINS=${SSRF_PROXY_ALLOW_PRIVATE_DOMAINS:-}
# SSRF_DEFAULT_TIME_OUT=5
# SSRF_DEFAULT_CONNECT_TIME_OUT=5
# SSRF_DEFAULT_READ_TIME_OUT=5
# SSRF_DEFAULT_WRITE_TIME_OUT=5
# SSRF_POOL_MAX_CONNECTIONS=100
# SSRF_POOL_MAX_KEEPALIVE_CONNECTIONS=20
# SSRF_POOL_KEEPALIVE_EXPIRY=5.0
# Container variable mappings; keep these expressions unchanged in the copy.
COREDUMP_DIR=${SSRF_COREDUMP_DIR:-/var/spool/squid}
HTTP_PORT=${SSRF_HTTP_PORT:-3128}
@@ -1,26 +0,0 @@
# ------------------------------
# Ssrf Proxy Configuration
# ------------------------------
SSRF_PROXY_HTTP_URL=http://ssrf_proxy:3128
SSRF_PROXY_HTTPS_URL=http://ssrf_proxy:3128
SSRF_HTTP_PORT=3128
SSRF_COREDUMP_DIR=/var/spool/squid
# Comma-separated CIDR ranges that the SSRF proxy should allow even when they
# resolve to private, loopback, link-local, or otherwise non-public addresses.
# Leave empty (the default) to keep the deny-by-default policy. Required when
# Dify needs to reach internal HTTP endpoints (e.g. an internal API on
# http://172.21.x.x) from an HTTP Request node, a tool, or a plugin.
# Example: 172.21.0.0/16,10.0.0.0/8
SSRF_PROXY_ALLOW_PRIVATE_IPS=
# Comma-separated domain suffixes that the SSRF proxy should allow even when
# they would otherwise resolve to a denied range. Leave empty to keep the
# deny-by-default policy.
SSRF_PROXY_ALLOW_PRIVATE_DOMAINS=
SSRF_DEFAULT_TIME_OUT=5
SSRF_DEFAULT_CONNECT_TIME_OUT=5
SSRF_DEFAULT_READ_TIME_OUT=5
SSRF_DEFAULT_WRITE_TIME_OUT=5
SSRF_POOL_MAX_CONNECTIONS=100
SSRF_POOL_MAX_KEEPALIVE_CONNECTIONS=20
SSRF_POOL_KEEPALIVE_EXPIRY=5.0
+16
View File
@@ -0,0 +1,16 @@
# Defaults for chroma. Copy this file to chroma.env to customize it.
# Edit the settings below in the copy; docker/.env takes precedence.
# Optional application settings are commented to retain their application defaults.
# CHROMA_DATABASE=default_database
# CHROMA_AUTH_PROVIDER=chromadb.auth.token_authn.TokenAuthClientProvider
# CHROMA_AUTH_CREDENTIALS=
# CHROMA_HOST=127.0.0.1
# CHROMA_PORT=8000
# CHROMA_TENANT=default_tenant
CHROMA_SERVER_AUTHN_CREDENTIALS=${CHROMA_SERVER_AUTHN_CREDENTIALS:-difyai123456}
CHROMA_SERVER_AUTHN_PROVIDER=${CHROMA_SERVER_AUTHN_PROVIDER:-chromadb.auth.token_authn.TokenAuthenticationServerProvider}
CHROMA_IS_PERSISTENT=${CHROMA_IS_PERSISTENT:-TRUE}
# Container variable mappings; keep these expressions unchanged in the copy.
IS_PERSISTENT=${CHROMA_IS_PERSISTENT:-TRUE}
@@ -1,13 +0,0 @@
# ------------------------------
# Chroma Configuration
# ------------------------------
CHROMA_DATABASE=default_database
CHROMA_AUTH_PROVIDER=chromadb.auth.token_authn.TokenAuthClientProvider
CHROMA_AUTH_CREDENTIALS=
CHROMA_HOST=127.0.0.1
CHROMA_PORT=8000
CHROMA_TENANT=default_tenant
CHROMA_SERVER_AUTHN_CREDENTIALS=difyai123456
CHROMA_SERVER_AUTHN_PROVIDER=chromadb.auth.token_authn.TokenAuthenticationServerProvider
CHROMA_IS_PERSISTENT=TRUE
@@ -0,0 +1,14 @@
# Defaults for couchbase-server. Copy this file to couchbase.env to customize it.
# Edit the settings below in the copy; docker/.env takes precedence.
# Optional application settings are commented to retain their application defaults.
COUCHBASE_PASSWORD=${COUCHBASE_PASSWORD:-password}
COUCHBASE_BUCKET_NAME=${COUCHBASE_BUCKET_NAME:-Embeddings}
# COUCHBASE_SCOPE_NAME=_default
# COUCHBASE_CONNECTION_STRING=couchbase://couchbase-server
COUCHBASE_USER=${COUCHBASE_USER:-Administrator}
# Container variable mappings; keep these expressions unchanged in the copy.
COUCHBASE_ADMINISTRATOR_USERNAME=${COUCHBASE_USER:-Administrator}
COUCHBASE_ADMINISTRATOR_PASSWORD=${COUCHBASE_PASSWORD:-password}
COUCHBASE_BUCKET=${COUCHBASE_BUCKET_NAME:-Embeddings}
@@ -1,9 +0,0 @@
# ------------------------------
# Couchbase Configuration
# ------------------------------
COUCHBASE_PASSWORD=password
COUCHBASE_BUCKET_NAME=Embeddings
COUCHBASE_SCOPE_NAME=_default
COUCHBASE_CONNECTION_STRING=couchbase://couchbase-server
COUCHBASE_USER=Administrator
@@ -0,0 +1,21 @@
# Defaults for elasticsearch. Copy this file to elasticsearch.env to customize it.
# Edit the settings below in the copy; docker/.env takes precedence.
# Optional application settings are commented to retain their application defaults.
# ELASTICSEARCH_CLOUD_URL=YOUR-ELASTICSEARCH_CLOUD_URL
ELASTICSEARCH_PASSWORD=${ELASTICSEARCH_PASSWORD:-elastic}
# Set KIBANA_PORT in docker/.env; Compose needs it before loading service files.
# ELASTICSEARCH_USE_CLOUD=false
# ELASTICSEARCH_API_KEY=YOUR-ELASTICSEARCH_API_KEY
# ELASTICSEARCH_VERIFY_CERTS=False
# ELASTICSEARCH_CA_CERTS=
# ELASTICSEARCH_REQUEST_TIMEOUT=100000
# ELASTICSEARCH_RETRY_ON_TIMEOUT=True
# ELASTICSEARCH_MAX_RETRIES=10
# ELASTICSEARCH_HOST=0.0.0.0
# Set ELASTICSEARCH_PORT in docker/.env; Compose needs it before loading service files.
# ELASTICSEARCH_USERNAME=elastic
# Set VECTOR_STORE in docker/.env to select the backend and its Compose profile together.
# Container variable mappings; keep these expressions unchanged in the copy.
ELASTIC_PASSWORD=${ELASTICSEARCH_PASSWORD:-elastic}
@@ -1,17 +0,0 @@
# ------------------------------
# Elasticsearch Configuration
# ------------------------------
ELASTICSEARCH_CLOUD_URL=YOUR-ELASTICSEARCH_CLOUD_URL
ELASTICSEARCH_PASSWORD=elastic
KIBANA_PORT=5601
ELASTICSEARCH_USE_CLOUD=false
ELASTICSEARCH_API_KEY=YOUR-ELASTICSEARCH_API_KEY
ELASTICSEARCH_VERIFY_CERTS=False
ELASTICSEARCH_CA_CERTS=
ELASTICSEARCH_REQUEST_TIMEOUT=100000
ELASTICSEARCH_RETRY_ON_TIMEOUT=True
ELASTICSEARCH_MAX_RETRIES=10
ELASTICSEARCH_HOST=0.0.0.0
ELASTICSEARCH_PORT=9200
ELASTICSEARCH_USERNAME=elastic
+20
View File
@@ -0,0 +1,20 @@
# Defaults for iris. Copy this file to iris.env to customize it.
# Edit the settings below in the copy; docker/.env takes precedence.
# Optional application settings are commented to retain their application defaults.
# IRIS_CONNECTION_URL=
# IRIS_MIN_CONNECTION=1
# IRIS_MAX_CONNECTION=3
# IRIS_TEXT_INDEX=true
# IRIS_TEXT_INDEX_LANGUAGE=en
IRIS_TIMEZONE=${IRIS_TIMEZONE:-UTC}
# IRIS_PASSWORD=Dify@1234
# IRIS_DATABASE=USER
# IRIS_SCHEMA=dify
# IRIS_HOST=iris
# Set IRIS_SUPER_SERVER_PORT in docker/.env; Compose needs it before loading service files.
# Set IRIS_WEB_SERVER_PORT in docker/.env; Compose needs it before loading service files.
# IRIS_USER=_SYSTEM
# Container variable mappings; keep these expressions unchanged in the copy.
TZ=${IRIS_TIMEZONE:-UTC}
-17
View File
@@ -1,17 +0,0 @@
# ------------------------------
# Iris Configuration
# ------------------------------
IRIS_CONNECTION_URL=
IRIS_MIN_CONNECTION=1
IRIS_MAX_CONNECTION=3
IRIS_TEXT_INDEX=true
IRIS_TEXT_INDEX_LANGUAGE=en
IRIS_TIMEZONE=UTC
IRIS_PASSWORD=Dify@1234
IRIS_DATABASE=USER
IRIS_SCHEMA=dify
IRIS_HOST=iris
IRIS_SUPER_SERVER_PORT=1972
IRIS_WEB_SERVER_PORT=52773
IRIS_USER=_SYSTEM
@@ -14,3 +14,12 @@ MILVUS_AUTHORIZATION_ENABLED=true
MILVUS_SECURE=false
MILVUS_SERVER_PEM_PATH=
MILVUS_SERVER_NAME=
# Dify vector client settings (API, workers and Beat)
# MILVUS_URI=http://host.docker.internal:19530
# MILVUS_TOKEN=
# MILVUS_USER=
# MILVUS_PASSWORD=
# MILVUS_ANALYZER_PARAMS=
# MILVUS_DATABASE=
# MILVUS_ENABLE_HYBRID_SEARCH=False
@@ -0,0 +1,21 @@
# Defaults for oceanbase. Copy this file to oceanbase.env to customize it.
# Edit the settings below in the copy; docker/.env takes precedence.
# Optional application settings are commented to retain their application defaults.
OCEANBASE_CLUSTER_NAME=${OCEANBASE_CLUSTER_NAME:-difyai}
OCEANBASE_MEMORY_LIMIT=${OCEANBASE_MEMORY_LIMIT:-6G}
OCEANBASE_VECTOR_PASSWORD=${OCEANBASE_VECTOR_PASSWORD:-difyai123456}
# Dify vector client settings (API, workers and Beat)
# Set OCEANBASE_VECTOR_PORT in docker/.env to keep the client and published port aligned.
# OCEANBASE_VECTOR_HOST=oceanbase
# OCEANBASE_VECTOR_USER=root@test
# OCEANBASE_VECTOR_DATABASE=test
# OCEANBASE_ENABLE_HYBRID_SEARCH=false
# OCEANBASE_FULLTEXT_PARSER=ik
# Container variable mappings; keep these expressions unchanged in the copy.
OB_CLUSTER_NAME=${OCEANBASE_CLUSTER_NAME:-difyai}
OB_MEMORY_LIMIT=${OCEANBASE_MEMORY_LIMIT:-6G}
OB_SYS_PASSWORD=${OCEANBASE_VECTOR_PASSWORD:-difyai123456}
OB_TENANT_PASSWORD=${OCEANBASE_VECTOR_PASSWORD:-difyai123456}
@@ -1,6 +0,0 @@
# ------------------------------
# Oceanbase Configuration
# ------------------------------
OCEANBASE_CLUSTER_NAME=difyai
OCEANBASE_MEMORY_LIMIT=6G
@@ -0,0 +1,17 @@
# Defaults for opengauss. Copy this file to opengauss.env to customize it.
# Edit the settings below in the copy; docker/.env takes precedence.
# Optional application settings are commented to retain their application defaults.
OPENGAUSS_PASSWORD=${OPENGAUSS_PASSWORD:-Dify@123}
OPENGAUSS_DATABASE=${OPENGAUSS_DATABASE:-dify}
# OPENGAUSS_MIN_CONNECTION=1
# OPENGAUSS_MAX_CONNECTION=5
# OPENGAUSS_ENABLE_PQ=false
# OPENGAUSS_HOST=opengauss
# Set OPENGAUSS_PORT in docker/.env; Compose needs it before loading service files.
OPENGAUSS_USER=${OPENGAUSS_USER:-postgres}
# Container variable mappings; keep these expressions unchanged in the copy.
GS_DB=${OPENGAUSS_DATABASE:-dify}
GS_PASSWORD=${OPENGAUSS_PASSWORD:-Dify@123}
GS_USERNAME=${OPENGAUSS_USER:-postgres}
@@ -1,12 +0,0 @@
# ------------------------------
# Opengauss Configuration
# ------------------------------
OPENGAUSS_PASSWORD=Dify@123
OPENGAUSS_DATABASE=dify
OPENGAUSS_MIN_CONNECTION=1
OPENGAUSS_MAX_CONNECTION=5
OPENGAUSS_ENABLE_PQ=false
OPENGAUSS_HOST=opengauss
OPENGAUSS_PORT=6600
OPENGAUSS_USER=postgres
@@ -0,0 +1,27 @@
# Defaults for opensearch. Copy this file to opensearch.env to customize it.
# Edit the settings below in the copy; docker/.env takes precedence.
# Optional application settings are commented to retain their application defaults.
# OPENSEARCH_PASSWORD=admin
# OPENSEARCH_AWS_REGION=ap-southeast-1
# OPENSEARCH_AWS_SERVICE=aoss
OPENSEARCH_INITIAL_ADMIN_PASSWORD=${OPENSEARCH_INITIAL_ADMIN_PASSWORD:-Qazwsxedc!@#123}
# Set OPENSEARCH_MEMLOCK_SOFT in docker/.env; Compose needs it before loading service files.
# Set OPENSEARCH_MEMLOCK_HARD in docker/.env; Compose needs it before loading service files.
# Set OPENSEARCH_NOFILE_SOFT in docker/.env; Compose needs it before loading service files.
# Set OPENSEARCH_NOFILE_HARD in docker/.env; Compose needs it before loading service files.
# OPENSEARCH_HOST=opensearch
# OPENSEARCH_PORT=9200
# OPENSEARCH_SECURE=true
# OPENSEARCH_VERIFY_CERTS=true
# OPENSEARCH_AUTH_METHOD=basic
# OPENSEARCH_USER=admin
OPENSEARCH_DISCOVERY_TYPE=${OPENSEARCH_DISCOVERY_TYPE:-single-node}
OPENSEARCH_BOOTSTRAP_MEMORY_LOCK=${OPENSEARCH_BOOTSTRAP_MEMORY_LOCK:-true}
OPENSEARCH_JAVA_OPTS_MIN=${OPENSEARCH_JAVA_OPTS_MIN:-512m}
OPENSEARCH_JAVA_OPTS_MAX=${OPENSEARCH_JAVA_OPTS_MAX:-1024m}
# Container variable mappings; keep these expressions unchanged in the copy.
OPENSEARCH_JAVA_OPTS=-Xms${OPENSEARCH_JAVA_OPTS_MIN:-512m} -Xmx${OPENSEARCH_JAVA_OPTS_MAX:-1024m}
bootstrap.memory_lock=${OPENSEARCH_BOOTSTRAP_MEMORY_LOCK:-true}
discovery.type=${OPENSEARCH_DISCOVERY_TYPE:-single-node}
@@ -1,22 +0,0 @@
# ------------------------------
# Opensearch Configuration
# ------------------------------
OPENSEARCH_PASSWORD=admin
OPENSEARCH_AWS_REGION=ap-southeast-1
OPENSEARCH_AWS_SERVICE=aoss
OPENSEARCH_INITIAL_ADMIN_PASSWORD=Qazwsxedc!@#123
OPENSEARCH_MEMLOCK_SOFT=-1
OPENSEARCH_MEMLOCK_HARD=-1
OPENSEARCH_NOFILE_SOFT=65536
OPENSEARCH_NOFILE_HARD=65536
OPENSEARCH_HOST=opensearch
OPENSEARCH_PORT=9200
OPENSEARCH_SECURE=true
OPENSEARCH_VERIFY_CERTS=true
OPENSEARCH_AUTH_METHOD=basic
OPENSEARCH_USER=admin
OPENSEARCH_DISCOVERY_TYPE=single-node
OPENSEARCH_BOOTSTRAP_MEMORY_LOCK=true
OPENSEARCH_JAVA_OPTS_MIN=512m
OPENSEARCH_JAVA_OPTS_MAX=1024m
+13
View File
@@ -0,0 +1,13 @@
# Defaults for oracle. Copy this file to oracle.env to customize it.
# Edit the settings below in the copy; docker/.env takes precedence.
# Optional application settings are commented to retain their application defaults.
# ORACLE_PASSWORD=dify
# ORACLE_DSN=oracle:1521/FREEPDB1
# ORACLE_CONFIG_DIR=/app/api/storage/wallet
# ORACLE_WALLET_LOCATION=/app/api/storage/wallet
# ORACLE_WALLET_PASSWORD=dify
# ORACLE_IS_AUTONOMOUS=false
# ORACLE_USER=dify
ORACLE_PWD=${ORACLE_PWD:-Dify123456}
ORACLE_CHARACTERSET=${ORACLE_CHARACTERSET:-AL32UTF8}
@@ -1,13 +0,0 @@
# ------------------------------
# Oracle Configuration
# ------------------------------
ORACLE_PASSWORD=dify
ORACLE_DSN=oracle:1521/FREEPDB1
ORACLE_CONFIG_DIR=/app/api/storage/wallet
ORACLE_WALLET_LOCATION=/app/api/storage/wallet
ORACLE_WALLET_PASSWORD=dify
ORACLE_IS_AUTONOMOUS=false
ORACLE_USER=dify
ORACLE_PWD=Dify123456
ORACLE_CHARACTERSET=AL32UTF8
@@ -0,0 +1,19 @@
# Defaults for pgvecto-rs. Copy this file to pgvecto-rs.env to customize it.
# Edit the settings below in the copy; docker/.env takes precedence.
# Optional application settings are commented to retain their application defaults.
# PGVECTO_RS_HOST=pgvecto-rs
# PGVECTO_RS_PORT=5432
# PGVECTO_RS_USER=postgres
# PGVECTO_RS_PASSWORD=difyai123456
# PGVECTO_RS_DATABASE=dify
PGVECTOR_PGDATA=${PGVECTOR_PGDATA:-/var/lib/postgresql/data/pgdata}
PGVECTOR_PGUSER=${PGVECTOR_PGUSER:-postgres}
PGVECTOR_POSTGRES_DB=${PGVECTOR_POSTGRES_DB:-dify}
PGVECTOR_POSTGRES_PASSWORD=${PGVECTOR_POSTGRES_PASSWORD:-difyai123456}
# Container variable mappings; keep these expressions unchanged in the copy.
PGDATA=${PGVECTOR_PGDATA:-/var/lib/postgresql/data/pgdata}
PGUSER=${PGVECTOR_PGUSER:-postgres}
POSTGRES_DB=${PGVECTOR_POSTGRES_DB:-dify}
POSTGRES_PASSWORD=${PGVECTOR_POSTGRES_PASSWORD:-difyai123456}
@@ -1,9 +0,0 @@
# ------------------------------
# Pgvecto Rs Configuration
# ------------------------------
PGVECTO_RS_HOST=pgvecto-rs
PGVECTO_RS_PORT=5432
PGVECTO_RS_USER=postgres
PGVECTO_RS_PASSWORD=difyai123456
PGVECTO_RS_DATABASE=dify
@@ -0,0 +1,27 @@
# Defaults for pgvector. Copy this file to pgvector.env to customize it.
# Edit the settings below in the copy; docker/.env takes precedence.
# Optional application settings are commented to retain their application defaults.
PGVECTOR_PGUSER=${PGVECTOR_PGUSER:-postgres}
PGVECTOR_POSTGRES_PASSWORD=${PGVECTOR_POSTGRES_PASSWORD:-difyai123456}
PGVECTOR_POSTGRES_DB=${PGVECTOR_POSTGRES_DB:-dify}
PGVECTOR_PGDATA=${PGVECTOR_PGDATA:-/var/lib/postgresql/data/pgdata}
PGVECTOR_PG_BIGM=${PGVECTOR_PG_BIGM:-false}
PGVECTOR_PG_BIGM_VERSION=${PGVECTOR_PG_BIGM_VERSION:-1.2-20240606}
# Dify vector client settings (API, workers and Beat)
# PGVECTOR_HOST=pgvector
# PGVECTOR_PORT=5432
# PGVECTOR_USER=postgres
# PGVECTOR_PASSWORD=difyai123456
# PGVECTOR_DATABASE=dify
# PGVECTOR_MIN_CONNECTION=1
# PGVECTOR_MAX_CONNECTION=5
# Container variable mappings; keep these expressions unchanged in the copy.
PGDATA=${PGVECTOR_PGDATA:-/var/lib/postgresql/data/pgdata}
PGUSER=${PGVECTOR_PGUSER:-postgres}
PG_BIGM=${PGVECTOR_PG_BIGM:-false}
PG_BIGM_VERSION=${PGVECTOR_PG_BIGM_VERSION:-1.2-20240606}
POSTGRES_DB=${PGVECTOR_POSTGRES_DB:-dify}
POSTGRES_PASSWORD=${PGVECTOR_POSTGRES_PASSWORD:-difyai123456}
@@ -1,8 +0,0 @@
# ------------------------------
# Pgvector Configuration
# ------------------------------
PGVECTOR_PGUSER=postgres
PGVECTOR_POSTGRES_PASSWORD=difyai123456
PGVECTOR_POSTGRES_DB=dify
PGVECTOR_PGDATA=/var/lib/postgresql/data/pgdata
+12
View File
@@ -0,0 +1,12 @@
# Defaults for qdrant. Copy this file to qdrant.env to customize it.
# Edit the settings below in the copy; docker/.env takes precedence.
# Optional application settings are commented to retain their application defaults.
QDRANT_API_KEY=${QDRANT_API_KEY:-difyai123456}
# Dify vector client settings (API, workers and Beat)
# QDRANT_URL=http://qdrant:6333
# QDRANT_CLIENT_TIMEOUT=20
# QDRANT_GRPC_ENABLED=false
# QDRANT_GRPC_PORT=6334
# QDRANT_REPLICATION_FACTOR=1
@@ -1,4 +0,0 @@
# ------------------------------
# Qdrant Configuration
# ------------------------------
+10
View File
@@ -0,0 +1,10 @@
# Defaults for seekdb. Copy this file to seekdb.env to customize it.
# Edit the settings below in the copy; docker/.env takes precedence.
# Optional application settings are commented to retain their application defaults.
SEEKDB_MEMORY_LIMIT=${SEEKDB_MEMORY_LIMIT:-2G}
OCEANBASE_VECTOR_PASSWORD=${OCEANBASE_VECTOR_PASSWORD:-difyai123456}
# Container variable mappings; keep these expressions unchanged in the copy.
MEMORY_LIMIT=${SEEKDB_MEMORY_LIMIT:-2G}
ROOT_PASSWORD=${OCEANBASE_VECTOR_PASSWORD:-difyai123456}
@@ -1,4 +0,0 @@
# ------------------------------
# Seekdb Configuration
# ------------------------------
@@ -0,0 +1,37 @@
# Defaults for weaviate. Copy this file to weaviate.env to customize it.
# Edit the settings below in the copy; docker/.env takes precedence.
# Optional application settings are commented to retain their application defaults.
WEAVIATE_PERSISTENCE_DATA_PATH=${WEAVIATE_PERSISTENCE_DATA_PATH:-/var/lib/weaviate}
WEAVIATE_QUERY_DEFAULTS_LIMIT=${WEAVIATE_QUERY_DEFAULTS_LIMIT:-25}
WEAVIATE_AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED=${WEAVIATE_AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED:-true}
WEAVIATE_DEFAULT_VECTORIZER_MODULE=${WEAVIATE_DEFAULT_VECTORIZER_MODULE:-none}
WEAVIATE_CLUSTER_HOSTNAME=${WEAVIATE_CLUSTER_HOSTNAME:-node1}
WEAVIATE_AUTHENTICATION_APIKEY_ENABLED=${WEAVIATE_AUTHENTICATION_APIKEY_ENABLED:-true}
WEAVIATE_AUTHENTICATION_APIKEY_ALLOWED_KEYS=${WEAVIATE_AUTHENTICATION_APIKEY_ALLOWED_KEYS:-WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih}
WEAVIATE_AUTHENTICATION_APIKEY_USERS=${WEAVIATE_AUTHENTICATION_APIKEY_USERS:-hello@dify.ai}
WEAVIATE_AUTHORIZATION_ADMINLIST_ENABLED=${WEAVIATE_AUTHORIZATION_ADMINLIST_ENABLED:-true}
WEAVIATE_AUTHORIZATION_ADMINLIST_USERS=${WEAVIATE_AUTHORIZATION_ADMINLIST_USERS:-hello@dify.ai}
WEAVIATE_DISABLE_TELEMETRY=${WEAVIATE_DISABLE_TELEMETRY:-false}
WEAVIATE_ENABLE_TOKENIZER_GSE=${WEAVIATE_ENABLE_TOKENIZER_GSE:-false}
WEAVIATE_ENABLE_TOKENIZER_KAGOME_JA=${WEAVIATE_ENABLE_TOKENIZER_KAGOME_JA:-false}
WEAVIATE_ENABLE_TOKENIZER_KAGOME_KR=${WEAVIATE_ENABLE_TOKENIZER_KAGOME_KR:-false}
# Dify vector client settings (API, workers and Beat)
# WEAVIATE_TOKENIZATION=word
# Container variable mappings; keep these expressions unchanged in the copy.
AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED=${WEAVIATE_AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED:-true}
AUTHENTICATION_APIKEY_ALLOWED_KEYS=${WEAVIATE_AUTHENTICATION_APIKEY_ALLOWED_KEYS:-WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih}
AUTHENTICATION_APIKEY_ENABLED=${WEAVIATE_AUTHENTICATION_APIKEY_ENABLED:-true}
AUTHENTICATION_APIKEY_USERS=${WEAVIATE_AUTHENTICATION_APIKEY_USERS:-hello@dify.ai}
AUTHORIZATION_ADMINLIST_ENABLED=${WEAVIATE_AUTHORIZATION_ADMINLIST_ENABLED:-true}
AUTHORIZATION_ADMINLIST_USERS=${WEAVIATE_AUTHORIZATION_ADMINLIST_USERS:-hello@dify.ai}
CLUSTER_HOSTNAME=${WEAVIATE_CLUSTER_HOSTNAME:-node1}
DEFAULT_VECTORIZER_MODULE=${WEAVIATE_DEFAULT_VECTORIZER_MODULE:-none}
DISABLE_TELEMETRY=${WEAVIATE_DISABLE_TELEMETRY:-false}
ENABLE_TOKENIZER_GSE=${WEAVIATE_ENABLE_TOKENIZER_GSE:-false}
ENABLE_TOKENIZER_KAGOME_JA=${WEAVIATE_ENABLE_TOKENIZER_KAGOME_JA:-false}
ENABLE_TOKENIZER_KAGOME_KR=${WEAVIATE_ENABLE_TOKENIZER_KAGOME_KR:-false}
PERSISTENCE_DATA_PATH=${WEAVIATE_PERSISTENCE_DATA_PATH:-/var/lib/weaviate}
QUERY_DEFAULTS_LIMIT=${WEAVIATE_QUERY_DEFAULTS_LIMIT:-25}
@@ -1,18 +0,0 @@
# ------------------------------
# Weaviate Configuration
# ------------------------------
WEAVIATE_PERSISTENCE_DATA_PATH=/var/lib/weaviate
WEAVIATE_QUERY_DEFAULTS_LIMIT=25
WEAVIATE_AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED=true
WEAVIATE_DEFAULT_VECTORIZER_MODULE=none
WEAVIATE_CLUSTER_HOSTNAME=node1
WEAVIATE_AUTHENTICATION_APIKEY_ENABLED=true
WEAVIATE_AUTHENTICATION_APIKEY_ALLOWED_KEYS=WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih
WEAVIATE_AUTHENTICATION_APIKEY_USERS=hello@dify.ai
WEAVIATE_AUTHORIZATION_ADMINLIST_ENABLED=true
WEAVIATE_AUTHORIZATION_ADMINLIST_USERS=hello@dify.ai
WEAVIATE_DISABLE_TELEMETRY=false
WEAVIATE_ENABLE_TOKENIZER_GSE=false
WEAVIATE_ENABLE_TOKENIZER_KAGOME_JA=false
WEAVIATE_ENABLE_TOKENIZER_KAGOME_KR=false
+7 -40
View File
@@ -64,50 +64,20 @@ def generate_shared_env_block(env_vars, anchor_name="shared-api-worker-env"):
return "\n".join(lines)
def create_env_files_from_example(env_example_path):
"""
Creates actual env files from .env.example by copying the categorized .env.example files.
This allows docker-compose to use env_file references.
Supports per-module structure with subdirectories.
"""
def create_env_file_from_example(env_example_path):
"""Create the required root .env without activating optional provider settings."""
base_dir = os.path.dirname(os.path.abspath(env_example_path))
root_env_file = os.path.join(base_dir, ".env")
if not os.path.exists(root_env_file):
with open(env_example_path, "r", encoding="utf-8") as src, open(
root_env_file, "w", encoding="utf-8", newline="\n"
) as dst:
with (
open(env_example_path, "r", encoding="utf-8") as src,
open(root_env_file, "w", encoding="utf-8", newline="\n") as dst,
):
dst.write(src.read())
print(f"Created {root_env_file}")
else:
print(f"{root_env_file} already exists, skipping")
envs_dir = os.path.join(base_dir, "envs")
if not os.path.isdir(envs_dir):
print(f"No envs directory found at {envs_dir}, skipping split env files")
return []
created_files = []
# Walk through all .env.example files in subdirectories
for root, dirs, files in os.walk(envs_dir):
for file in files:
if file.endswith('.env.example'):
example_file = os.path.join(root, file)
env_file = example_file.replace('.env.example', '.env')
if os.path.exists(env_file):
print(f"{env_file} already exists, skipping")
continue
# Copy .example to actual file
with open(example_file, "r", encoding="utf-8") as src, open(
env_file, "w", encoding="utf-8", newline="\n"
) as dst:
dst.write(src.read())
created_files.append(env_file)
print(f"Created {env_file}")
return created_files
def insert_shared_env(template_path, output_path, header_comments):
"""
@@ -146,11 +116,8 @@ def main():
print(f"Error: File {path} does not exist.")
sys.exit(1)
# Create env files from categorized .env.example files
# These files are used by docker-compose's env_file directive
# This ensures .env files exist even in CI/CD environments
if "--compose-only" not in sys.argv:
create_env_files_from_example(env_example_path)
create_env_file_from_example(env_example_path)
# Copy template to output with header comments
# The template now uses env_file references instead of a huge YAML anchor
+573
View File
@@ -0,0 +1,573 @@
"""Exercise copied Docker defaults without starting containers."""
import json
import os
import re
import shutil
import subprocess
import sys
import tempfile
import unittest
from pathlib import Path
DOCKER_DIR = Path(__file__).resolve().parents[1]
class ComposeEnvironmentTests(unittest.TestCase):
def setUp(self):
self.temp = tempfile.TemporaryDirectory(prefix="dify-compose-env-")
self.addCleanup(self.temp.cleanup)
self.project = Path(self.temp.name)
shutil.copyfile(DOCKER_DIR / "docker-compose.yaml", self.project / "docker-compose.yaml")
for source in (DOCKER_DIR / "envs").rglob("*.defaults"):
target = self.project / source.relative_to(DOCKER_DIR)
target.parent.mkdir(parents=True, exist_ok=True)
shutil.copyfile(source, target)
self.copy_template(
".env.example",
".env",
{"DIFY_AGENT_LOCAL_SANDBOX_AUTH_TOKEN": "test-sandbox-token"},
)
def copy_template(self, source, target, values=None):
content = (DOCKER_DIR / source).read_text()
for key, value in (values or {}).items():
content, count = re.subn(
rf"(?m)^(?:#\s*)?{re.escape(key)}=.*$",
lambda _, setting=f"{key}={value}": setting,
content,
)
self.assertEqual(count, 1, f"Expected one setting for {key} in {source}")
destination = self.project / target
destination.parent.mkdir(parents=True, exist_ok=True)
destination.write_text(content)
def override_root(self, values):
with (self.project / ".env").open("a") as target:
target.write("\n" + "\n".join(f"{key}={value}" for key, value in values.items()) + "\n")
def render(self, *compose_args):
inputs = set(re.findall(r"\$\{(\w+)", (DOCKER_DIR / "docker-compose.yaml").read_text()))
for source in (DOCKER_DIR / "envs").rglob("*.defaults"):
inputs.update(re.findall(r"\$\{(\w+)", source.read_text()))
env = {key: value for key, value in os.environ.items() if key not in inputs and not key.startswith("COMPOSE_")}
result = subprocess.run(
[
"docker",
"compose",
*compose_args,
"--profile",
"*",
"config",
"--format",
"json",
],
cwd=self.project,
env=env,
text=True,
capture_output=True,
check=True,
)
return json.loads(result.stdout)["services"]
def test_minimal_setup_has_working_connection_defaults(self):
services = self.render()
for name in ("api", "worker", "worker_beat", "plugin_daemon"):
values = services[name]["environment"]
for key, expected in {
"DB_HOST": "db_postgres",
"DB_USERNAME": "postgres",
"DB_PASSWORD": "difyai123456",
"DB_PORT": "5432",
"REDIS_HOST": "redis",
"REDIS_PORT": "6379",
"REDIS_PASSWORD": "difyai123456",
}.items():
self.assertEqual(values[key], expected, f"{name}.{key}")
self.assertEqual(services["plugin_daemon"]["environment"]["DB_DATABASE"], "dify_plugin")
self.assertEqual(services["web"]["environment"]["SERVER_CONSOLE_API_URL"], "http://api:5001")
self.assertEqual(services["web"]["environment"]["NEXT_PUBLIC_ENABLE_AGENT_V2"], "true")
self.assertEqual(
services["local_sandbox"]["environment"]["SHELLCTL_AUTH_TOKEN"],
"test-sandbox-token",
)
self.assertEqual(
services["agent_backend"]["environment"]["DIFY_AGENT_LOCAL_SANDBOX_AUTH_TOKEN"],
"test-sandbox-token",
)
self.assertFalse((DOCKER_DIR / ".env.custom.example").exists())
self.assertEqual(services["elasticsearch"]["environment"]["xpack.security.enabled"], "true")
self.assertEqual(services["elasticsearch"]["environment"]["discovery.type"], "single-node")
def test_copying_defaults_without_changes_preserves_service_values(self):
baseline = self.render()
for source in (DOCKER_DIR / "envs").rglob("*.defaults"):
# This KnowledgeFS parser file deliberately has a different override basename.
if source.name == "knowledge-fs-unstructured-service.defaults":
continue
self.copy_template(
str(source.relative_to(DOCKER_DIR)),
str(source.relative_to(DOCKER_DIR).with_suffix(".env")),
)
actual = self.render()
for name, service in baseline.items():
for key, value in service.get("environment", {}).items():
self.assertEqual(actual[name]["environment"].get(key), value, f"{name}.{key}")
def test_api_and_weaviate_defaults_and_isolated_overrides(self):
cases = [
("core-services/shared", "worker", "CELERY_WORKER_AMOUNT", "CELERY_WORKER_AMOUNT", "4", "2", "3"),
("core-services/shared", "api", "SERVER_WORKER_CLASS", "SERVER_WORKER_CLASS", "gevent", "sync", "gthread"),
("core-services/shared", "api", "GUNICORN_TIMEOUT", "GUNICORN_TIMEOUT", "360", "120", "240"),
(
"vectorstores/weaviate",
"weaviate",
"WEAVIATE_AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED",
"AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED",
"true",
"false",
"true",
),
]
root = self.project / ".env"
initial_root = root.read_text()
for path, service, key, native, default, custom, root_value in cases:
with self.subTest(setting=key):
source = f"envs/{path}.defaults"
target = f"envs/{path}.env"
try:
self.assertEqual(self.render()[service]["environment"].get(native), default, "fresh deployment")
# Exercise root customization without any service override file.
self.override_root({key: custom})
self.assertEqual(self.render()[service]["environment"][native], custom, "root only")
root.write_text(initial_root)
self.assertEqual(self.render()[service]["environment"][native], default, "restored root")
self.copy_template(source, target)
self.assertEqual(self.render()[service]["environment"][native], default, "unchanged copy")
self.copy_template(source, target, {key: custom})
self.assertEqual(self.render()[service]["environment"][native], custom, "service only")
# Leave the service file unchanged while changing only the root file.
self.override_root({key: root_value})
self.assertEqual(self.render()[service]["environment"][native], root_value, "root precedence")
finally:
(self.project / target).unlink(missing_ok=True)
root.write_text(initial_root)
def test_copying_shared_defaults_does_not_activate_optional_settings(self):
baseline = self.render()
self.copy_template("envs/core-services/shared.defaults", "envs/core-services/shared.env")
# Compare the entire configuration, including extra variables introduced by an unsafe copy.
self.assertEqual(self.render(), baseline)
def test_consolidated_settings_reach_consumers_and_respect_root_precedence(self):
api_services = ("api", "api_websocket")
worker_services = (
"worker",
"worker_knowledge_fs_upgrade",
"knowledge_fs_document_worker",
"knowledge_fs_source_worker",
"knowledge_fs_research_worker",
"knowledge_fs_maintenance_worker",
"knowledge_fs_dispatch_worker",
)
vector_clients = (*api_services, "worker", "worker_knowledge_fs_upgrade", "worker_beat")
cases = [
(
"core-services/shared.defaults",
(*api_services, *worker_services, "worker_beat"),
{
"CODE_MAX_STRING_LENGTH": ("500000", "600000"),
"ENABLE_OTEL": ("true", "false"),
"OTLP_BASE_ENDPOINT": ("http://collector:4318", "http://root-collector:4318"),
"CELERY_BROKER_VISIBILITY_TIMEOUT": ("10800", "14400"),
"OPS_TRACE_QUEUE": ("custom_traces", "root_traces"),
"KNOWLEDGE_FS_BACKGROUND_POLL_INTERVAL_SECONDS": ("7", "9"),
"AGENT_BACKEND_HOME_SNAPSHOT_TIMEOUT_SECONDS": ("60", "90"),
"UNSTRUCTURED_API_URL": ("http://parser:8000", "http://root-parser:8000"),
"S3_ENDPOINT": ("https://storage.example.test", "https://root-storage.example.test"),
"TENCENT_COS_SECRET_KEY": ("app-storage-key", "root-storage-key"),
},
),
(
"core-services/api.defaults",
api_services,
{"GUNICORN_KEEP_ALIVE": ("20", "30"), "RESPECT_XFORWARD_HEADERS_ENABLED": ("false", "true")},
),
(
"core-services/worker.defaults",
worker_services,
{"CELERY_AUTO_SCALE": ("true", "false"), "CELERY_MIN_WORKERS": ("2", "3")},
),
("vectorstores/weaviate.defaults", vector_clients, {"WEAVIATE_TOKENIZATION": ("field", "word")}),
("vectorstores/qdrant.defaults", vector_clients, {"QDRANT_CLIENT_TIMEOUT": ("42", "60")}),
(
"vectorstores/oceanbase.defaults",
vector_clients,
{"OCEANBASE_VECTOR_HOST": ("custom-oceanbase", "root-oceanbase")},
),
("vectorstores/pgvector.defaults", vector_clients, {"PGVECTOR_MIN_CONNECTION": ("2", "3")}),
("vectorstores/milvus.env.example", vector_clients, {"MILVUS_DATABASE": ("custom_dify", "root_dify")}),
]
root = self.project / ".env"
initial_root = root.read_text()
for template, consumers, values in cases:
source = f"envs/{template}"
target = source.removesuffix(".env.example").removesuffix(".defaults") + ".env"
custom = {key: pair[0] for key, pair in values.items()}
root_values = {key: pair[1] for key, pair in values.items()}
with self.subTest(template=template):
try:
# Each stage changes one file; no other service override is present.
self.override_root(custom)
services = self.render()
for name in consumers:
for key, value in custom.items():
self.assertEqual(services[name]["environment"][key], value, f"root only: {name}.{key}")
root.write_text(initial_root)
self.copy_template(source, target, custom)
services = self.render()
for name in consumers:
for key, value in custom.items():
self.assertEqual(services[name]["environment"][key], value, f"service only: {name}.{key}")
self.override_root(root_values)
services = self.render()
for name in consumers:
for key, value in root_values.items():
self.assertEqual(
services[name]["environment"][key], value, f"root precedence: {name}.{key}"
)
finally:
(self.project / target).unlink(missing_ok=True)
root.write_text(initial_root)
def test_existing_shared_overrides_and_empty_value_cleanup(self):
values = {
"API_WEBSOCKET_WORKER_AMOUNT": "3",
"CELERY_MAX_WORKERS": "5",
"QDRANT_URL": "http://existing-qdrant:6333",
"PGVECTOR_HOST": "existing-pgvector",
"MILVUS_DATABASE": "existing_dify",
"CELERY_WORKER_AMOUNT": "",
"SERVER_WORKER_CLASS": "",
"GUNICORN_TIMEOUT": "",
}
override = self.project / "envs/core-services/shared.env"
override.write_text("\n".join(f"{key}={value}" for key, value in values.items()) + "\n")
services = self.render()
for name in ("api", "api_websocket", "worker", "worker_knowledge_fs_upgrade", "worker_beat"):
for key, value in values.items():
self.assertEqual(services[name]["environment"][key], value, f"existing override: {name}.{key}")
# Cleaning accidental blanks in the existing file restores Docker defaults without replacing it.
override.write_text("\n".join(f"{key}={value}" for key, value in values.items() if value) + "\n")
services = self.render()
self.assertEqual(services["worker"]["environment"]["CELERY_WORKER_AMOUNT"], "4")
self.assertEqual(services["api"]["environment"]["SERVER_WORKER_CLASS"], "gevent")
self.assertEqual(services["api"]["environment"]["GUNICORN_TIMEOUT"], "360")
self.assertEqual(services["api_websocket"]["environment"]["API_WEBSOCKET_WORKER_AMOUNT"], "3")
self.assertEqual(services["worker"]["environment"]["QDRANT_URL"], values["QDRANT_URL"])
def test_service_overrides_and_root_precedence(self):
cases = [
(
"infrastructure/nginx",
"nginx",
"NGINX_CLIENT_MAX_BODY_SIZE",
"NGINX_CLIENT_MAX_BODY_SIZE",
"200M",
"300M",
),
(
"core-services/web",
"web",
"TOP_K_MAX_VALUE",
"TOP_K_MAX_VALUE",
"23",
"24",
),
(
"core-services/sandbox",
"sandbox",
"SANDBOX_WORKER_TIMEOUT",
"WORKER_TIMEOUT",
"120",
"121",
),
(
"core-services/plugin-daemon",
"plugin_daemon",
"PLUGIN_DAEMON_PORT",
"SERVER_PORT",
"5998",
"5999",
),
(
"vectorstores/weaviate",
"weaviate",
"WEAVIATE_QUERY_DEFAULTS_LIMIT",
"QUERY_DEFAULTS_LIMIT",
"66",
"67",
),
(
"core-services/api",
"api",
"API_SENTRY_DSN",
"SENTRY_DSN",
"https://api.example.test/1",
"https://api.example.test/2",
),
(
"core-services/worker",
"worker",
"API_SENTRY_DSN",
"SENTRY_DSN",
"https://worker.example.test/1",
"https://api.example.test/2",
),
(
"infrastructure/certbot",
"certbot",
"CERTBOT_DOMAIN",
"CERTBOT_DOMAIN",
"one.example.test",
"two.example.test",
),
(
"vectorstores/opensearch",
"opensearch",
"OPENSEARCH_JAVA_OPTS_MIN",
"OPENSEARCH_JAVA_OPTS",
"768m",
"896m",
),
]
for path, _, key, _, local, _ in cases:
self.copy_template(f"envs/{path}.defaults", f"envs/{path}.env", {key: local})
services = self.render()
for _, service, _, native, local, _ in cases:
expected = f"-Xms{local} -Xmx1024m" if native == "OPENSEARCH_JAVA_OPTS" else local
self.assertEqual(
services[service]["environment"][native],
expected,
f"{service}.{native}",
)
self.override_root({key: value for _, _, key, _, _, value in cases})
services = self.render()
for _, service, _, native, _, value in cases:
expected = f"-Xms{value} -Xmx1024m" if native == "OPENSEARCH_JAVA_OPTS" else value
self.assertEqual(
services[service]["environment"][native],
expected,
f"{service}.{native}",
)
def test_database_redis_overrides_reach_clients_and_commands(self):
for name in (
"shared",
"api",
"worker",
"worker-beat",
"plugin-daemon",
"dify-agent",
):
self.copy_template(f"envs/core-services/{name}.defaults", f"envs/core-services/{name}.env")
self.copy_template(
"envs/databases/db-postgres.defaults",
"envs/databases/db-postgres.env",
{
"DB_USERNAME": "custom_user",
"DB_PASSWORD": "test-db-password",
"DB_DATABASE": "custom_dify",
"POSTGRES_MAX_CONNECTIONS": "321",
},
)
self.copy_template(
"envs/databases/redis.defaults",
"envs/databases/redis.env",
{"REDIS_PASSWORD": "test-redis-password"},
)
services = self.render()
for name in ("api", "worker", "worker_beat", "plugin_daemon"):
values = services[name]["environment"]
self.assertEqual(values["DB_USERNAME"], "custom_user", name)
self.assertEqual(values["DB_PASSWORD"], "test-db-password", name)
self.assertEqual(values["REDIS_PASSWORD"], "test-redis-password", name)
for name in ("api", "worker", "worker_beat"):
self.assertEqual(
services[name]["environment"]["CELERY_BROKER_URL"],
"redis://:test-redis-password@redis:6379/1",
name,
)
self.assertEqual(
services["db_postgres"]["environment"]["POSTGRES_PASSWORD"],
"test-db-password",
)
self.assertEqual(services["plugin_daemon"]["environment"]["DB_DATABASE"], "dify_plugin")
self.assertEqual(services["redis"]["environment"]["REDISCLI_AUTH"], "test-redis-password")
self.assertEqual(
services["agent_backend"]["environment"]["DIFY_AGENT_REDIS_URL"],
"redis://:test-redis-password@redis:6379/2",
)
# Execute the command with a harmless stand-in for the image entrypoint.
executable = self.project / "docker-entrypoint.sh"
executable.write_text('#!/bin/sh\nprintf "%s\\n" "$@"\n')
executable.chmod(0o755)
for service in ("db_postgres", "db_mysql", "redis"):
config = services[service]
command = [arg.replace("$$", "$") for arg in config["command"]]
env = {
**config["environment"],
"PATH": f"{self.project}:{os.environ['PATH']}",
}
if service == "redis":
env["REDIS_PASSWORD"] = "literal $(touch should-not-exist) ; password"
result = subprocess.run(
command,
cwd=self.project,
env=env,
text=True,
capture_output=True,
check=True,
)
args = result.stdout.splitlines()
self.assertEqual(
args[0],
{
"db_postgres": "postgres",
"db_mysql": "mysqld",
"redis": "redis-server",
}[service],
)
if service == "db_postgres":
self.assertIn("max_connections=321", args)
if service == "redis":
self.assertEqual(args[-1], env["REDIS_PASSWORD"])
self.assertFalse((self.project / "should-not-exist").exists())
def test_root_plugin_credentials_reach_every_consumer(self):
for name in ("shared", "api", "worker", "worker-beat", "plugin-daemon", "dify-agent"):
self.copy_template(f"envs/core-services/{name}.defaults", f"envs/core-services/{name}.env")
api_services = (
"api",
"api_websocket",
"worker",
"worker_knowledge_fs_upgrade",
"knowledge_fs_document_worker",
"knowledge_fs_source_worker",
"knowledge_fs_research_worker",
"knowledge_fs_maintenance_worker",
"knowledge_fs_dispatch_worker",
)
cases = {
"PLUGIN_DAEMON_KEY": {
**dict.fromkeys((*api_services, "worker_beat"), "PLUGIN_DAEMON_KEY"),
"plugin_daemon": "SERVER_KEY",
"agent_backend": "DIFY_AGENT_PLUGIN_DAEMON_API_KEY",
},
"PLUGIN_DIFY_INNER_API_KEY": {
**dict.fromkeys(api_services, "INNER_API_KEY_FOR_PLUGIN"),
"plugin_daemon": "DIFY_INNER_API_KEY",
"agent_backend": "DIFY_AGENT_INNER_API_KEY",
"knowledge_fs": "DIFY_INNER_API_KEY",
},
}
for key, consumers in cases.items():
value = f"custom-{key.lower()}"
self.override_root({key: value})
services = self.render()
for name, native in consumers.items():
self.assertEqual(services[name]["environment"][native], value, f"{name}.{native}")
if key == "PLUGIN_DIFY_INNER_API_KEY":
for name in api_services:
if name.startswith("knowledge_fs_"):
self.assertEqual(services[name]["environment"]["DIFY_INNER_API_KEY"], value, name)
def test_websocket_uses_copied_api_settings(self):
self.copy_template(
"envs/core-services/api.defaults",
"envs/core-services/api.env",
{"API_WEBSOCKET_WORKER_AMOUNT": "3"},
)
config = self.render()["api_websocket"]
# Stand in for the image's entrypoint; exercise the actual shell expansion.
command = [arg.replace("$$", "$") for arg in config["entrypoint"]]
command[-1] = command[-1].replace("exec /bin/bash /entrypoint.sh", 'printf "%s" "$SERVER_WORKER_AMOUNT"')
result = subprocess.run(
command,
env=config["environment"],
text=True,
capture_output=True,
check=True,
)
self.assertEqual(result.stdout, "3")
def test_e2b_overlay_preserves_service_credentials(self):
self.copy_template("docker-compose.e2b.yaml", "docker-compose.e2b.yaml")
self.copy_template(
"envs/core-services/dify-agent.defaults",
"envs/core-services/dify-agent.env",
{
"DIFY_AGENT_E2B_API_KEY": "service-api-key",
"DIFY_AGENT_E2B_TEMPLATE": "custom-template",
},
)
values = self.render("-f", "docker-compose.yaml", "-f", "docker-compose.e2b.yaml")["agent_backend"][
"environment"
]
self.assertEqual(values["DIFY_AGENT_RUNTIME_BACKEND"], "e2b")
self.assertEqual(values["DIFY_AGENT_E2B_API_KEY"], "service-api-key")
self.assertEqual(values["DIFY_AGENT_E2B_TEMPLATE"], "custom-template")
def test_generator_creates_only_root_env_and_preserves_edits(self):
for source in (
"generate_docker_compose",
".env.example",
"docker-compose-template.yaml",
"envs/security.env.example",
):
self.copy_template(source, source)
(self.project / ".env").unlink()
command = [sys.executable, str(self.project / "generate_docker_compose")]
subprocess.run(command, check=True, capture_output=True)
self.assertEqual(
(self.project / ".env").read_text(),
(DOCKER_DIR / ".env.example").read_text(),
)
self.assertEqual(list((self.project / "envs").rglob("*.env")), [])
(self.project / ".env").write_text("COMPOSE_PROFILES=custom\n")
subprocess.run(command, check=True, capture_output=True)
self.assertEqual((self.project / ".env").read_text(), "COMPOSE_PROFILES=custom\n")
def test_runtime_secrets_stay_in_their_service(self):
self.copy_template(
"envs/core-services/api.defaults",
"envs/core-services/api.env",
{"PASSWORD_PEPPER": "api-only-test-secret"},
)
self.copy_template(
"envs/core-services/web.defaults",
"envs/core-services/web.env",
{"NEXT_PUBLIC_ENABLE_HITL_IM": "true"},
)
services = self.render()
self.assertEqual(services["web"]["environment"]["NEXT_PUBLIC_ENABLE_HITL_IM"], "true")
self.assertEqual(services["api"]["environment"]["PASSWORD_PEPPER"], "api-only-test-secret")
for name in ("web", "plugin_daemon", "nginx", "db_postgres", "agent_backend"):
self.assertNotIn("PASSWORD_PEPPER", services[name]["environment"], name)
def test_generated_compose_matches_template(self):
self.assertTrue(
(DOCKER_DIR / "docker-compose.yaml")
.read_text()
.endswith((DOCKER_DIR / "docker-compose-template.yaml").read_text())
)
if __name__ == "__main__":
unittest.main()