news 2026/10/24 7:41:27

Dify本地部署全流程:Docker Compose启动、排错、备份与升级

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Dify本地部署全流程:Docker Compose启动、排错、备份与升级

简介:Dify 官方项目完整源码安装包取自 GitHub,面向希望本地部署、体验或二次开发 Dify 的开发者与运维人员,可解决官方安装包获取与项目主体文件缺失的问题,也适合作为软件或插件类项目研究其工程组织。压缩包共 2000 个文件,约 20.25MB,以 Python 后端代码、JSON/YAML 配置、CSS/JS 前端资源为主,另含 Markdown 文档、Shell 脚本、HTML 模板、SQL 初始化语句及 XML/TXT 辅助文件,基本覆盖运行、配置、界面与部署所需组件。已有 2916 人学习或下载,在 Dify 实践群体中具备一定参考价值。解压后可沿目录查看核心模块、配置项与文档说明,用于搭建本地环境、梳理前后端协作方式,或作为插件扩展与二次开发的起点。

1. 一套跑在自己机器上的 LLM 应用平台:先把「安装包」这三个字说清楚

很多人搜 Dify 官方安装包,期望拿到一个双击就能装完的 exe 或者 setup 向导,结果在 GitHub 下载下来解压一看,是一堆 YAML 和.env.example,当场愣住。这是最常见的预期错位:官方发布的是源码归档,真正的“安装”动作发生在docker/目录里,靠 Docker Compose 拉起一整套容器。想清楚这一点,后面所有步骤才顺。适合谁?想把知识库问答、Agent 编排、模型接入握在自己手里、又不想从零写后端的团队;也适合只想在本地跑一套环境做验证的开发者。反过来,如果你的机器只有 2G 内存、或者公司网络完全禁止容器出网,这套东西会让你很痛苦,先别急。

2. 拆开压缩包:docker 目录里到底躺着什么

2.1 Releases 页面下到的东西与你想的不一样

在仓库的 Releases 页面,通常能拿到两类东西:一类是自动生成的源码归档(Source code 的 zip 和 tar.gz),另一类是随版本附带的说明或校验文件。绝大多数人需要的就是源码归档。解压之后你会得到一个以版本号命名的顶层目录,里面是后端、前端、SDK 等多个子目录,部署入口只有一个:docker/。

我把这个目录里真正影响部署的文件列一下,方便你判断哪些能动、哪些别碰:

路径作用是否建议修改
docker/.env.example全部环境变量的样板,键名以此为准只读,复制成.env再改
docker/docker-compose.yaml服务编排、镜像标签、卷挂载、依赖关系一般不直接改,用 override 文件
docker/nginx/反向代理配置、端口、上传大小、超时按需改
docker/ssrf_proxy/出站代理配置,限制容器能访问哪些地址内网环境必看
docker/volumes/数据卷宿主机挂载点,数据库、文件、向量库都在这不要手删

这里有个血泪经验:docker-compose.yaml和.env.example是成对演进的,新版本经常新增服务、新增必填变量。你如果只把docker/目录覆盖成新的,.env还是半年前那份,docker compose up大概率会报某个变量为空导致容器直接退出。正确做法永远是先 diff 一遍.env.example,把新增的键补进自己的.env,再动镜像。

另外提醒一句:不要试图从包里找.sql初始化脚本手动建库。表结构由 api 容器启动时执行的迁移流程负责,你手工建反而会打架。

2.2 十个容器各管一段:谁在前、谁在后

一套标准编排起来大致是这些角色,不同版本可能增减,但职责划分基本稳定:

  • nginx:唯一对外的入口,把/console/api、/api、/v1等路径分发给后端,其余静态资源给前端。
  • web:前端服务,负责界面渲染,本身不碰数据库。
  • api:核心后端,处理控制台接口、应用运行时接口、对外 Service API。
  • worker:异步任务进程,知识库文档解析、分段、向量化、网页抓取都在这里跑。它和 api 共用同一份代码和同一个数据库。
  • db:PostgreSQL,存应用配置、会话、消息、账号等结构化数据。
  • redis:缓存加消息队列,worker 从这里取任务。
  • weaviate:默认向量库,存文档分段的向量。
  • sandbox:代码执行与工具调用的隔离环境。
  • plugin_daemon:插件运行时,模型供应商、工具插件都跑在它下面。
  • ssrf_proxy:出站代理,沙箱和部分外部请求经由它出去。

