Dify 国内镜像拉取失败?dify-main 私有化部署与离线包实战
发布时间:2026/9/29 14:13:27 锦皓数字建站

简介这份资源是面向国内开发者的 dify-main Docker 镜像包主要解决在国内网络环境下拉取与部署 Dify 项目时遇到的访问慢、不稳定等问题。适合需要快速搭建 Dify 运行环境、进行本地测试或私有化部署的技术人员无需再为镜像源配置反复折腾。压缩包共包含 2000 个文件以 1411 个 py 源码文件、370 个 json 配置、103 个 css 样式、25 个 js 脚本及 23 个 yaml 编排文件为主另有少量 md 文档、sh 脚本与 html 页面整体约 20.29MB目录结构完整覆盖前后端与部署配置。目前已有 1480 人学习下载。借助该镜像包读者可直接获得一套可运行的 Dify 环境省去逐层构建依赖的繁琐过程同时便于对照源码理解项目模块划分与配置方式为二次开发或排错提供参考。1. 国内可以的镜像版本 dify-main从拉取失败到本地跑通的那条路如果你在国内做过 Dify 的私有化部署大概率经历过这个场景docker compose up -d敲下去终端卡在Pulling dify-api ...一动不动等十分钟后报一个context deadline exceeded或者TLS handshake timeout。这不是你网络的问题是默认镜像源在境内基本不可用。标题里的「dify-main 镜像版本」说的就是怎么把 Dify 主仓库这套服务在国内环境下完整拉起来——包括镜像加速、版本锁定、离线包制作这几件事。它解决的不是「Dify 是什么」这种问题而是「我已经决定用 Dify但拉不下来镜像」这个具体卡点。适合两类人一是在内网或受限网络里做私有化部署的运维二是想在自己机器上跑一套完整 Dify 做二次开发的后端。下面按我实际踩过的顺序把镜像源配置、版本选择、离线打包、排错这几步拆开讲。2. 镜像拉不动的根因与三种可用方案2.1 为什么默认源在国内会失败Dify 的docker-compose.yaml里api、web、worker、sandbox这些服务默认引用的是 Docker Hub 上的langgenius/dify-api、langgenius/dify-web等镜像。Docker Hub 的 registry 端点在境内访问时TCP 握手阶段就可能超时即使连上manifest 拉取和 layer 下载也经常断流。表现就是docker pull卡住、docker compose报net/http: TLS handshake timeout或者拉到一半unexpected EOF。这里有个常见误解以为配了registry-mirrors就万事大吉。实际上 Docker 的 mirror 只对 Docker Hub 的官方镜像生效而且很多公共 mirror 对langgenius/*这种非官方命名空间的镜像支持并不稳定。所以真正可靠的做法不是只加一个 mirror而是组合使用镜像加速 显式指定可用的镜像仓库 必要时做离线包。2.2 方案一配置 daemon.json 镜像加速这是成本最低的一步。编辑/etc/docker/daemon.jsonLinux或 Docker Desktop 的设置Windows/macOS加入registry-mirrors。注意不同云厂商的加速地址不一样我这里只写结构具体地址用你自己账号在对应云控制台拿到的。{ registry-mirrors: [ https://你的加速地址1, https://你的加速地址2 ], max-concurrent-downloads: 10, max-download-attempts: 5 }改完执行sudo systemctl restart dockerLinux或重启 Docker Desktop。max-concurrent-downloads调大能缓解大镜像分层下载慢的问题max-download-attempts让断流后自动重试而不是直接失败。逻辑说明registry-mirrors是 Docker 在拉取 Docker Hub 镜像时的优先代理Docker 会按顺序尝试。参数上max-concurrent-downloads默认是 3国内拉多分层镜像时调到 10 左右能明显提速但别调太大否则容易触发对端限流。提示改完 daemon.json 后一定要docker info确认Registry Mirrors列表已经生效很多人改完没重启 Docker 就以为配好了。2.3 方案二显式替换 compose 里的镜像地址如果 mirror 对langgenius/*不生效就直接在 compose 文件里把镜像地址换成可用的仓库前缀。Dify 的 compose 文件里镜像名是写死的你可以用sed批量替换或者用docker-compose.override.yaml覆盖。# 备份原文件 cp docker-compose.yaml docker-compose.yaml.bak # 把 langgenius/ 前缀替换成你的可用仓库前缀 sed -i s|langgenius/|registry.example.com/langgenius/|g docker-compose.yaml # 确认替换结果 grep -n image: docker-compose.yaml逻辑说明sed的s|...|...|g用竖线做分隔符避免路径里的斜杠转义。替换后grep检查每一行image:是否都指向了新前缀。参数上如果你的私有仓库需要认证先docker login registry.example.com否则拉取会报unauthorized。这里要注意Dify 的 compose 文件里除了langgenius/*还有postgres、redis、nginx、weaviate等第三方镜像。这些镜像在 Docker Hub 上mirror 通常能覆盖但如果你的环境完全隔离这些也要一并替换。2.4 方案三离线包制作与导入内网环境最稳的做法是离线包。在一台能正常拉镜像的机器上把 Dify 所有镜像pull下来save成 tar拷进内网后load。# 在能联网的机器上先拉取所有镜像 docker compose pull # 导出所有镜像到一个 tar 包 docker save -o dify-images.tar \ langgenius/dify-api:latest \ langgenius/dify-web:latest \ langgenius/dify-sandbox:latest \ postgres:15-alpine \ redis:6-alpine \ nginx:latest # 在内网机器上导入 docker load -i dify-images.tar # 确认镜像已导入 docker images | grep -E dify|postgres|redis|nginx逻辑说明docker save支持一次导出多个镜像导出的 tar 包含所有分层体积可能到几个 GB。docker load导入后镜像名和 tag 保持不变compose 文件不用改。参数上-o指定输出文件多个镜像名用空格分隔。如果镜像特别大可以分服务导出避免单个 tar 过大导致拷贝失败。注意docker save导出的 tar 不包含镜像的latest之外的其他 tag如果你 compose 里锁定了具体版本号导出时也要用同样的版本号否则 load 进来后 compose 找不到对应 tag。3. dify-main 版本选择与 compose 文件锁定3.1 main 分支镜像和 release 镜像的区别Dify 的镜像 tag 有几类latest、main、具体版本号如0.6.9。latest和main通常指向最新的构建变动频繁适合尝鲜但不适合生产。生产环境我一般锁定具体版本号比如langgenius/dify-api:0.6.9。这样做的原因是Dify 的数据库迁移脚本和 API 版本是绑定的你这次用main跑起来下次pull到新的main可能数据库 schema 就对不上了启动时报alembic迁移错误。标题里的「dify-main 镜像版本」我的理解是两层一是你要能拉到main这个 tag 的镜像二是你要清楚main和 release 的区别别在生产上用main。下面这张表是我整理的选择依据。tag 类型适用场景风险latest快速体验版本漂移随时可能变main跟进最新功能不稳定可能有未测试的迁移具体版本号生产部署需要手动跟进升级版本号日期需要精确复现需要确认仓库里有这个 tag3.2 用 .env 锁定版本号Dify 的 compose 文件支持通过环境变量指定镜像 tag。在.env文件里设置DIFY_API_IMAGE、DIFY_WEB_IMAGE等变量compose 文件里用${DIFY_API_IMAGE}引用。这样你改版本只需要改.env不用动 compose 文件。# .env 文件片段 DIFY_API_IMAGEregistry.example.com/langgenius/dify-api:0.6.9 DIFY_WEB_IMAGEregistry.example.com/langgenius/dify-web:0.6.9 DIFY_SANDBOX_IMAGEregistry.example.com/langgenius/dify-sandbox:0.2.10逻辑说明把镜像地址和 tag 抽到.env里compose 文件里写image: ${DIFY_API_IMAGE}。这样切换环境测试/生产或者切换仓库前缀时只改一个文件。参数上tag 一定要写全不要只写0.6因为 Docker 不会自动补全。3.3 验证镜像版本是否匹配拉完镜像后别急着up。先确认 API 镜像的版本和 web 镜像的版本是否一致以及数据库迁移文件是否匹配。# 查看 api 镜像的标签和构建信息 docker inspect registry.example.com/langgenius/dify-api:0.6.9 | grep -E RepoTags|Created # 启动数据库和 redis docker compose up -d db redis # 单独启动 api观察迁移日志 docker compose up api逻辑说明docker inspect看镜像的创建时间和 tag确认不是旧缓存。先起db和redis再起api是因为api启动时会执行数据库迁移如果数据库没就绪迁移会失败。观察api日志里有没有Running upgrade之类的 alembic 输出如果有报错说明版本不匹配。提示如果api启动时报Target database is not up to date说明镜像里的迁移脚本比数据库当前版本新需要先跑迁移或者回退镜像版本。4. 避坑镜像部署中最容易翻车的五个点4.1 拉取成功但启动报 exec format error现象docker compose up后api容器反复重启日志里报exec /app/docker/entrypoint.sh: exec format error。原因镜像架构和宿主机架构不匹配。比如你在 ARM 机器M 系列 Mac 或鲲鹏服务器上拉了 amd64 的镜像或者反过来。解决确认宿主机架构uname -m然后拉对应架构的镜像。Dify 官方镜像有 amd64 和 arm64 两个版本用docker pull --platform linux/amd64显式指定。如果仓库里没有对应架构就需要自己构建或者找多架构 manifest。4.2 镜像拉下来了但 compose 还是去 Docker Hub 拉现象你已经docker load了离线包docker images也能看到镜像但docker compose up还是卡在Pulling。原因compose 文件里的镜像名和你 load 进来的镜像名不一致。比如你 load 的是langgenius/dify-api:0.6.9但 compose 文件里写的是langgenius/dify-api:latesttag 对不上Docker 就会去远程拉。解决docker images看清楚 load 进来的完整镜像名和 tag然后改 compose 文件或.env里的 tag保持一致。或者用docker tag给现有镜像打一个 compose 需要的 tag。4.3 数据库迁移卡住导致 api 起不来现象api容器启动后一直停在Waiting for database...或者Running upgrade不动最后超时退出。原因数据库连接配置不对或者数据库版本和迁移脚本不兼容。Dify 的api启动时会等db服务就绪如果.env里的DB_HOST、DB_PORT、DB_PASSWORD和 compose 里db服务的配置不一致就会一直等。解决检查.env里的DB_*变量和 compose 文件里db服务的environment是否一致。另外确认db容器的健康检查是否通过docker compose ps看db的状态是不是healthy。4.4 镜像加速配了但只对部分镜像生效现象postgres、redis拉得很快但langgenius/dify-api还是超时。原因公共镜像加速器通常只缓存 Docker Hub 官方镜像library/*命名空间对langgenius/*这种第三方命名空间支持不好或者根本不缓存。解决对langgenius/*单独处理要么用方案二替换仓库前缀要么用方案三做离线包。不要指望一个 mirror 解决所有镜像。4.5 离线包导入后磁盘空间不足现象docker load到一半报no space left on device。原因docker save出来的 tar 包本身占空间docker load解压后镜像又占一份空间加上原有镜像磁盘很容易满。解决docker load前先df -h看/var/lib/docker所在分区剩余空间至少留出 tar 包体积的两倍。导入完成后可以删掉 tar 包释放空间。另外定期docker system prune清理无用镜像和缓存。5. 进阶用私有仓库做团队级镜像分发5.1 为什么团队场景要上私有仓库单人部署用离线包就够了但团队里多台机器、多个环境开发/测试/生产都要用同一套镜像时离线包拷贝的方式就低效了。这时候搭一个私有 registry把 Dify 镜像推上去其他机器直接从私有 registry 拉速度和稳定性都可控。私有 registry 的另一个好处是版本管理。你可以给镜像打上dev、staging、prod这样的 tag配合 CI 流水线每次构建自动推送部署时按 tag 拉取避免手动传 tar 包传错版本。5.2 搭建 registry 并推送镜像# 启动一个本地 registry测试用生产建议加认证和 TLS docker run -d -p 5000:5000 --name registry registry:2 # 给现有镜像打上私有仓库的 tag docker tag langgenius/dify-api:0.6.9 localhost:5000/dify-api:0.6.9 docker tag langgenius/dify-web:0.6.9 localhost:5000/dify-web:0.6.9 # 推送到私有 registry docker push localhost:5000/dify-api:0.6.9 docker push localhost:5000/dify-web:0.6.9 # 在其他机器上从私有 registry 拉取 docker pull registry-ip:5000/dify-api:0.6.9逻辑说明docker tag给镜像起一个带私有仓库地址的新名字docker push推上去。其他机器拉取时把 compose 文件里的镜像地址改成registry-ip:5000/dify-api:0.6.9。参数上localhost:5000换成你 registry 的实际 IP 或域名。生产环境一定要配 TLS 和认证否则任何人都能推拉镜像。注意Docker 默认要求 registry 使用 HTTPS如果内网用 HTTP需要在 daemon.json 里加insecure-registries但这只建议在完全隔离的内网用。5.3 用 registry 做版本回滚私有 registry 的另一个价值是回滚。当你发现新版本有问题想回到上一个版本只需要把 compose 里的 tag 改回旧版本号重新pull和up就行。前提是你推送镜像时保留了旧版本的 tag没有覆盖。我一般会在 CI 里保留最近 5 个版本的镜像超过的自动清理。这样既不会占太多存储又能在出问题时快速回滚。回滚时记得数据库迁移是不可逆的如果新版本已经跑了迁移回滚镜像后数据库 schema 可能不兼容需要提前备份数据库。5.4 一个我踩过的坑有次在客户内网部署私有 registry 搭好了镜像也推上去了但docker compose up时api一直报manifest unknown。排查了半天发现是 registry 的存储驱动配置有问题推上去的镜像 manifest 不完整。后来换成registry:2的默认配置重新推了一遍就好了。所以私有 registry 虽然简单但存储后端filesystem、S3、OSS的配置要确认清楚推完镜像后用docker manifest inspect验证一下 manifest 是否完整。希望帮到你。本文还有配套的精品资源点击获取
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。