Dify离线部署全攻略:从Docker镜像到插件离线导入的实战指南

发布时间:2026/9/16 23:18:19
Dify离线部署全攻略:从Docker镜像到插件离线导入的实战指南
为什么给人装了三个月Dify最后我还是老老实实写了这份离线部署笔记大概三个月前有朋友问我能不能帮他把 Dify 部署到一台内网服务器上。当时我第一反应是直接 docker compose up -d 不就行了结果真到了现场才发现那台机器在隔离网络里别说访问 Docker Hub连 pip 源都连不上。折腾了一下午最终方案是跑到能联网的机器上把所有东西准备好再一包一包搬进去。那次之后我陆续又帮几个项目做了同样的离线部署。Dify 本身升级快、插件生态也越来越丰富但一件事反复做就会踩到各种边角问题。这篇文章算是我把这几个月踩过的坑、试过的方法、整理出来的流程一次性写清楚。如果你也面临“Dify 必须上内网、插件还得能装”这种需求按这份流程走能省下大半天的摸索时间。先说结论Dify 插件离线部署的核心工作其实分两块——Dify 应用本体和镜像的离线安装以及插件市场/插件包的离线导入。只搞定前者不搞定后者Dify 虽然起来了但进了插件市场点安装照样转圈圈失败。所以这篇文章会把两条线一起讲从下载准备到安装验证完整过一遍。适合看这篇文章的人有两类一类是公司内网、政务云、涉密环境里必须离线部署 Dify 的运维或开发另一类就是个人折腾网络不稳定或者想完全掌控插件版本不想被在线市场变来变去影响。两种场景思路一样只有细节上的取舍。1. 离线部署的适用场景与前置判断1.1 先弄清楚你是“完全隔离”还是“半隔离”做离线部署前第一件事不是下载东西而是搞清楚目标网络到底是什么状态。我碰到过三种情况完全隔离目标服务器上不了外网DNS 解析外网域名都是失败的Docker daemon 拉镜像直接 timeout。半隔离能访问部分白名单域名比如能上 Docker Hub 但访问不了 GitHub或者反过来。受限网络能通外网但带宽极低、稳定性差在线拉镜像基本靠运气。这三种情况对应完全不同的离线策略。第一种必须把所有东西打包搬过去这也是本文最核心的适用场景。第二种可以考虑部分内容在线拉取减少人工搬运工作量。第三种其实用不着严格离线但可以通过配置镜像加速器、设置 Docker 代理等方式改善体验。在动手之前有个判断技巧值得分享先看目标机上 Docker 能不能拉镜像再决定要不要走离线方案。不要凭着“应该是内网环境”就默认走全程离线那会平白增加很多工作量。可以先执行一下 docker pull hello-world 试试能通就直接在线部署不能通再启动离线流程。1.2 离线部署需要准备的核心物料清单离线部署听起来像“把 Docker 镜像导出来带走就行”但实际做起来涉及的物料比想象中多。我通常会在开始前先列一份清单避免到了现场缺东少西物料说明获取方式Dify 源码或安装包包含 docker-compose.yaml、环境变量模板等从 GitHub 官方仓库下载对应 release 版本Docker 镜像Dify 本体所有服务镜像 插件运行时依赖镜像联网机器上 docker pull 后 docker save 导出插件包需要安装的插件 .difypkg 文件或插件市场缓存插件 GitHub 仓库 release 或市场渠道手动下载内网镜像仓库可选用 Registry/Harbor 接收镜像供多台机器拉取在联网机器上拉取 registry:2 镜像后离线导入传输介质U 盘、移动硬盘或内网共享目录现场情况灵活选择很多教程只讲“镜像导出导入”就完事了忽略了插件包的准备。结果就是把 Dify 本体跑起来了点开插件市场什么也装不了又得回来研究插件怎么离线装。所以我建议从一开始就把插件包的获取纳入整体计划后面操作起来会流畅很多。2. 下载阶段在联网机器上把“搬家”物料备齐2.1 确定 Dify 版本并拉取源码Dify 的部署方式比较固定官方推荐的是 Docker Compose 方式。你要做的第一步就是确定目标版本。版本选择上我的经验是不要一味追新尤其在生产环境。Dify 社区迭代很快某一个大版本更新后工作流配置、插件 API 可能在细节上有调整如果你的业务流程已经稳定跑在某个版本上离线环境里没有特殊必要就别升了。确定版本后到 GitHub 仓库找到对应 tag 的源码包下载。也可以直接下载 zip 压缩包不需要 git clone 完整历史离线部署只需要 docker 目录下的内容就够了。下载完成后解压在源码目录里找到 .env.example 文件。按官方文档说明需要把它复制成 .env 并修改关键配置比如密钥、端口、数据库密码等。这个文件影响的是 Dify 本体服务启动时的环境变量对内网部署特别重要的是** postgres 密码、redis 密码和密钥 SECRET_KEY**这些必须自定且保持一致。2.2 镜像拉取与导出docker save 的正确姿势Dify 本体涉及十几个容器包括 api、worker、web、postgres、redis、nginx、weaviate 或 opensearch 等。在联网机器上先进入源码目录执行 docker compose config 看看配置文件里引用了哪些镜像然后逐个拉取。我的习惯是写一个简单的循环脚本统一拉取和保存避免手工敲十几条命令。大致逻辑如下for img in $(docker compose config | grep image: | awk {print $2} | sort -u) do docker pull $img docker save $img -o $(echo $img | tr / _ | tr : _).tar done这里有个常见坑直接用 docker compose config 出来的镜像列表里可能包含${IMAGE_TAG}这类变量。执行前一定先确认 .env 文件已经配置好否则变量没赋值导出的镜像名和实际需要的镜像名对不上。导出后的 tar 文件可以按镜像用途分类放好。比如把 Dify 基础服务镜像放一个目录把插件运行时镜像放另一个目录方便后续现场安装时按顺序导入。文件大也无所谓移动硬盘 64G 起步完全够用了。2.3 插件包下载不要只下载一个文件Dify 的插件系统在在线环境是通过插件市场直接安装插件市场实际指向的是 GitHub 上的插件仓库。离线环境的难点在于你得在能联网的机器上先拿到插件安装包。插件包的格式是 .difypkg 后缀本质上是一个 zip 形式的打包文件里面包含了插件的 manifest、代码或二进制以及依赖声明。你可以在插件仓库的 release 页面找到对应版本直接下载。在下载时要注意三件事插件版本必须与 Dify 版本兼容。有些插件在 manifest 里声明了最低 Dify 版本要求低于该版本直接装不上。注意插件的依赖项。有的插件依赖其他插件比如一些工具类插件会声明依赖特定的 helper 插件。如果只下载了目标插件没下载依赖装的时候会提示缺依赖这时候还得回头补下。尽量下载“打包好”的 release 产物而不是源码包。源码包在离线环境里还需要自己编译纯给自己找麻烦。如果插件市场里某一个插件你非常需要但在 release 页找不到直接的 .difypkg 文件那你也可以在一个在线部署的 Dify 环境里装好插件后从插件管理页面找到该插件的详情导出本地文件使用。这个方法我试过导出的文件同样可以离线导入其他 Dify 实例。2.4 准备内网镜像仓库可选但推荐如果目标环境只是单台服务器那 docker save 后到现场 docker load 就够了。但如果现场有多台服务器要部署同一个 Dify或者后续还要加节点我建议搭一个内网 Registry。方法也很简单在联网机器上拉取 registry:2 镜像docker save 导出到内网一台服务器上 load 后启动容器把仓库端口默认 5000暴露在内网里。然后把之前 docker save 出的一堆 tar 文件用 docker load 导入到这台内网服务器重新打 tag 后 push 到内网 registry其他机器配置 insecure-registries 后就能正常 pull 了。这样做的好处是后续单台机器回滚、重新部署都方便不用每次拿个移动硬盘到处跑。当然如果只是单机环境这一步完全可以跳过去。我个人的经验是只要数量超过两台就值得搭。没有这一层你后续给每台机器手动导镜像很容易出现版本不一致的低级错误。3. 安装阶段离线服务器的导入与启动流程3.1 工作现场的第一步先导入基础镜像到了内网现场先把 U 盘或移动硬盘里的镜像 tar 文件拷贝到服务器上。导入用 docker load 命令可以单文件导入也可以写个循环批量导入for f in *.tar do docker load -i $f done导入完成后验证一下镜像是否齐全docker images 看看列表。这里有个小技巧在联网机器上导出镜像前可以先在一台测试机上跑一遍 docker compose pull确认所有镜像都能正常拉取。到了内网现场再对照镜像列表逐项检查缺哪个立刻知道。镜像导入的顺序没有严格要求但建议先把基础镜像postgres、redis、nginx 这些导入再导入 Dify 应用镜像。实际操作中其实顺序无所谓反正 loade 完都在本地了但分目录放好对照检查时有条理不容易漏。3.2 配置 .env 环境变量源码包解压出来后进入 docker 目录执行cp .env.example .env然后编辑 .env至少要确认或修改这些值SECRET_KEY不要用默认值用 openssl rand -hex 32 生成一段随机字符串。POSTGRES_PASSWORD和POSTGRES_DB根据实际需要修改。REDIS_PASSWORD如果你在内网环境不想暴露在公网设一个强密码即可。NGINX_PORT和EXPOSE_NGINX_PORT确认端口是否被占用。CONSOLE_API_URL和APP_API_URL内网环境的访问域名或 IP要注意这里不只影响浏览器访问还影响 Dify 内部服务之间回调时的地址拼接。设错了会导致登录回调异常、工作流 webhook 通知无法访问之类的问题。.env文件是 Dify 部署中非常容易出问题的一个环节。我见过有人把SECRET_KEY留空导致整个服务起不来也见过有人把APP_API_URL填成localhost导致局域网内其他机器能打开页面但无法调 API。建议配置完毕后再整段检查一遍尤其注意 URL 结尾不要带斜杠。3.3 启动 Dify 本体服务环境变量配好后直接在 docker 目录下执行docker compose up -d如果镜像已经全部导入这一步应该很快就完成。启动后别急着用先看容器状态docker compose ps正常情况下所有服务都应该是 Up 状态。如果有服务反复重启或者 Exited优先看日志常见的几个原因数据库容器没起来api 和 worker 启动时连不上数据库。环境变量里 SECRET_KEY 为空或格式不对。端口冲突nginx 容器起不来。排错的时候我习惯按顺序检查先看 postgres、redis 是否健康再检查 api、worker 是否能正常启动。依赖链底层的服务不健康上层的报错基本都是误导信息。这一步的经验是不要同时处理两件事先从最底层依赖查起大部分瞬间就能定位问题。3.4 等待数据库迁移完成再登录界面Dify 启动后api 容器首次启动会执行数据库迁移这个过程需要一点时间。别看到页面能打开就立刻开展配置工作先等几分钟确认 api 服务日志里没有任何报错了再进页面操作。我第一次离线部署时就是没注意这个细节页面打开后直接去创建管理员账号结果提示数据库异常。回去看日志发现迁移还没执行完。后来我的做法是docker compose up -d 之后主动盯两分钟 api 容器日志看到迁移完成或者进入等待服务状态的标志后再开浏览器。docker compose logs -f api看到日志里没有 ERROR 级别的报错再通过页面访问。这一步稍微耐心点后面能省掉很多莫名其妙的坑。4. 插件离线导入真正让 Dify 好用的最后一块拼图4.1 Dify 插件的安装入口与路径Dify 的插件管理入口在控制台界面里顶栏有一个类似拼图图标的入口。进入插件市场后在线环境可以直接搜索安装但离线环境这里基本就是空的。离线环境下安装插件走的是“通过本地文件安装”的通道。在插件市场的页面上有一个“安装插件”的按钮点击后可以选择上传本地 .difypkg 文件也可以从 URL 安装离线环境 URL 基本不可用。上传完成后系统会解析插件文件里的 manifest并在界面上展示插件的名称、作者、版本、依赖信息。这里需要注意的是插件安装后不一定立刻生效。有些插件会作为 Agent 策略或工具注册到 Dify 的系统里需要你在对应 Agent 应用里配置才会启用有些插件是模型供应商需要在设置里填 API 密钥才能发挥功能。不要在插件管理里看到“已安装”就以为万事大吉要看插件的具体类型做进一步配置。4.2 插件依赖的处理顺序刚才说过离线下载插件时要注意依赖。实际导入时同样要注意顺序。比较好的做法是先安装插件包中作为基础库的插件比如依赖类、工具类的 helper 插件。再安装具体业务插件比如某个模型平台的对接插件。最后在应用中验证插件是否注册成功。Dify 的插件机制会做依赖检查如果先装业务插件而缺依赖界面会直接提示缺少 xxx 插件。这时候你有两个选择去联网机器下载对应 .difypkg 拿回来装上或者如果你之前的插件包目录里已经下载了依赖文件直接选择本地文件安装即可。我建议在联网机器上下载插件时就把每个插件仓库的依赖关系捋清楚同一个业务插件的所有前置依赖放在同一个目录到现场安装时按依赖顺序批量导入一次成功。省得到现场来回跑。4.3 离线插件与市场版本漂移问题离线部署最大的隐患是插件版本漂移。说白了就是你在联网机器上下载插件时市场插件可能是最新版但你内网 Dify 版本可能是几周前甚至几个月前的插件的新版插件也许已经调用了新版 Dify 才有的 API。所以在选择插件版本时我的经验是尽量选择与 Dify 内核版本同期发布的插件版本。如果你用的是 Dify 1.17.1那么优先选择这个版本前后一周内发布的插件版本。如果某插件新版发布了但声明要求 Dify 版本更高就向下找一个兼容版本。绝大多数插件仓库的 release 页面会标注兼容的 Dify 版本下载之前多看一眼避免装完就报错。另外提醒一点Dify 从某个版本之后插件与内核的版本耦合越来越明显。升级 Dify 主版本时旧插件往往需要同步更新否则插件的行为可能异常。离线环境里升级 Dify 的系统性工作比在线环境要大所以版本规划尤其重要。如果你预见到后续有升级需求从第一次部署就开始记录版本信息每次部署的 Dify 版本、插件版本、镜像版本都记下来后面维护心态会稳很多。4.4 插件安装后的验证方式插件导入成功后验证工作不能省。我通常会做三件事检查插件详情页是否正常展示插件元数据、版本、作者、描述信息页面有没有报错。尝试新建一个 Agent 应用看该插件对应的工具或模型是否出现在可选列表中。实际发起一次调用不一定要走完整业务逻辑但至少要确认插件的鉴权、模型连通性没有大问题。不要嫌麻烦。我之前有一次装完某个插件后页面显示已安装但实际创建应用时那个工具怎么都不出现排查半天发现是插件内部初始化时抛异常了而插件管理页面没有明显报错。所以第三步的“实际调用”是唯一能确认插件真正可用的验证方式。三步都过了这个插件才算真正部署完成。5. 高频报错与排查思路离线环境特有的坑5.1 镜像导入成功但 docker compose 仍提示拉取镜像这个坑我踩得最痛。docker load 完镜像后docker images 里明明能看到但 docker compose up -d 还是提示拉取镜像。原因通常是镜像 tag 与 compose 文件里的 image 引用不一致。比如离线机器上镜像通过 docker load 导入后TAG 是 master 或 1.17.1但 docker-compose.yaml 里写的是 latest两个名称对不上Docker 就会尝试从远程仓库拉取。解决方法是导入后手动打 tag或者在导出镜像前在联网机器上就按 compose 文件里的 image 名称完整 pull 并 save。docker tag difyapi:latest local/difyapi:1.17.1 docker compose up -d更稳妥一点在联网机器上导出前就把环境变量和镜像名统一好。使用 docker compose config 检查最终的 image 名称然后按这个名称拉取和保存到了现场基本就不会出现匹配问题。5.2 数据库容器起不来或数据卷权限报错内网服务器可能用的是 CentOS 或某些特殊发行版SELinux 开启状态下的容器数据卷权限问题是老熟人了。postgres 容器起不来docker logs 里一堆 permission denied 的报错十有八九是数据目录权限不对。最简单的处理方法是给数据目录宽松权限或者直接关闭 SELinux如果安全策略允许。生产环境不建议直接关 SELinux但很多内网机器的策略本来就相对严格运维自己也未必说得清规则。我的建议是chmod -R 777 ./volumes这是最省事的方案适合测试环境。生产环境请根据实际目录配置权限保证 postgres 用户可写。还有一种情况是服务器重启后 docker 服务没起来导致容器全部 Exited你只要确认 docker 服务状态即可不一定和 SELinux 有关系。5.3 插件界面上传卡住或提示校验失败离线环境下浏览器和 Dify 后端都在内网上传 .difypkg 文件理论上很快。如果你遇到上传卡住或者提示校验失败先排除两个可能上传的文件不是规范的 .difypkg 压缩包可能是浏览器直接下载了 zip 但没有正确命名。Dify 后端的插件目录没有写权限导致文件写入失败。第一种情况比较常见很多 release 产物下载下来文件名可能是 source code.zip你需要自己重命名为 .difypkg或者最好从 release assets 里找那些明确带 .difypkg 后缀的文件。第二种情况检查一下 Dify 容器内插件目录的挂载权限即可通常调整宿主目录权限就能解决。5.4 插件装了但不起作用日志才是真正的裁判插件装在 Dify 里之后它的运行日志并不只存在于插件管理页面里。很多时候插件是个单独的容器或服务日志要去对应容器的 stdout 或日志文件里找。排查这类问题的思路是先复现一次插件调用比如在 Agent 里发一条触发该插件工具的消息。立即查看 Dify api 容器日志看有没有插件调用链路的报错。再查看插件对应容器的日志看有没有内部异常。把报错信息放到搜索引擎里搜Dify 社区和 GitHub Issues 里能解决大部分问题。我遇到过最离谱的一种情况是插件本身正常但没有配置上游模型导致的报错。比如某插件需要调用 GPT-4 做中间处理但离线环境根本没有 OpenAI 的 key插件就反复报鉴权失败。这不是插件部署的问题是运行条件的问题。排查时需要把环境因素一并考虑不要局限在“离线部署”四个字里。6. 离线环境下的后续更新与维护建议6.1 版本台账是离线部署的救命稻草离线环境的特殊性在于拿到一个新版本或新插件前你无法实时看到它对当前环境的影响。所以记录版本台账这件事比在线环境重要得多。我在维护 Dify 离线项目时专门建了一个文档记录了每一台服务器的以下信息Dify 部署版本、部署时间所有镜像名称与 tag插件包清单包含插件名、版本、来源仓库、依赖关系.env 文件的关键配置项历次变更记录与问题处理备注这个台账平时看着不起眼一旦要升级、回滚或者复制一份新环境价值就完全体现出来了。很多线上问题排查半天找不到原因最后发现是一台服务器的插件版本比另一台旧了几周。台账能让你一眼看清差异。6.2 离线升级的推荐路径离线升级 Dify 时不要心一热就在生产机上直接动。我推荐的路径是在联网机器上拉取新版本镜像导出。下载新版本源码包和对应插件包。先在一台测试机上还原当前生产环境的版本组合。在测试机上执行升级流程记录过程。确认无问题后再到生产机执行同样的操作。这个流程看起来多了一步测试机工作但实际能规避掉至少一半的升级风险。离线环境里一旦升级失败没有“在线回滚到上一版本”的便利只能靠本地备份和自己梳理的版本组合。所以“先在测试机验证”几乎是必须的省不得。关于备份升级前至少备份两个东西数据库数据卷和 .env 文件。Dify 的数据库里存了应用配置、知识库索引等信息丢了很难重建。用 docker compose 自带的数据卷机制直接把 volumes 目录拷走一份就行。我在升级前通常会把 volumes 目录给它 tar 出来避免升级到一半想回退却没路可退。6.3 插件新版本获取的替代思路离线环境里想更新插件除了定期从联网机器上手动下载外还有一个思路值得推荐在联网环境中维护一个“Dify 插件缓存仓”。做法很简单就是在能联网的 Dify 实例或 CI 机器上把常用插件的 release 产物定时下载到一个目录然后通过安全方式同步到内网环境内网维护人员从本地目录选择版本安装。这个思路本质上就是给自己的离线环境建一个私有插件市场。配合内网镜像仓库Dify 主程序和插件可以形成一个完整的离线分发体系。虽然前期搭建需要花一点时间但长期维护多台服务器时省下的精力非常客观。7. 从离线部署到常态维护我的几点体会离线部署这件事做一次两次会觉得繁琐但做多了会发现它的核心逻辑其实很简单把网上能拿到的所有东西在联网机器上有条理地准备好再到内网环境里有条理地导入。真正让人头疼的不是某个命令不会敲而是版本组合、依赖关系、环境变量这些细节没有理清。我个人的体会是在离线环境里慢就是快。第一次部署时为了追求“快点把页面跑起来”结果插件装不上、回调地址配错、容器反复重启来回折腾的时间远超按部就班操作的时间。反而是后来每次部署都严格按清单走先梳理版本兼容关系再准备物料再到现场稳扎稳打整个流程顺畅得多。如果你只是单机验证那按照这篇文章的流程走一遍基本够了。如果你要维护一批机器我真心建议从一开始就把镜像仓库、插件缓存、版本台账这三件事做起来。初期多花一两天后面省下的时间是按周计算的。最后分享一个非常实用的小技巧把整个部署流程写成 shell 脚本或 Ansible playbook。不管你是把镜像 tar 批量 load 进 docker还是按依赖顺序批量安装插件脚本都能把重复性高、容易出错的操作固化下来。我自己的离线部署包里就放着一个 load_images.sh 和一个 check_dify.sh前者负责批量导入、后者负责巡检容器状态和镜像 tag 是否匹配到了现场两条命令就能搞定大部分事情。Dify 的插件生态还在快速发展离线部署的需求也会越来越多。希望这篇基于实际踩坑经验写出来的攻略能让你少走点弯路。