调用链理解清楚,排查就快一半:浏览器 → nginx → web/api;api 读写 db、redis、向量库;上传文档后 api 把任务丢进 redis,worker 消费并把向量写进 weaviate;api 调插件时走 plugin_daemon;沙箱执行外部请求时走 ssrf_proxy。哪一环断,现象都不一样。

2.3 为什么官方只认 Docker Compose 这条路

有人问能不能pip install一把梭。理论上后端是 Python 的,前端是 Node 的,你自己拼也能拼出来,但代价是:Python 版本要卡准、前端要单独构建、PostgreSQL 和 Redis 得自己装、向量库还得挑一个装、迁移脚本要手动跑、worker 要单独起进程并保证和 api 用同一份配置。这套东西手工对齐,熟手也要折腾大半天,而且一旦出问题,版本组合的锅很难甩清。

Compose 的价值就在于把这堆版本约束固化成一份文件:镜像标签写死、卷挂载写死、启动顺序用depends_on加健康检查兜住。代价是资源占用——一套全起来,空跑也要吃掉两三个 G 内存,向量库和数据库是大头。所以 2 核 4G 是能跑的下限,4 核 8G 才是能安心用的配置;如果你还要在上面跑本地 embedding 模型,另算。

3. 从解压到第一次登录:一套能复现的启动流程

3.1 起容器之前的三项检查

别急着up,先花两分钟把下面三件事确认掉,能省掉后面一半的报错。

第一是 Docker 与 Compose 插件版本。现在用的是docker compose(空格,插件形态),不是老的docker-compose(横杠)。跑一下确认:

# 确认 docker 引擎与 compose 插件都在 docker version --format '{{.Server.Version}}' docker compose version

第二是内核参数。向量库这类组件对内存映射区有要求,vm.max_map_count太小会在启动阶段直接崩,日志里是一串看不懂的映射失败:

# 查看当前值,低于 262144 建议调高 sysctl vm.max_map_count # 临时生效(重启失效),永久生效写到 /etc/sysctl.conf sudo sysctl -w vm.max_map_count=262144

第三是端口和磁盘。默认会占用宿主机 80 端口做入口,很多机器上这个端口已经被别的 Web 服务占了;磁盘方面镜像加卷,留 20G 起步比较稳,知识库一多,volumes/app/storage涨得比你想的快。

# 看 80/443 有没有被占 ss -lntp | grep -E ':(80|443)\s' # 看根分区余量,单位 G df -h /

提示:如果 80 端口被占又不想动别的服务,别去改 compose 里的端口映射,直接改.env里的对外端口变量即可,下一节会说。

3.2 .env 里真正必须改的六个键

把样板复制成实际配置,然后只改必要的部分。全部键都改一遍是给自己挖坑,尤其是那些你并不理解的开关。

cd docker cp .env.example .env # 生成一个强随机密钥,作为会话与凭据加密的根 openssl rand -base64 42

拿到随机串之后,按下面几类逐个落实:

密钥类:SECRET_KEY必须换,且一旦定下来就不能再改。它参与登录态签名和模型供应商凭据的加密存储,中途换掉,已存的 API Key 全部解不开,用户也得重新登录。这是我最想强调的一条。

数据库与缓存口令:DB_PASSWORD、REDIS_PASSWORD换成强口令。这两个值要和 compose 里传给 db、redis 容器的变量保持一致,通常样板里已经用变量引用串好了,你只改这一处就行。

对外地址类:CONSOLE_API_URL、CONSOLE_WEB_URL、SERVICE_API_URL、APP_WEB_URL、FILES_URL。本机自测可以留空走相对路径;一旦挂到域名后面,这几个必须填成浏览器能访问到的完整地址,否则上传的文件预览打不开、插件回调找不到入口。

端口类:对外暴露端口那个变量,改成你实际空闲的端口,比如 8080。

向量库选择:VECTOR_STORE决定用哪个向量库。默认值和 compose 里默认启用的服务是配套的,改之前先确认对应服务已经启用,别只改一半。

迁移开关:MIGRATION_ENABLED保持开启,让 api 容器启动时自动建表升级。

一个常被忽略的点:.env里的值如果包含$、#、空格,记得加引号,否则会被解析截断,报错信息完全指不到这一行。

3.3 启动、看日志与健康校验

