如何用 Docker Compose 在 VPS 自托管 Dify
Dify Compose 默认运行六个容器,建议准备 4 GB RAM。启动前替换 .env 中的每个密钥,并先访问 /install 创建管理员账户,避免被他人抢先注册。
Dify 是什么,以及您将要运行的内容
Dify 是一个可自行托管的平台,用于构建基于大语言模型的应用。您可以使用 Web 界面设计聊天应用、智能体和检索管道,使用 API 从自己的代码中调用这些应用,并在一个位置管理提示词、数据集和模型密钥。小型团队通常会部署这类工具,让所有人基于同一个私有平台开发,而不是将 API 密钥分散在各个脚本中。如果您还不熟悉智能体、工具调用和检索管道等概念,可以先从头理解这些概念。这样,Dify 的构建器界面看起来会像一组熟悉的控件,而不是一面没有标签的开关墙。
自行运行 Dify 意味着要运行多个组件。Dify 以一组 Docker 容器的形式发布,包括 API 服务器、后台工作进程、Web 前端、Postgres 数据库、Redis 缓存和向量数据库。这些组件通过 Docker Compose 连接在一起。它不只是一个二进制文件,但 Compose 会处理组件连接。配备几 GB 可用 RAM 的 VPS 可以较为稳定地运行 Dify。如果该 VPS 还要运行其他服务,应根据实测数据规划规格,而不要只参考宣传的配置要求。因为PhotoPrism 和 Immich 的实际 RAM 下限远高于其公布的最低要求,共享同一台服务器的照片服务会首先耗尽 Dify 数据库和向量存储的资源。CPU 争用也会产生同样的问题:将 Jellyfin 媒体库换成 90 年代录像店风格在用户只浏览封面时几乎不需要额外资源,但一旦有人开始转码,Dify 的工作队列就会排在转码任务之后。Dify 的容器数量不会随着您构建的应用数量增加,这一点可以降低资源成本波动。相比之下,OpenBot 会为每个 AI 协作者分配独立容器和浏览器,每增加一个协作者,RAM 下限都会再次上升。
由于 Dify 会保存您的模型 API 密钥,以及您为检索加载的私有文档,因此从部署的第一分钟起,就应将运行 Dify 的服务器视为敏感系统。本指南会先安装 Dify,再按照保护任何保存机密信息的服务的方式对其进行加固。
前置条件
您需要一台运行 Ubuntu 24.04 的 VPS,并安装 Docker 和 Docker Compose plugin;同时需要一个具有 sudo 的用户,或属于 docker 组的用户。如果您刚开始使用 Docker,VPS 上 Docker Compose 的基础知识介绍了本指南所需的安装步骤和核心命令。建议准备一个已指向该服务器的域名,因为您应在 Dify 前配置 TLS,而不是直接使用裸 IP 地址。
第 1 步:获取 Dify 及其 Compose 文件
Dify 将 Docker 配置保存在主仓库中。克隆仓库并进入 docker 目录:
git clone https://github.com/langgenius/dify.git
cd dify/docker
cp .env.example .env.env 文件包含完整配置。开始操作前先阅读该文件。首先需要关注用于设置密码和密钥的配置项:SECRET_KEY、Postgres 密码和 Redis 密码。示例文件中的值是占位值,保留这些默认值是自托管 Dify 被入侵的最常见原因。生成一个真实的密钥:
openssl rand -base64 42将其粘贴到 SECRET_KEY 中,并为文件中的每个密码字段设置强度高且唯一的值。
第 2 步:启动服务
启动整个服务栈:
docker compose up -d首次运行会拉取多个镜像并初始化数据库,请等待片刻。检查容器是否健康:
docker compose ps每个服务都应读取 running。默认情况下,Dify 通过内置的 nginx 容器在端口 80 上提供 Web 界面。首次访问 http://YOUR_SERVER/install 时,创建管理员帐户。请立即完成此操作,确保在其他任何请求到达该端口之前完成,因为在该帐户创建前,任何打开此页面的人都可以注册并控制您的实例。
第 3 步:不要直接暴露。先配置 TLS 和防火墙
大多数快速安装到这里就停止了,而大多数安全事件也从这里开始。Dify 自带的 nginx 监听端口 80,并以明文方式绑定到所有网络接口。不要让管理员登录凭据和模型密钥通过纯 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 两个协议栈都已过滤。
对于 TLS,最简洁的做法是将 Dify 的 Web 端口绑定到 loopback,然后在前面运行一个使用 Let's Encrypt 证书的反向代理。这样,公网中唯一可见的服务就是通过 HTTPS 通信的代理。Dify 的 .env 允许你更改暴露端口;将其设置为绑定到 127.0.0.1,然后让代理指向该地址。在 VPS 上安全运行 AI agent 中的加固思路同样适用:让各组件留在 loopback 上,只暴露必须公开的服务,并让一个经过加固的入口统一处理 TLS。如果某个工具的界面只供你自己使用,完全不需要证书,可以跳过代理,通过 SSH 隧道访问。自托管 open-kritt 安全扫描器采用的就是这种方式:将其控制面板绑定到 loopback,再转发到你的笔记本,而不是直接发布到公网。如果整个团队都需要使用 Dify,但不希望它暴露到公网,overlay network 可以将这种方式扩展到多台设备:将服务器的私有子网公布到 tailnet后,每台获授权的设备都可以通过私有地址访问构建器,同时防火墙仍只允许 SSH。如果你通过 coding agent 管理这台服务器,而不是手动操作,应在授予它密钥前确定允许它在无人监督时执行多少操作,因为为 Claude Code 保留的权限模式决定了它在重写 .env 或重启服务栈前是否会先请求确认。如果一个会话正在跟踪容器日志,而另一个会话同时编辑代理配置,这两个会话可以在同一台服务器上相互传递文本。这样每次重启服务栈时,就不必在终端之间反复复制输出。
第 4 步:及时安装补丁
Dify 更新频繁,更新内容包括安全修复。从 docker 目录执行拉取和重启即可完成更新:
git pull
docker compose pull
docker compose up -d升级到主要版本前,请先阅读发行说明。因为 Dify 有时会在不同版本之间修改 .env 架构,而您尚未设置的新变量可能导致容器无法启动。
第 5 步:备份无法重新生成的数据
Dify 主机上有两类数据无法替代:保存应用、用户和设置的 Postgres 数据库,以及存储上传文档和向量索引的卷。两者都位于 docker 目录下的 Docker 卷中。按计划创建快照,并将快照复制到服务器之外。这些快照会在单个文件中包含所有模型密钥和上传文档,因此在传出主机前必须加密,原因与Vaultwarden 备份成为原本安全的密码服务器薄弱环节相同。模型 API 密钥可以重新签发,但花费一周构建的应用无法重新生成。任何需要在运行它的机器停止运行后仍保留状态的代理,都应遵循同样的原则:让 KiroCrew 作为始终运行的容器持续工作,归根结底就是创建内存和计划任务的快照,否则这些数据会在下一次重启时消失。
如果希望在此构建的代理访问自己的数据集之外的内容并搜索实时网络,将代理指向自托管的 SearXNG 实例可以让查询流保留在您控制的硬件上。不过,在启用之前,应先了解由此暴露的提示注入面。对于更自主、能够运行代码的代理,请参阅自托管 Agent Zero;在 VPS 上构建自己的 AI 代理则介绍了这些方案共同依赖的基础。
FAQ
自托管 Dify 的系统要求是什么?
Dify 以 Docker Compose 栈的形式运行,包含大约 6 个容器。因此,建议使用至少有 2 GB 可用 RAM 的 VPS,理想情况下为 4 GB,并配备至少 2 个 CPU 核心,以及足够存储上传文档和向量索引的磁盘空间。内存压力主要来自数据库和向量存储,而不是 Dify 本身。
直接通过端口 80 暴露 Dify 安全吗?
不安全。Dify 内置的 Web 服务器监听纯 HTTP,并承载管理员登录和模型 API 密钥。应在前面配置带有 Let's Encrypt 证书的反向代理,将 Dify 自身的端口绑定到 loopback,仅让 HTTPS 代理面向互联网。同时配置覆盖 IPv4 和 IPv6 的默认拒绝防火墙。
如何更新自托管的 Dify?
进入 docker 目录后,运行 git pull,然后运行 docker compose pull 和 docker compose up -d,以获取新镜像并重启服务。先阅读发行说明,因为 Dify 有时会在版本之间新增 .env 变量,缺少变量可能导致容器无法启动。
安装 Dify 后首先要做什么?
访问 /install,立即创建管理员账户。在该账户创建之前,任何能够访问此页面的人都可以占用管理员账户。应在容器状态正常后立即完成设置,并在向公网开放防火墙之前完成此操作。