Dify:AI 工作流平台
如何使用 Pigsty 自建 AI Workflow LLMOps 平台 —— Dify,并使用外部 PostgreSQL,PGVector,Redis 作为存储?
Dify 是一个生成式 AI 应用创新引擎和开源 LLM 应用开发平台。它提供从 Agent 构建到 AI 工作流编排、RAG 检索和模型管理的能力,帮助用户轻松构建和运营生成式 AI 原生应用程序。
Pigsty 提供对自托管 Dify 的支持,允许您使用单个命令部署 Dify,同时将关键状态存储在外部管理的 PostgreSQL 中。您可以在同一个 PostgreSQL 实例中使用 pgvector 作为向量数据库,进一步简化部署。
app/dify 模板最后验证的 Dify 版本:v1.15.0(2026-07-09)。模板包含一份针对 PostgreSQL 18 内置 uuidv7() 的 Dify 迁移脚本兼容补丁。
快速开始
在运行 兼容操作系统 的全新 Linux x86 / ARM 服务器上执行:
curl -fsSL https://repo.pigsty.cc/get | bash; cd ~/pigsty
./bootstrap # 安装 Pigsty 依赖
./configure -c app/dify # 使用 Dify 配置模板
vi pigsty.yml # 编辑密码、域名、密钥等
./deploy.yml # 安装 Pigsty
./docker.yml # 安装 Docker 和 Compose
./app.yml # 安装 Dify
Dify 默认监听端口 5001。您可以通过浏览器访问 http://<ip>:5001 并设置您的初始用户凭据来登录。
Dify 启动后,您可以安装各种扩展、配置系统模型并开始使用它!
为什么要自托管
自托管 Dify 有很多原因,但主要动机是数据安全。Dify 提供的 DockerCompose 模板使用基本的默认数据库镜像,缺乏企业级功能,如高可用性、灾难恢复、监控、IaC 和 PITR 能力。
Pigsty 为 Dify 提供声明式部署,并可使用镜像解决中国地区的镜像访问问题。模板将 PostgreSQL 与 pgvector 交给 Pigsty 管理,
部署 Compose Redis、VictoriaMetrics/Grafana 监控与 Nginx 反向代理;满足公网 DNS、端口和 Certbot 配置后,还可申请 Let’s Encrypt 证书。
文件默认保存到 DIFY_DATA(/data/dify),也可按需接入 Silo/S3 对象存储。
当前模板把 PostgreSQL/pgvector 放在 Pigsty 管理的外部数据库中,并把 API 文件与插件数据定向到 DIFY_DATA(默认 /data/dify)。但 Compose 内置 Redis 的数据仍位于 /opt/dify/volumes/redis/data,Sandbox 依赖与 Certbot 数据也位于 /opt/dify/volumes/,因此整套应用并非完全无状态,备份时不能只保留数据库。
安装
让我们从单节点 Dify 部署开始。我们稍后将介绍生产高可用部署方法。
首先,使用 Pigsty 的 标准安装过程 安装 Dify 所需的 PostgreSQL 实例:
curl -fsSL https://repo.pigsty.cc/get | bash; cd ~/pigsty
./bootstrap # 准备 Pigsty 依赖
./configure -c app/dify # 使用 Dify 应用程序模板
vi pigsty.yml # 编辑配置文件,修改域名和密码
./deploy.yml # 安装 Pigsty 和各种数据库
当您使用 ./configure -c app/dify 命令时,Pigsty 会根据 conf/app/dify.yml 模板和您当前的环境自动生成配置文件。
您应该根据实际需要在生成的 pigsty.yml 配置文件中修改密码、域名和其他相关参数,然后使用 ./deploy.yml 执行标准安装过程。
接下来,运行 docker.yml 安装 Docker 和 Docker Compose,然后使用 app.yml 完成 Dify 部署:
./docker.yml -l dify # 在 Dify 节点安装 Docker 和 Docker Compose
./app.yml -l dify # 使用 Docker 部署 Dify 应用组件
您可以在本地网络上通过 http://<your_ip_address>:5001 访问 Dify Web 管理界面。
首次登录时会提示设置默认用户名、邮箱和密码。
您也可以使用本地解析的占位符域名 dify.pigsty,或按照下面的配置使用带有 HTTPS 证书的真实域名。
配置
当您使用 ./configure -c app/dify 命令进行配置时,Pigsty 会根据 conf/app/dify.yml 模板和当前环境生成配置文件。以下快照与 v4.5.0 源模板同步:
---
#==============================================================#
# File : dify.yml
# Desc : pigsty config for running 1-node dify app
# Ctime : 2025-02-24
# Mtime : 2026-07-09
# Docs : https://pigsty.io/docs/app/dify
# License : Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright : 2018-2026 Ruohang Feng / Vonng (rh@vonng.com)
#==============================================================#
# Last Verified Dify Version: v1.15.0 on 2026-07-09
# tutorial: https://pigsty.io/docs/app/dify
# how to use this template:
#
# curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
# ./bootstrap # prepare local repo & ansible
# ./configure -c app/dify # use this dify config template
# vi pigsty.yml # IMPORTANT: CHANGE CREDENTIALS!!
# ./deploy.yml # install pigsty & pgsql
# ./docker.yml # install docker & docker-compose
# ./app.yml # install dify with docker-compose
#
# To replace domain name:
# sed -ie 's/dify.pigsty/dify.pigsty.cc/g' pigsty.yml
all:
children:
# the dify application
dify:
hosts: { 10.10.10.10: {} }
vars:
app: dify # specify app name to be installed (in the apps)
apps: # define all applications
dify: # app name, should have corresponding ~/pigsty/app/dify folder
file: # data directory to be created
- { path: /data/dify ,state: directory ,mode: 0755 }
conf: # override /opt/dify/.env config file
# change domain, mirror, proxy, secret key
NGINX_SERVER_NAME: dify.pigsty
# A secret key for signing and encryption, gen with `openssl rand -base64 42` (CHANGE PASSWORD!)
SECRET_KEY: sk-somerandomkey
# expose DIFY nginx service with port 5001 by default
DIFY_PORT: 5001
# where to store dify files? the default is ./volume, we'll use another volume created above
DIFY_DATA: /data/dify
# enable the upstream websocket sidecar, while keeping PostgreSQL/pgvector external
COMPOSE_PROFILES: collaboration
NEXT_PUBLIC_SOCKET_URL: ws://dify.pigsty
TRIGGER_URL: http://dify.pigsty
ENDPOINT_URL_TEMPLATE: http://dify.pigsty/e/{hook_id}
# proxy and mirror settings
#PIP_MIRROR_URL: https://pypi.tuna.tsinghua.edu.cn/simple
#SANDBOX_HTTP_PROXY: http://10.10.10.10:12345
#SANDBOX_HTTPS_PROXY: http://10.10.10.10:12345
# database credentials
DB_TYPE: postgresql
DB_USERNAME: dify
DB_PASSWORD: difyai123456
DB_HOST: 10.10.10.10
DB_PORT: 5432
DB_DATABASE: dify
DB_SSL_MODE: disable
VECTOR_STORE: pgvector
PGVECTOR_HOST: 10.10.10.10
PGVECTOR_PORT: 5432
PGVECTOR_USER: dify
PGVECTOR_PASSWORD: difyai123456
PGVECTOR_DATABASE: dify
PGVECTOR_MIN_CONNECTION: 2
PGVECTOR_MAX_CONNECTION: 10
# optional MinIO/S3 storage, disabled by default to avoid touching backup MinIO
#STORAGE_TYPE: s3
#S3_ENDPOINT: http://10.10.10.10:9000
#S3_BUCKET_NAME: dify
#S3_ACCESS_KEY: dify
#S3_SECRET_KEY: S3User.Dify
#S3_REGION: us-east-1
#S3_ADDRESS_STYLE: path
pg-meta:
hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
vars:
pg_cluster: pg-meta
pg_extensions: [ pgvector ]
pg_users:
- { name: dify ,password: difyai123456 ,pgbouncer: true ,roles: [ dbrole_admin ] ,superuser: true ,comment: dify superuser }
pg_databases:
- { name: dify ,owner: dify ,extensions: [ { name: vector } ] ,comment: dify main database }
- { name: dify_plugin ,owner: dify ,comment: dify plugin daemon database }
pg_hba_rules:
- { user: dify ,db: all ,addr: 172.16.0.0/12 ,auth: pwd ,title: 'allow dify access from local docker networks' }
pg_crontab: [ '00 01 * * * /pg/bin/pg-backup full' ] # make a full backup every 1am
infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }
etcd: { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }
#minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio } }
vars: # global variables
version: v4.5.0 # pigsty version string
admin_ip: 10.10.10.10 # admin node ip address
region: default # upstream mirror region: default|china|europe
node_tune: oltp # node tuning specs: oltp,olap,tiny,crit
pg_conf: oltp.yml # pgsql tuning specs: {oltp,olap,tiny,crit}.yml
docker_enabled: true # enable docker on app group
#docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]
proxy_env: # global proxy env when downloading packages & pull docker images
no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.tsinghua.edu.cn"
#http_proxy: 127.0.0.1:12345 # add your proxy env here for downloading packages or pull images
#https_proxy: 127.0.0.1:12345 # usually the proxy is format as http://user:pass@proxy.xxx.com
#all_proxy: 127.0.0.1:12345
infra_portal: # domain names and upstream servers
home : { domain: i.pigsty }
#minio : { domain: m.pigsty ,endpoint: "${admin_ip}:9001" ,scheme: https ,websocket: true }
dify: # nginx server config for dify
domain: dify.pigsty # REPLACE WITH YOUR OWN DOMAIN!
endpoint: "10.10.10.10:5001" # dify service endpoint: IP:PORT
websocket: true # add websocket support
certbot: dify.pigsty # certbot cert name, apply with `make cert`
repo_enabled: false
node_repo_modules: node,infra,pgsql
# Dify v1.15.0 is patched in app/dify/patches for PostgreSQL 18's built-in uuidv7().
pg_version: 18
#----------------------------------------------#
# PASSWORD : https://pigsty.io/docs/setup/security/
#----------------------------------------------#
grafana_admin_password: pigsty
grafana_view_password: DBUser.Viewer
pg_admin_password: DBUser.DBA
pg_monitor_password: DBUser.Monitor
pg_replication_password: DBUser.Replicator
patroni_password: Patroni.API
haproxy_admin_password: pigsty
minio_secret_key: S3User.MinIO
etcd_root_password: Etcd.Root
...
检查清单
以下是您需要关注的配置项检查清单:
- 硬件/软件:准备所需的机器资源:Linux
x86_64/arm64 服务器,主流 Linux 操作系统 的全新安装 - 网络/权限:SSH 免密登录访问权限,用户具有 免密 sudo 权限
- 确保机器在内网中有静态 IPv4 网络地址且可访问互联网
- 如果通过公网访问,确保您有可用的域名指向当前节点的 公网 IP 地址
- 确保使用
app/dify 配置模板并根据需要修改参数configure -c app/dify,并输入节点的内网主 IP 地址,或通过 -i <primary_ip> 命令行参数指定
- 在生产环境中,您是否已经修改全部示例密码、应用密钥与数据库凭据?【必需】
- 您是否修改了 PostgreSQL 集群业务用户密码和使用这些密码的应用程序配置?
- 默认用户名
dify 和密码 difyai123456 是 Pigsty 为 Dify 生成的,请根据实际情况修改 - 在 Dify 的配置块中,请相应修改
DB_USERNAME、DB_PASSWORD、PGVECTOR_USER、PGVECTOR_PASSWORD 等参数
- 您是否修改了 Dify 的默认加密密钥?
- 您可以使用
openssl rand -base64 42 随机生成密码字符串并填入 SECRET_KEY 参数
- 您是否修改了 Dify 使用的域名?
- 将占位符域名
dify.pigsty 替换为您的实际域名,例如 dify.pigsty.cc - 您可以使用
sed -ie 's/dify.pigsty/dify.pigsty.cc/g' pigsty.yml 修改 Dify 的域名
域名和 SSL
如果您想使用带有 HTTPS 证书的真实域名,需要在 pigsty.yml 配置文件中修改:
all:
children: # 集群定义
dify: # Dify 组
vars: # Dify 组变量
apps: # 应用程序配置
dify: # Dify 应用程序定义
conf: # Dify 应用程序配置
NGINX_SERVER_NAME: dify.pigsty
vars: # 全局参数
#certbot_sign: true # 使用 Certbot 申请免费 HTTPS 证书
certbot_email: your@email.com # 证书申请邮箱,用于过期通知,可选
infra_portal: # 配置 Nginx 服务器
dify: # Dify 服务器定义
domain: dify.pigsty # 请在此处替换为您自己的域名!
endpoint: "10.10.10.10:5001" # 请在此处指定 Dify 的 IP 和端口(默认自动配置)
websocket: true # Dify 需要启用 websocket
certbot: dify.pigsty # 指定 Certbot 证书名称
使用以下命令申请 Nginx 证书:
# 在明确限定的 infra 组上申请并加载证书
./infra.yml -l infra -t nginx_certbot,nginx_reload -e certbot_sign=true
执行 app.yml 剧本重新部署 Dify 服务以使 NGINX_SERVER_NAME 配置生效。
./app.yml -l dify -t app_config,app_launch
文件备份
您可以使用 restic 备份 Dify 的文件状态。当前模板至少需要保留 /data/dify、/opt/dify/.env 与 /opt/dify/volumes/;其中后者包含 Compose Redis、Sandbox 依赖和可能存在的 Certbot 数据。PostgreSQL 中的 Dify 数据仍应使用 Pigsty/pgBackRest 单独备份。
export RESTIC_REPOSITORY=/data/backups/dify # 指定 dify 备份目录
export RESTIC_PASSWORD=some-strong-password # 指定备份加密密码
mkdir -p ${RESTIC_REPOSITORY} # 创建 dify 备份目录
restic init
创建 Restic 备份仓库后,您可以使用以下命令备份 Dify:
export RESTIC_REPOSITORY=/data/backups/dify # 指定 dify 备份目录
export RESTIC_PASSWORD=some-strong-password # 指定备份加密密码
restic backup /data/dify /opt/dify/.env /opt/dify/volumes
restic snapshots # 查看备份快照列表
restic restore 0b11f778 --target /tmp/dify-restore # 先恢复到临时目录,核对后再回填
restic check # 定期检查仓库完整性
另一种方案是把 /data/dify 放在由 JUICE 模块管理的共享文件系统上。文件数据可以位于 Silo/S3,也可以位于 PostgreSQL 的 jfs_blob 表;后者并不是“大对象”存储。
若使用 PostgreSQL 同时保存 JuiceFS 元数据和文件数据,请先在 pg_databases 中声明并创建专用数据库和最小权限用户,再在 Dify 节点上声明实例。以下示例中的密码只是占位符,不能直接用于生产环境:
pg_databases:
- { name: dify_fs, owner: dify, comment: JuiceFS metadata and data for Dify }
juice_instances:
dify:
path: /data/dify
meta: postgres://dify:<password>@10.10.10.10:5432/dify_fs
data: --storage postgres --bucket 10.10.10.10:5432/dify_fs --access-key dify --secret-key <password>
owner: 1001
group: 1001
port: 9567
先分别对数据库创建与 JUICE 部署做检查,确认精确目标后再执行实际 playbook:
./pgsql-db.yml -l pg-meta -e dbname=dify_fs
./juice.yml -l dify -e fsname=dify
数据库创建、文件系统首次格式化和挂载都会改变目标环境,实际执行前必须确认备份、数据库名和主机组。部署后再启动 Dify,参见 JUICE 配置 与 PITR 一致性边界。直接挂载到已有非空的 /data/dify 之前,还必须先停止 Dify 并规划现有文件迁移。
参考
Dify 自托管常见问题
感谢反馈,我们会据此改进这篇文档。
哪里没有解决?(可选)