配置齐了就起。第一次会拉不少镜像,耐心等,别在中途 Ctrl+C,半拉状态最容易留下坏卷。

# 后台启动全部服务,首次会拉镜像 docker compose up -d # 看容器状态,重点看有没有 Restarting 或 Exited docker compose ps # 跟踪后端日志,迁移进度和报错都在这 docker compose logs -f api

docker compose ps里如果某个容器反复重启,先别急着重启全部,直接看那个容器的日志,docker compose logs --tail=200 <服务名>,绝大多数原因就写在最后几十行。

api 日志里看到迁移执行完成、Gunicorn 正常监听之后,做一次入口连通性验证:

# 换成你实际配置的端口 curl -I http://127.0.0.1:8080/ # 探一下后端接口是否可达,返回 200 或 401 都算通 curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080/console/api/setup

返回 200 说明系统还没初始化管理员,浏览器打开对应地址就会跳到初始化页面,设置邮箱和密码即可。设完之后这个接口会变成 401 或 403,属于正常。到这一步,一套环境就算立住了。

4. 参数落到生产:数据库、反代与沙箱的调法

4.1 数据库与向量库:卷、连接与内存

先说卷。所有持久化数据都落在docker/volumes/下面,按服务分目录:数据库一个、文件存储一个、向量库一个、插件一个。这个设计的含义很直接——容器可以随便删,这个目录不能删。备份的本质就是备份这个目录加一份数据库逻辑导出,后面一章会展开。

再说连接。api 和 worker 是两个进程,各自维护自己的数据库连接池,默认池大小是按小规模场景设的。并发一上来,最先出问题的往往不是 CPU 而是连接数:现象是接口偶发超时、日志里出现连接获取等待。我一般会把池大小按(api 副本数 + worker 并发数) × 单进程连接数估一遍,再和 PostgreSQL 的max_connections对一下,别让应用侧的池加起来超过数据库上限。

# 看数据库实际连接数,逼近上限就该调了 docker compose exec db psql -U postgres -c \ "select count(*), state from pg_stat_activity group by state;"

向量库的选型是个绕不开的决策,给你一张对照表,按规模挑:

方案部署成本适用规模备注
weaviate低,默认自带中小知识库,单机开箱即用,内存占用中等
qdrant低中小知识库过滤查询友好,配置简单
pgvector最低,复用现有库小规模、不想多一个组件和业务库同生共死,扩容受限
milvus高,依赖多大规模、需要独立扩缩容组件多,小机器别碰

换向量库不是改一个变量就完事:compose 里对应服务要启用,连接地址和凭据要填对,而且切换之后旧向量不会自动迁移,已有知识库得重新索引。这一点在动手前必须算进时间成本。

4.2 Nginx 反代与上传:413 和超时的源头

上传大小限制是最容易踩的一处,因为它在三个地方各有一份,改漏一个就白改。

第一处是反向代理层。请求体超过它的限制,会直接被挡回 413,压根到不了后端。第二处是后端的上传限制变量,样板里通常有几个:单文件大小、批量文件数、图片大小。第三处是前端自己的校验提示。三处的数值要从大到小或者相等,让代理层放行、后端做最终判定,否则要么用户看到一个没头没尾的 413,要么后端明明允许却被代理拦了。

# docker/nginx/conf.d/ 下对应站点配置里的关键几行 client_max_body_size 100m; # 要和后端上传上限对齐或略大 proxy_read_timeout 3600s; # 长任务、流式输出场景必须放大 proxy_send_timeout 3600s; proxy_buffering off; # 流式响应不要缓冲,否则前端一卡一卡的

proxy_buffering off这条尤其值得说。知识库问答和 Agent 走的是流式返回,开着缓冲会出现“等半天,然后一大段字突然全出来”的观感,很多人以为是模型慢,其实是代理在攒数据。

另一个常被忘的是超时。文档解析、批量索引这类操作耗时长,如果反向代理读超时只有默认的几十秒,前端会频繁看到网关超时,但后端任务其实还在跑,用户重试一次就重复索引一遍,白白烧算力。

4.3 沙箱与出站:代码执行和插件下载的边界

沙箱这块的设计意图是双重的:既隔离用户代码,也限制它能访问哪些地址,防止被拿来探测内网。沙箱的出站请求会走那个代理容器,代理的配置文件里是一份允许清单。如果你的应用需要调用内网自建的模型服务、或者访问某个内部 API,请求会被拦下来,现象是代码节点执行失败但日志里没有明显的异常堆栈。

