把 Dify 装进自己的服务器:Docker Compose 私有化部署实战

系列第一篇我们问过:什么时候应该用云版,什么时候值得私有化。走到收官篇,答案可以更具体了——当数据边界、网络接入、成本结构或定制能力要求你掌握运行环境时,私有化才有价值;它也意味着可用性、安全、备份和升级都由你负责。
本文按一次真实部署应有的顺序讲解 Docker Compose 路线,但不伪装成某台生产服务器的验收记录。
验证边界:内容基于 2026-09-10 获取的 Dify 官方 Docker Compose、环境变量、常见问题、Docker 排错及存储迁移文档。本文未在一台全新服务器上实际执行完整安装、域名解析和灾难恢复演练,因此命令是实施清单,不是“已部署成功”证明。目标版本发布说明优先级高于本文。
| # | 主题 | 状态 |
|---|---|---|
| 1—9 | 从平台认知到生产运维 | 已发布 |
| 10 | Docker Compose 私有化部署 | ← 系列收官 |
部署前先决定四件事
- 域名与 HTTPS 在哪里终止:Dify 自带 Nginx,还是外部 Caddy/Nginx/负载均衡;
- 数据放哪里:本机卷、云数据库、对象存储、独立向量库;
- 谁管理 Secret:
.env只是起点,生产更适合密钥管理服务; - 如何备份和恢复:先写恢复目标,再选择存储。
如果只准备了一台服务器和一句 docker compose up -d,那是体验环境,不是生产方案。
第一步:核对基础条件
Dify 官方当前 Docker Compose 文档要求 Docker Compose 2.24.0 或更高。先检查:
docker --version
docker compose version
git --version
df -h
free -h
同时确认 80/443 是否被占用、服务器能否拉取镜像、DNS 是否已指向主机、出站网络能否访问模型和插件服务。资源规格应以目标版本官方文档及你的并发量为准,不要照抄旧文章中的固定数字。
第二步:固定版本,不要永远追 main
git clone https://github.com/langgenius/dify.git
cd dify
git fetch --tags
git checkout <经过评估的发布标签>
cd docker
cp .env.example .env
生产部署使用明确 Release/Tag,并记录 Git SHA。直接跟随 main 会把“升级”变成不可审计的代码漂移。
第三步:把 .env 当配置合同
不要逐行盲抄 200 多个变量。先分组管理:
| 分组 | 典型内容 | 重点 |
|---|---|---|
| URL 与跨域 | Console/API/Web App URL、Cookie、CORS、WebSocket | 协议、域名和子域一致 |
| 数据库与队列 | PostgreSQL、Redis、Celery | 强密码、网络隔离、连接池 |
| 文件与向量 | STORAGE_TYPE、对象存储、VECTOR_STORE |
持久化、备份、迁移方案 |
| 安全 | 应用 Secret、插件密钥、SSRF 规则 | 不用默认值、不进 Git |
| 运行限制 | 上传大小、超时、并发 | 按业务与资源设上限 |
生成高强度 Secret,例如:
openssl rand -base64 48
把值写入受控的 Secret 管理系统或权限严格的部署配置。.env 加入忽略规则,日志和截图中也不得出现。官方文档说明 docker/.env 的值优先于 docker/envs/*.env,排查“改了没生效”时要先看覆盖关系。
第四步:先启动,再逐服务验证
docker compose pull
docker compose up -d
docker compose ps
“容器 Up”只说明进程在运行。继续检查反代入口、API 健康、数据库迁移、Worker、Sandbox、插件服务以及浏览器静态资源;至少完成一次登录、创建应用、模型调用、文件上传、知识库索引和工作流执行。
排障先锁定服务:
docker compose logs --tail=200 nginx
docker compose logs --tail=200 api
docker compose logs --tail=200 worker
docker compose logs --tail=200 web
避免一上来把所有日志混在一起搜索,时间线和根因会更难判断。
第五步:域名、反代与 HTTPS
若使用外部反代,只让 Dify 内部端口监听受控网络,公网入口统一走 443。转发时保留 Host、X-Forwarded-For、X-Forwarded-Proto,并正确支持 WebSocket。
修改默认入口端口可使用官方文档中的 EXPOSE_NGINX_PORT 与 EXPOSE_NGINX_SSL_PORT。如果前后端跨子域,还要核对 Cookie 域、CORS 以及 NEXT_PUBLIC_SOCKET_URL;线上 HTTPS 对应 WebSocket 应使用 wss://。
浏览器出现 CORS 或 401 时,先比较浏览器实际请求 URL、公开配置和反代头,不要先清数据库或重装容器。
数据到底在哪里
Dify 不是只有一个数据库:关系数据、Redis 状态、上传文件、向量索引、插件与归档日志可能分散在不同卷或外部服务。
备份清单至少包含:
- PostgreSQL 一致性备份;
- 文件存储或对象存储桶;
- 向量数据库及其集合;
.env的安全副本和密钥恢复方案;- 部署版本、Compose 文件和自定义反代配置;
- 插件清单及外部凭证的引用关系。
备份是否成功,不能只看文件存在。必须定期在隔离环境恢复,并验证登录、应用、知识库、文件与工作流。
升级的正确姿势
- 阅读目标版本 Release Notes 和升级指南;
- 备份数据库、文件、向量数据和配置;
- 在测试环境用生产数据副本演练;
- 对比新旧
.env.example,补新增或变更变量; - 固定新 Tag,拉取镜像并执行升级;
- 检查迁移日志和核心回归;
- 观察错误、延迟与资源;
- 达不到门槛就按已演练方案回退。
官方明确提醒:不同版本升级步骤可能不同,且升级后必须比较 .env.example。因此不存在一条永远正确的通用升级命令。
向量库和文件存储迁移
切换 VECTOR_STORE 不会让原索引凭空搬家。官方文档提供专门的向量迁移步骤;执行前先备份,核对源与目标配置,并在迁移后用固定问题集比较召回数量、排序和答案质量。
从本地文件迁到 S3/OSS 等对象存储也要迁移已有对象,不只是改 STORAGE_TYPE。还要验证权限、区域、Endpoint、路径风格、生命周期和跨域配置。
常见故障的排查顺序
502 Bad Gateway
先看 Nginx 日志,再看 api/web 是否健康、端口和服务名能否在 Compose 网络中解析。502 是网关没有拿到有效上游响应,不等于“域名没备案”或“浏览器缓存坏了”。
端口冲突
用 lsof -i :80 或 ss -lntp 找占用者。决定复用现有反代或改映射,不要随机停掉未知进程。
容器反复重启
查看 docker compose ps、目标容器日志和退出码,重点检查数据库连接、权限、挂载路径、Secret 和依赖健康。反复 down/up 只会重演同一错误。
上传失败或节点超时
上传大小需要同时核对应用限制与反代限制;节点超时可通过官方变量如 TEXT_GENERATION_TIMEOUT_MS 调整,但调大之前先定位慢在模型、网络、工具还是 Worker 饱和。
无法访问宿主机 localhost
容器里的 localhost 指容器自身,不是宿主机。应使用可达的宿主机地址或同一 Docker 网络的服务名,并评估由此带来的 SSRF 风险。
安全基线
- 管理入口限制来源并启用强身份验证;
- 数据库、Redis、向量库不直接暴露公网;
- Secret 使用最小权限并定期轮换;
- SSRF 代理阻止访问云元数据与内网敏感地址;
- 镜像和依赖定期扫描,升级先演练;
- 日志脱敏,备份加密,恢复操作留审计;
- 管理员密码重置、成员邀请和离职回收有流程。
上线验收单
- 固定版本、SHA 和镜像;
- 默认密码和 Secret 已替换;
- HTTPS、Cookie、CORS、WebSocket 已验证;
- 数据库、Redis、文件、向量库均持久化;
- 模型、插件、Sandbox、Worker 真实调用成功;
- 监控、日志、告警和容量阈值已配置;
- 备份已在隔离环境恢复成功;
- 升级与回退已演练;
- 隐私、权限和审计满足业务要求。
私有化买到的是控制权,不是免维护。真正的完成标准,是你能解释每份数据在哪、每个入口谁能访问、每次升级怎样失败以及怎样恢复。
系列结语
十篇文章从“Dify 是什么”走到“如何自己维护 Dify”。中间所有节点和技巧最终都服务于同一件事:把模型的不确定能力装进一个有输入合同、数据边界、执行路径和恢复机制的系统。
先用云版理解产品和验证价值;需要私有化时,再带着真实的合规、成本与运维目标迁移。工具选型不是信仰,能持续解决问题才是答案。
资料来源
- Dify 官方文档:使用 Docker Compose 部署、环境变量、常见问题、Docker 问题、存储与迁移(2026-09-10 获取)。
- Dify GitHub Releases:实际升级时应以目标版本发布说明为准。
- 封面为 Codex 原生生成,并已做关键区域放大检查。