如何用 Docker Compose 在 VPS 自托管 Dify
Dify 默认启动 15 个容器,最低需要 4 GiB 内存。首次启动前先在 .env 中修改默认密码,并在 /install 抢先创建管理员账户。
Dify 是什么,以及您准备运行什么
Dify 是一个可自行托管的平台,用于基于大语言模型构建应用。它提供 Web 界面,用于设计聊天应用、代理和检索管道;提供 API,供您从自己的代码中调用这些应用;还提供统一位置,用于管理提示词、数据集和模型密钥。小型团队通常会部署这类工具,让所有人基于同一个共享私有平台构建应用,而不是把 API 密钥分散在各个脚本中。如果您还不熟悉 agent、tool call 和 retrieval pipeline 等概念,建议先从头了解这些概念。这样,阅读 Dify 的构建器界面时,您看到的会是熟悉的控件,而不是一面没有标签的开关墙。
自行运行 Dify 意味着需要运行许多组件。截至 2026 年 10 月,Dify 文档中的默认堆栈会启动 15 个长期运行的容器,另有一个只运行一次的任务,用于设置文件权限后退出。其中 7 个是 Dify 自有服务:API 服务器、WebSocket 服务器、后台 worker、调度器、Web 前端、插件 daemon 和 agent 后端。另外 8 个是依赖项:Postgres 数据库、Redis 缓存、Weaviate 向量数据库、nginx 入口层、2 个代码沙箱和 2 个 SSRF 代理。Docker Compose 会将它们连接起来,但这确实是一套完整的服务栈。Dify 文档给出的最低要求是 4 GiB 内存和 2 个 CPU 核心。如果这台 VPS 还要运行其他服务,应根据实测数据进行规格规划,而不要只看宣传的最低要求,因为PhotoPrism 和 Immich 的实际内存下限都明显高于其公开的最低要求;如果照片服务器与 Dify 共用这台主机,最先出现资源不足的通常是 Dify 的数据库和向量存储。CPU 争用也会产生同样的问题:将 Jellyfin 媒体库改造成 90 年代录像店时,仅浏览封面几乎不消耗服务资源,但一旦有人开始转码,Dify 的 worker 就会排在转码任务之后。好在,无论您在 Dify 上构建多少个应用,其容器数量都保持不变。这种资源成本增长方式比OpenBot 更平缓;在 OpenBot 中,每个 AI 协作者都有自己的容器和浏览器,每增加一个协作者,内存下限就会再次上升。
Dify 会保存您的模型 API 密钥,而且通常还会保存您为检索功能加载的私有文档。因此,从部署的第一分钟起,就应将运行 Dify 的主机视为敏感系统。本指南会先安装 Dify,然后按照保护任何保存机密信息的服务的方式对其进行加固。
前置条件
您需要一台运行 Ubuntu 24.04 的 VPS,至少配备 4 GiB RAM 和 2 个 CPU 核心,并安装 Docker 及 Docker Compose 插件(Dify 要求 Compose 2.24.0 或更高版本)。此外,您需要拥有 sudo,或属于 docker 组。下面的克隆命令还会使用 git、curl 和 jq。如果您不熟悉 Docker,可参阅VPS 上的 Docker Compose 基础,其中介绍了本指南所需的安装步骤和核心命令。建议为服务器配置一个域名,因为您应在 Dify 前部署 TLS,而不是直接使用裸 IP 地址。
第 1 步:获取 Dify 及其 Compose 文件
Dify 将 Docker 配置保存在主仓库中。克隆最新发布版本,而不是开发分支,然后进入 docker 目录:
git clone --branch "$(curl -s https://api.github.com/repos/langgenius/dify/releases/latest | jq -r .tag_name)" https://github.com/langgenius/dify.git
cd dify/docker
cp .env.example .env如果克隆时出现 “Remote branch null” 错误,说明 GitHub API 未返回结果;请从 releases 页面选择一个版本,然后手动将其传递给 --branch。
.env 文件是核心配置文件。开始操作前先阅读该文件。首先需要关注设置密码和密钥的值:SECRET_KEY、Postgres 密码和 Redis 密码。SECRET_KEY 发布时为空;如果保留为空,Dify 会生成一个密钥,并将其保存在存储目录中。密码则不同:示例文件为 Postgres 和 Redis 设置了相同的 difyai123456,还为代码沙箱、插件 daemon 和 Weaviate 设置了固定且公开已知的密钥。保留这些默认值,是自托管 Dify 被入侵的最常见原因。如果您希望设置自己的密钥,请生成一个:
openssl rand -base64 42将其粘贴到 SECRET_KEY,并为文件中的每个密码和密钥字段设置强度高且唯一的值。Redis 密码也出现在 CELERY_BROKER_URL 中,因此请同时在那里修改,否则 worker 无法连接到 Redis。
步骤 2:启动
启动整个服务栈:
docker compose up -d首次运行会拉取多个镜像并初始化数据库,请等待约 1 分钟。检查容器是否运行正常:
docker compose ps每个长期运行的服务都应读取 running;一次性权限任务完成工作后会退出。默认情况下,Dify 通过随附的 nginx 容器在端口 80 上提供 Web 界面。首次访问 http://YOUR_SERVER/install 时创建管理员账户。请立即完成此操作,并确保在其他任何对象能够访问该端口之前完成,因为在该账户创建前,任何加载此页面的人都可以注册并控制您的实例。
步骤 3:不要直接暴露服务。在前面配置 TLS 和防火墙
大多数快速安装会在这里停止,而大多数安全事件也从这里开始。Dify 自带的 nginx 以明文方式监听端口 80,并监听所有网络接口,同时还会发布端口 443。您不应让管理员登录凭据和模型密钥通过明文 HTTP 传输,也不应让外部网络访问内部服务。
使用默认拒绝的防火墙锁定服务器,只允许 SSH 和 Web 流量:
sudo ufw default deny incoming
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable请注意,只覆盖 IPv4 的防火墙可能会让相同端口继续在 IPv6 上开放,这就是经常导致自托管服务暴露的 IPv6 防火墙缺口。请确认 IPv4 和 IPv6 两套协议栈都已过滤。还要注意,Docker 发布的端口由 Docker 自己的防火墙规则处理,而不是由 ufw 处理;默认配置会在所有网络接口上发布插件 daemon 的调试端口 5003。除非您确实需要从其他机器调试插件,否则请在 .env 中将 EXPOSE_PLUGIN_DEBUGGING_PORT 设置为 127.0.0.1:5003。
对于 TLS,最简洁的方案是将 Dify 的 Web 端口绑定到 loopback,然后在前面运行一个使用 Let's Encrypt 证书的反向代理,使公网中唯一可访问的服务是通过 HTTPS 通信的代理。Dify 的 .env 可用于修改对外暴露的端口;将其设置为绑定到 127.0.0.1,然后让代理指向该地址。EXPOSE_NGINX_SSL_PORT 也要进行相同设置,因为 Dify 的 nginx 默认会占用主机端口 443,而您的代理需要使用该端口。在 VPS 上安全运行 AI agent 中的加固思路同样适用于此处:让活动组件保持在 loopback 上,只暴露必须公开的服务,并让一个经过加固的入口统一处理 TLS。如果某个工具的界面只供您自己使用,完全不需要证书,则可以跳过代理,改用 SSH 隧道访问;自托管 open-kritt 安全扫描器就是这样将其仪表板绑定到 loopback,再转发到您的笔记本,而不是直接发布。若整个团队都需要使用 Dify,但不希望将其暴露到公网,则可以使用覆盖网络,将这一方案扩展到多台笔记本:将服务器的私有子网发布到您的 tailnet,即可让每台获准设备通过私有地址访问构建器,同时防火墙仍只允许 SSH。若您通过 coding agent 而不是手动方式管理此服务器,请在交给它密钥之前确定允许它在无人监督时执行哪些操作,因为 您为 Claude Code 保留的权限模式决定了它在重写 .env 或重启整个堆栈之前是否会停下来请求确认。如果您让一个会话持续查看容器日志,同时让另一个会话编辑代理配置,这两个会话可以在同一台服务器上相互传递文本,这样每次重启堆栈时就不必在终端之间反复复制输出。
第 4 步:及时安装补丁
Dify 更新频繁,更新内容包括安全修复。由于你检出的是发行版标签,因此更新时应检出下一个标签,而不是拉取分支。先备份数据库,然后在 docker 目录中执行:
docker compose down
git fetch --tags
git checkout NEW_VERSION
docker compose pull
docker compose up -d数据库迁移会在启动时自动运行,其中一些迁移无法回滚,因此必须先备份。每次升级前都要阅读发行说明,不要只阅读重大版本的说明:Dify 表示,不同发行版之间的升级步骤可能不同。例如,1.17.1 的说明(2026 年 9 月)要求使用捆绑的 Weaviate 且已有数据的用户,不要直接升级到该版本,而应依次经过每个次要版本。Dify 还会在不同发行版之间修改 .env 架构,因此检出新标签后,应将 .env.example 与你的 .env 进行比较,并迁移你的修改;因为未设置的新变量可能导致容器无法启动。
第 5 步:备份无法重新生成的数据
Dify 主机上有两类数据无法替代:保存应用、用户和设置的 Postgres 数据库,以及存储上传文档和向量索引的卷。两者都位于 docker 目录下的 Docker 卷中。按计划创建快照,并将快照复制到服务器之外。这些快照会在单个文件中包含所有模型密钥和上传文档,因此在传出主机前必须加密,原因与Vaultwarden 备份成为原本安全的密码服务器薄弱环节相同。模型 API 密钥可以重新签发,但花费一周构建的应用无法重新生成。任何需要在运行它的机器停止运行后仍保留状态的代理,都应遵循同样的原则:让 KiroCrew 作为始终运行的容器持续工作,归根结底就是创建内存和计划任务的快照,否则这些数据会在下一次重启时消失。
如果希望在此构建的代理访问自己的数据集之外的内容并搜索实时网络,将代理指向自托管的 SearXNG 实例可以让查询流保留在您控制的硬件上。不过,在启用之前,应先了解由此暴露的提示注入面。对于更自主、能够运行代码的代理,请参阅自托管 Agent Zero;在 VPS 上构建自己的 AI 代理则介绍了这些方案共同依赖的基础。
FAQ
自托管 Dify 的系统要求是什么?
Dify 文档规定,最低需要 4 GiB RAM 和 2 个 CPU 核心,以及 Docker Compose 2.24.0 或更高版本。这个最低配置对应默认堆栈的规模:截至 October 2026,共有 15 个长期运行的容器和 1 个仅运行一次的初始化任务。还应为上传的文档和向量索引预留足够的磁盘空间。如果同一台服务器还运行其他服务,则需要更多内存。
直接在端口 80 上暴露 Dify 是否安全?
不安全。Dify 附带的 Web 服务器监听纯 HTTP,并处理管理员登录和模型 API 密钥。应在前面部署带有 Let's Encrypt 证书的反向代理,将 Dify 自身的端口绑定到 loopback,仅让 HTTPS 代理面向互联网。还应配合默认拒绝规则的防火墙,并同时覆盖 IPv4 和 IPv6。
如何更新自托管的 Dify?
先备份数据库,然后在 docker 目录中运行 docker compose down、git fetch --tags、git checkout 新的 release tag、docker compose pull 和 docker compose up -d。先阅读 release notes,因为不同版本的升级步骤可能不同,迁移可能不可逆,而且 Dify 有时会新增 .env 变量。缺少该变量可能导致容器无法启动。
安装 Dify 后首先要做什么?
访问 /install,立即创建管理员账户。在该账户创建之前,任何能够访问此页面的人都可以占用该账户。应在容器运行正常后立即完成设置,并在向互联网开放防火墙之前完成。