处理方式是往代理配置里加放行规则,而不是图省事把代理关掉。关掉等于把内网暴露面直接摊开,这笔账不划算。同理,如果宿主环境本身不允许容器出网,那所有依赖外网的能力都得提前规划,别等上线才发现。

插件守护进程是另一个出网点。安装插件本质是去插件源拉包,网络不通就是安装一直转圈然后失败。离线环境的常见做法是:在有网机器上把插件包下下来,再导入到目标环境,而不是硬开网络。另外那个“内网 API 地址”变量,填的必须是容器网络内可达的地址,填成127.0.0.1是最典型的错——在容器里,127.0.0.1 指的是容器自己,不是宿主机。

5. 排查实录:五个从「起不来」到「跑不稳」的坑

5.1 启动阶段:端口、密钥、数据库版本

坑一:docker compose up直接报端口被占用,整套起不来。现象是 nginx 容器不断重启,日志里明确写着绑定 80 失败。原因是宿主机上已经有别的 Web 服务占着 80,而编排文件里端口映射是写死的默认值。解决办法是改.env里的对外暴露端口,然后docker compose up -d重建,别去动docker-compose.yaml里的映射段——动了以后升级时容易被覆盖掉,问题重现一次。改完用ss -lntp复核一眼。

坑二:中途改过SECRET_KEY,模型供应商全部报凭据无效。现象是之前配好的模型突然调不通,界面上提示鉴权失败,但去供应商后台看密钥是好的。原因是这个密钥参与凭据的对称加密,换了之后密文解不出来。这个问题没有后悔药,只能把每个供应商的 Key 重新填一遍。所以我现在的习惯是:SECRET_KEY生成之后就写进密码管理工具,部署脚本里直接从环境读取,绝不在.env里手敲第二次。

坑三:沿用旧数据卷,数据库容器起不来。现象是 db 容器启动几秒后退出,日志里提到数据目录版本不兼容。原因通常是换了镜像的大版本,而volumes/db/data还是旧版本写下的格式。解决方式是先备份卷,再决定是回退镜像版本,还是导出数据后重建卷再导入。千万不要在没备份的情况下删卷重来,那等于把应用配置和会话全部清空。这类问题的根子在于升级前没读变更说明,踩过一次就该记住:大版本升级先读说明,再动数据。

5.2 运行阶段:反向代理、出站网络、插件守护进程

坑四:挂在域名后面,文件上传成功但预览 404。现象很割裂——上传接口返回成功,点开文件却是空白或者 404。原因是几个“对外地址”变量还留空或者填的是内网地址,后端生成的文件链接浏览器根本访问不到。解决方式是把控制台、应用、文件这几类对外地址统一填成外部可访问的完整地址,重启 api 和 worker。填完之后注意,历史文件的链接是按当时的配置生成的,老数据可能需要重新上传。我一般会在部署清单里把这几项单独列一行,配完逐项打勾。

坑五:知识库文档一直“排队中”,或者插件安装转圈到失败。现象是上传了文档,状态卡在处理中不动;插件市场点安装也一直失败。前者去看 worker 日志,常见原因是 worker 没起来、或者连不上队列;后者多半是出站网络不通,插件包拉不下来。还有一种隐蔽情况:那个内网 API 地址填错,插件守护进程连不上后端,安装流程走一半就断。解决顺序是固定的——先docker compose ps确认 worker 和插件守护进程都在跑,再看各自日志的最后几十行,最后才怀疑网络策略。反过来先怀疑网络,往往白折腾半天。

顺带提一句排队中的另一个来源:worker 并发数设得太小,文档一多就排长队。这不是故障,是容量问题,调并发或者加机器,别在日志里找不存在的错误。

6. 升级与备份:把「后悔药」提前做好

升级这件事,我的做法是先做一次完整的备份演练,再谈升级。具体流程是这样:停掉写入(docker compose stop api worker),导出一份数据库逻辑备份,把关键卷打成一个包,然后才去下载新版本的包、比对配置、拉镜像、启动。

# 1. 停写入,避免备份到一半数据还在变 docker compose stop api worker # 2. 逻辑备份数据库,文件名带日期便于回滚定位 docker compose exec -T db pg_dump -U postgres \ "$DB_DATABASE" | gzip > /backup/dify-db-$(date +%F).sql.gz # 3. 打包文件存储和插件目录,这两个丢了最肉疼 tar -czf /backup/dify-files-$(date +%F).tar.gz \ volumes/app/storage volumes/plugin_daemon # 4. 恢复写入 docker compose start api worker

