Dify 的可视化编排界面把模型调用、条件分支、知识检索和工具节点放在同一张画布上。对自托管部署而言,难点不在启动某个 Web 容器,而在于同时管理 API、异步任务、数据库、缓存、向量存储、插件服务、代码沙箱和反向代理。
工作流画布用于连接模型、检索、条件判断和输出节点。
本文采用仓库维护的docker/docker-compose.yaml部署路径,不在宿主机直接构建前端或安装 Python 依赖。这样可以让应用及其基础组件使用仓库定义的镜像和容器网络,减少宿主机运行时版本差异带来的问题。
一、部署结构与组件关系
Dify 不是单容器应用。不同版本的 Compose 文件可能调整服务名称或增加可选组件,因此应以当前检出版本中的docker-compose.yaml为准。典型服务职责如下:
| 组件 | 主要职责 | 持久化要求 |
|---|---|---|
web | 管理界面与应用页面 | 通常不保存核心业务数据 |
api | HTTP API、鉴权、应用和知识库管理 | 文件目录需要持久化 |
worker | 文档处理、索引、异步任务 | 依赖数据库、缓存和文件存储 |
worker_beat | 调度周期性任务 | 依赖数据库和缓存 |
db | 保存账号、应用、工作流和运行记录 | 必须备份 |
redis | 缓存与任务队列 | 建议持久化 |
weaviate等 | 保存知识库向量索引 | 必须与数据库一起考虑备份 |
sandbox | 隔离执行工作流中的代码 | 不应直接暴露到公网 |
plugin_daemon | 管理和运行插件 | 插件数据需要持久化 |
ssrf_proxy | 约束容器对外访问路径 | 仅供内部服务调用 |
nginx | 对外提供统一 HTTP/HTTPS 入口 | 证书启用时需要持久化 |
Compose 内部服务通过容器名称通信,例如 API 连接db和redis,不需要把 PostgreSQL、Redis、向量数据库或沙箱端口映射到公网。
对话流在多轮会话基础上组织模型、知识检索和分支逻辑。
二、准备 Linux 服务器
仓库给出的最低要求是:
- CPU 不少于 2 核
- 内存不少于 4 GiB
- 已安装 Git
- 已安装 Docker Engine
- Docker Compose 不低于 v2.24.0
- 服务器能够拉取部署所需镜像
4 GiB 是启动要求,不代表适合所有知识库规模。文档解析、向量化和多个工作流并发会继续占用内存与磁盘。生产环境还要预留数据库增长、镜像更新和备份空间。
检查系统资源以及 Docker 版本:
uname-anprocfree-hdf-hdockerversiondockercompose version如果docker compose version低于 v2.24.0,应先按照 Docker 官方文档更新 Compose 插件。不要使用旧的独立docker-compose命令替代仓库要求的 Compose v2。
对外访问通常只需要 TCP 80;启用 HTTPS 后再开放 TCP 443。SSH 端口应限制为管理来源地址。以下以 UFW 为例,ADMIN_CIDR是需要替换的管理网络变量:
sudoufw allow from ADMIN_CIDR to any port22proto tcpsudoufw allow80/tcp# 只有完成 HTTPS 配置后才需要开放sudoufw allow443/tcpsudoufw status数据库、缓存、沙箱和向量数据库端口不应创建公网放行规则。
三、获取固定版本的仓库
直接长期跟随main分支会增加不可预测的升级变化。部署前可在项目 Releases 页面选择一个发布标签,并将其写入DIFY_REF。下面的<release-tag>是变量,不是固定版本号:
exportDIFY_REF="<release-tag>"gitclone--branch"$DIFY_REF"--depth1\https://github.com/langgenius/dify.gitcddifygitlog-1--onelinegitstatus--short--branch--branch用来固定发布标签,--depth 1可以减少首次下载量。若后续需要在同一目录切换版本,再执行完整的标签获取操作。
提交摘要可以定位当前代码快照,但提交哈希不能替代发布标签。
仓库状态应保持干净。部署相关文件集中在docker/目录,其中需要重点关注:
dify/ ├── api/ # 后端 API 源码 ├── web/ # 前端源码 ├── docker/ │ ├── docker-compose.yaml # 容器编排入口 │ ├── .env.example # 基础环境变量模板 │ ├── envs/ # 按主题拆分的高级配置 │ └── volumes/ # 默认本地持久化目录 └── README.md不同发布版本的目录可能变化,实际文件列表可用下面的命令核对:
gitls-filesdocker|sort四、创建并检查环境配置
进入 Compose 目录,从当前版本自带的模板创建配置文件:
cddockercp.env.example .envchmod600.env不要从旧教程复制整份.env。环境变量会随版本增加或改名,当前标签中的.env.example才与当前 Compose 文件匹配。
至少检查以下配置项:
# 应替换为随机值 SECRET_KEY=YOUR_RANDOM_SECRET # 初始化管理员时使用;完成初始化后仍应妥善保存配置 INIT_PASSWORD=YOUR_INITIAL_PASSWORD # 数据库与缓存凭据 DB_PASSWORD=YOUR_DATABASE_PASSWORD REDIS_PASSWORD=YOUR_REDIS_PASSWORD # 内部服务鉴权 SANDBOX_API_KEY=YOUR_SANDBOX_KEY PLUGIN_DIFY_INNER_API_KEY=YOUR_PLUGIN_KEY # 默认反向代理端口 EXPOSE_NGINX_PORT=80 EXPOSE_NGINX_SSL_PORT=443 # 默认向量存储类型,以当前模板支持的值为准 VECTOR_STORE=weaviate可以生成多组互不相同的随机值,不要把命令输出直接留在终端历史之外的公开位置:
openssl rand-base6442openssl rand-hex32几个 URL 类变量需要按访问方式处理:
CONSOLE_API_URL:管理界面调用 API 的外部地址。CONSOLE_WEB_URL:管理界面的外部地址。SERVICE_API_URL:应用服务 API 的外部地址。APP_API_URL:已发布应用调用 API 的外部地址。APP_WEB_URL:已发布 Web 应用的外部地址。FILES_URL:外部服务访问上传文件时使用的地址。INTERNAL_FILES_URL:容器内部访问文件服务的地址。
单域名、同源部署通常可以沿用模板默认值。只有在前端、API、文件服务使用不同域名或外部反向代理时,才需要分别填写完整 URL。协议或域名写错时,常见表现是页面可以打开,但浏览器请求被跨域策略拦截,或者模型服务无法获取上传文件。
修改完成后先让 Compose 解析配置:
dockercompose config--quietdockercompose config--services第一条命令用于发现变量替换或 YAML 结构错误;第二条命令显示当前版本实际会启动的服务。不要把docker compose config的完整输出直接发布,因为解析结果可能包含密码和密钥。
五、拉取镜像并启动服务
在dify/docker目录执行:
dockercompose pulldockercompose up-dpull单独执行可以把镜像下载问题与容器启动问题分开。up -d会创建内部网络、启动依赖服务,并在后台运行应用容器。
随后查看状态:
dockercomposepsdockercompose logs--tail=100apidockercompose logs--tail=100workerdockercompose logs--tail=100nginx验收时不要只看docker compose up -d的退出码。需要关注以下现象:
docker compose ps中核心服务处于Up或running状态。- 数据库、缓存和向量存储没有持续重启。
- API 日志中没有数据库认证、迁移或存储目录权限错误。
- Worker 能连接任务队列,没有反复出现连接拒绝。
- Nginx 没有持续报告上游服务不可用。
若某个容器处于Restarting,应先查看该容器日志,而不是反复执行up -d:
dockercompose logs--tail=200<service-name>dockerinspect<container-name>--format'{{.State.Status}} {{.State.ExitCode}} {{.State.Error}}'其中<service-name>和<container-name>都是需要根据docker compose ps替换的变量。
六、初始化并验证 Dify
在服务器本机检查 HTTP 入口:
curl-Ihttp://127.0.0.1/installcurl-Ihttp://127.0.0.1/初始化页面地址为:
http://<服务器地址>/install<服务器地址>是变量。首次访问/install时应出现管理员初始化界面;完成初始化后,根路径应能进入登录页面。HTTP 状态可能因当前版本的重定向策略有所不同,但不应持续返回502或连接失败。
对话应用页面用于检查消息输入、模型响应和会话记录是否连通。
完成初始化后,可按以下路径做应用级验收:
- 使用管理员账号进入控制台。
- 在模型设置中配置一个可访问的模型接口。
- 创建最小对话应用,只保留开始节点、模型节点和输出节点。
- 在调试界面发送一条测试消息。
- 查看运行日志,确认调用进入预期模型。
- 发布测试应用,再验证外部应用页面和 API 入口。
应用调试页可以核对输入、模型输出和运行状态。
如果页面正常但模型调用失败,说明 Web、API 和数据库链路大体可用,后续应检查模型凭据、接口地址、容器出站网络及 DNS,而不是重新安装整个服务。
七、避免在宿主机直接构建前端
Dify Web 工程对 Node.js 运行时有明确约束。终端记录显示,使用 Node.jsv24.18.0执行安装时,项目要求的运行时为^22.22.1,因此 npm 返回EBADDEVENGINES。
宿主机 Node.js 不满足项目约束时,npm 会在依赖安装阶段终止。
这也是自托管部署优先使用仓库 Compose 镜像的原因:普通部署不需要在宿主机运行npm install或npm run build。只有进行源码开发时,才需要按照当前web/package.json、锁文件和开发文档准备对应 Node.js 版本及包管理器。
八、反向代理与 HTTPS
默认 Compose 使用 Nginx 作为统一入口。部署时应保持以下边界:
- 只公开 Web 入口端口。
db、redis、sandbox、ssrf_proxy和向量存储仅加入 Compose 内部网络。- HTTPS 终止位置只能有明确的一层,避免代理之间循环跳转。
- 外部代理使用 HTTPS 时,要正确传递
Host、X-Forwarded-Proto和客户端地址。 - 修改域名或协议后,同步检查
.env中控制台、应用 API 和文件 URL。
出现登录后跳回登录页、浏览器混合内容警告或上传文件无法访问时,应重点核对外部协议、Cookie 安全属性和 URL 配置。HTTPS 配置完成前,不要提前把所有外部 URL 写成无法访问的https://地址。
九、备份持久化数据
升级前至少备份:
docker/.env- PostgreSQL 数据
docker/volumes/下的应用文件- 向量存储数据
- 插件数据
- 自定义证书和反向代理配置
先创建数据库逻辑备份。命令从数据库容器自身读取用户名和数据库名,可兼容已经修改过的默认值:
cd/path/to/dify/dockerBACKUP_DIR="/path/to/backups/dify-$(date+%Y%m%d-%H%M%S)"mkdir-p"$BACKUP_DIR"cp.env"$BACKUP_DIR/env"dockercomposeexec-Tdbsh-c\'pg_dump -U "$POSTGRES_USER" "$POSTGRES_DB"'\>"$BACKUP_DIR/postgres.sql"为了获得一致的文件级副本,可在安排维护窗口后停止服务,再归档持久化目录:
dockercompose stoptar-C/path/to/dify/docker\-czf"$BACKUP_DIR/volumes.tar.gz"\volumesdockercompose start sha256sum"$BACKUP_DIR/postgres.sql""$BACKUP_DIR/volumes.tar.gz"只备份 PostgreSQL 并不完整,因为上传文件、插件和向量索引可能位于其他卷中。恢复演练还应验证备份文件能够解压、SQL 文件非空,并记录对应的 Dify 发布标签。
十、升级到新的发布版本
不要在没有备份的情况下直接切换代码和镜像。升级流程可以按以下顺序执行:
cd/path/to/difygitfetch--tagsexportDIFY_REF="<new-release-tag>"gitcheckout"$DIFY_REF"cddockercp.env".env.before-${DIFY_REF}"diff-u.env.example .env||truedockercompose config--quietdockercompose pulldockercompose up-ddiff的目的不是让.env与模板完全一致,而是发现新版本新增、删除或改名的变量。升级后重新检查:
dockercomposepsdockercompose logs--tail=200apidockercompose logs--tail=200workercurl-Ihttp://127.0.0.1/installcurl-Ihttp://127.0.0.1/数据库迁移通常由应用启动流程处理,迁移期间不要同时运行新旧两个版本的 API 或 Worker。确认新版本可用后再清理无引用镜像,且不要执行会删除卷的docker compose down -v。
十一、常见故障排查
1. 浏览器访问返回 502
通常是 Nginx 已启动,但 API 或 Web 上游尚未就绪。
dockercomposepsdockercompose logs--tail=200nginxdockercompose logs--tail=200apidockercompose logs--tail=200web检查上游容器是否持续重启,以及数据库迁移是否仍在进行。
2. API 提示数据库认证失败
检查.env中数据库密码是否修改完整,尤其要避免只修改应用侧连接密码,却没有同步数据库容器初始化变量。
如果数据库目录已经使用旧密码初始化,单纯修改.env不会自动修改数据库内部账号密码。应恢复原凭据,或在明确了解数据库操作的前提下修改账号密码。
3. Worker 无法连接 Redis
确认redis服务状态、密码配置和内部主机名。容器内连接地址应使用 Compose 服务名,不要写成127.0.0.1,因为容器里的回环地址只指向容器自身。
dockercompose logs--tail=200redisdockercompose logs--tail=200worker4. 知识库文档一直停留在排队状态
重点检查:
- Worker 是否运行。
- Redis 队列是否可连接。
- 文档解析是否触发内存不足。
- 向量存储是否正常。
- Embedding 模型接口是否可访问。
- 上传目录是否具有写权限。
可同时观察资源占用:
dockerstatsdf-hdockercompose logs--tail=200worker5. 上传文件后模型无法读取
检查FILES_URL是否能被模型服务访问。浏览器能打开文件不等于外部模型接口能够访问该地址,内网域名、回环地址或错误的 HTTPS 配置都可能导致读取失败。
6. 容器反复因内存不足退出
使用下面的命令确认是否发生 OOM:
dockerinspect<container-name>\--format'OOMKilled={{.State.OOMKilled}} ExitCode={{.State.ExitCode}}'dmesg-T|grep-i-E'out of memory|killed process'如果文档索引阶段触发 OOM,应降低并发、减少单批文档规模或增加可用内存,而不是只设置无限重启。
7. 修改.env后配置没有生效
仅执行docker compose restart不一定会重新创建容器并加载新环境变量。应执行:
dockercompose config--quietdockercompose up-dup -d会根据配置差异重建需要更新的容器。
十二、日常运维检查
日常检查可以保留为一组固定命令:
cd/path/to/dify/dockerdockercomposepsdockercompose logs--since=30m api worker nginxdockerstats --no-streamdf-hdu-shvolumes需要持续关注的不是单一 CPU 数值,而是以下趋势:
- API 或 Worker 是否频繁重启。
- 数据库和向量索引目录是否持续增长。
- 文档处理期间内存是否逼近上限。
- 磁盘剩余空间能否容纳下一次镜像拉取和备份。
- 日志中是否重复出现认证失败、超时、队列阻塞或上游不可达。
- 备份文件是否具有校验值,并能在隔离环境完成恢复。
十三、部署验收与结果判定
完成安装或升级后,应同时检查容器、HTTP 入口和应用调用链,不能只以登录页面能够打开作为部署完成的依据。可使用下面的命令收集一次验收状态:
cd/path/to/dify/dockerdockercompose config--quietdockercomposepsdockercompose logs--since=10m api worker nginxcurl-Ihttp://127.0.0.1/installcurl-Ihttp://127.0.0.1/部署结果可按以下条件判定:
- Compose 配置能够通过解析,没有缺失变量或 YAML 结构错误。
api、web、worker、db、redis、nginx以及当前版本启用的向量存储和插件服务没有持续重启。- 本机 HTTP 请求能够得到响应,不持续出现连接失败或
502。 - 管理员可以登录控制台并保存模型配置。
- 最小对话应用能够完成一次调试调用,运行日志中可以找到对应记录。
- 发布后的应用页面或 API 入口可以访问。
- 上传文件时,API、Worker、文件存储和模型访问链路没有出现权限或地址错误。
- 数据库与持久化目录已经纳入备份,备份文件具有校验值,并记录了对应发布标签。
只有容器启动但模型调用失败时,应将结果记录为基础服务可访问、应用调用链未通过;知识库文档持续排队时,应将结果记录为异步处理或向量化链路未通过。这样的判定可以把部署问题限制到具体组件,避免因局部配置错误重复安装整个服务栈。
十四、项目与官方参考
- Dify 源码仓库:https://github.com/langgenius/dify
- 自托管安装文档:https://docs.dify.ai/getting-started/install-self-hosted
- 环境变量说明:https://docs.dify.ai/getting-started/install-self-hosted/environments
- 自托管常见问题:https://docs.dify.ai/getting-started/install-self-hosted/faqs
- 源码部署文档:https://docs.dify.ai/getting-started/install-self-hosted/local-source-code
- Docker Engine 安装文档:https://docs.docker.com/engine/install/
- Docker Compose 文档:https://docs.docker.com/compose/
- Dify 发布记录:https://github.com/langgenius/dify/releases
仓库的许可证文件以 Apache 2.0 为基础并包含附加条件。部署、再分发或修改项目前,应以当前版本仓库中的LICENSE原文为准。