参数上只有两点要注意:-T是关掉伪终端分配,不加的话在脚本里重定向会报错;库名用变量引用,别写死成dify,不同版本默认库名可能不同,写死容易导错库。

升级时按这张表走,每一步都有明确验证点,出问题能立刻定位到是哪一步:

步骤动作验证点
1备份数据库与关键卷备份文件大小非零,能gunzip -t通过
2用新包替换docker/目录保留原.env,别整目录覆盖
3diff 新旧.env.example新增键全部补齐,废弃键确认可删
4拉新镜像并启动docker compose ps全部 Up
5观察 api 日志中的迁移输出无异常堆栈,迁移正常结束
6冒烟验证登录、跑一个已有应用、上传一份文档

第三步是最容易被跳过、也最容易出事的一步。我吃过一次亏:图快,直接把新包里的docker/整个覆盖上去,连带把.env也换成了样板,密码和密钥全变,数据库连不上,插件守护进程也起不来。那次之后我改了个习惯——升级前先把docker/目录整个复制一份到/tmp/dify-docker-$(date +%F),再往里覆盖,出问题三分钟就能切回去。这算不上什么高级技巧,但它救我至少两次。

还有个小细节值得单独记:升级完成后别急着宣布成功,先跑一遍“长链路”——上传一份几十页的文档,等它完成解析和索引,再对它提问一次。这条链路覆盖了 api、redis、worker、向量库、模型供应商五个环节,任何一环有版本兼容问题,都会在这里暴露出来。只测登录页和首页,等于什么都没测。

希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/24 7:40:20

日志与审计:记录什么才算可追溯

日志多不等于能查清 线上出了问题&#xff0c;翻日志看到满屏的请求开始、请求结束&#xff0c;中间夹杂着异常堆栈。想知道这次调用为什么读了那个文件、是谁授权的、前后重试了几次&#xff0c;却发现这些信息散在三个地方&#xff0c;还缺了关键的一环。 可追溯不是把更多文…

作者头像 李华
网站建设 2026/10/24 7:38:33

XL3126-R芯片支持LVDS转MIPI带旋转功能最高分辨率1920X1200 60hz

XL3126‑R 是一颗功能为 LVDS 转 MIPI DSI 显示桥接芯片&#xff0c;用于把单 / 双路 LVDS 输入信号转换成 MIPI DSI 输出&#xff0c;让带 LVDS 接口的主板可以驱动 MIPI DSI 屏幕&#xff0c;面向工业、医疗、车载、嵌入式场景。1、芯片概述&#xff08;Overview&#xff09;…

作者头像 李华
网站建设 2026/10/24 7:31:58

Docker Compose插值功能解析与应用实践

1. Docker Compose插值功能深度解析在容器编排领域&#xff0c;Docker Compose作为多容器应用管理的标准工具&#xff0c;其配置文件中的插值&#xff08;Interpolation&#xff09;功能往往被大多数开发者低估。这个看似简单的特性实际上隐藏着强大的环境适应能力&#xff0c;…

作者头像 李华
网站建设 2026/10/24 7:29:05

双 11 赛博朋克霓虹流光背景:基于 Signed Distance Fields 符号距离场的 GPU 动态排版光晕

在双 11 狂欢夜与主会场视觉搭建中&#xff0c;视觉设计师往往追求强烈的赛博朋克霓虹氛围&#xff1a;极具未来感的几何晶格、沿着版面边缘川流不息的能量光导流光、以及与品牌主标题深度融合的弥散辉光。在以往的工程实践中&#xff0c;前端团队大多依赖 UI 团队切出的大尺寸…

作者头像 李华
网站建设 2026/10/24 7:28:10

从克隆到第一次录制:LiveAutoRecord 直播自动录制实用笔记

从克隆到第一次录制&#xff1a;LiveAutoRecord 直播自动录制实用笔记 【免费下载链接】LiveAutoRecord 基于 Electron 的多平台直播自动录制软件 项目地址: https://gitcode.com/GitHub_Trending/li/LiveAutoRecord 周六决赛开打前&#xff0c;你不想熬夜盯着整场直播&…

作者头像 李华