Dify数据库迁移(PostgreSQL)安全指南
PostgreSQL 迁移这事儿,说大不大说小不小,但要是真把 Dify 的数据库从一台服务器搬到另一台,稍不留神就会翻车。元数据对不上、用户权限跑偏、时区设置没同步、UUID 主键断了链——随便一个坑,都能让你的 Dify 直接罢工,账号登不上、知识库打不开、API 直接甩 500。下面这三步,是实战里踩过无数坑才总结出来的硬核流程,照着做至少能少熬几个通宵。

迁移前必须做的三件事
首先得确认源库的 PostgreSQL 版本是不是大于等于 13。别小看这个版本号,低于 13 的话,pg_dump 会在兼容性上翻车——尤其是那些 GENERATED ALWAYS AS IDENTITY 的字段定义,导出来就可能缺胳膊少腿,等你导入目标库才发现,晚了。
确认版本没问题后,执行这条命令:
pg_dump --no-owner --no-privileges -Fc -f backup.dump dify
--no-owner 和 --no-privileges 是为了剥离掉所有权和权限信息——你想想,如果目标库的用户 ID 跟源库对不上,Dify 容器启动时直接报错,这锅谁背?而 -Fc 强制使用自定义格式,保证了 dump 文件的完整性和灵活性。
还有一件容易被忽略的事:时区。在源库跑一句
show timezone;
'Asia/Shanghai')。不然的话,created_at 这类时间字段会偏移 8 小时,RAG 检索结果按时间排序时,直接错乱到让你怀疑人生。
迁移中两个不可跳过的校验点
导入之前,用
pg_restore -l
documents、applications、users、tenant_settings。尤其是 tenant_settings,这个表要是丢了,整个租户体系就废了,Dify 初始化直接卡死。
导入动作开始前,别忘了在目标库执行一句:
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
导入完成后,立刻跑两个 COUNT 验证:
SELECT COUNT(*) FROM users;
SELECT COUNT(*) FROM documents WHERE status = 'active';
迁移后必须修复的权限陷阱
PostgreSQL 容器内部是以 UID=999 的 postgres 用户运行的。但宿主机上挂载的 volumes/db/data 目录,如果属主是 root,那容器启动时就会直接报 FATAL: data directory has invalid permissions,然后拒绝拉起。解决办法很简单:
chown -R 999:999 ./volumes/db/data
这条命令直接在目标服务器的 volumes 目录下执行就行,几秒钟的事。但漏掉这一步,你会在 docker-compose up 的第一秒就卡住,反复重启也毫无意义。
验证连接是否真正生效
最后一步,进到 dify-api 容器里跑个 Python 脚本确认一下:
docker exec -it dify-api bash
python3 -c "from sqlalchemy import create_engine; e = create_engine('postgresql://postgres:YOUR_PASS@db_postgres:5432/dify'); c = e.connect(); print(c.execute('SELECT version()').fetchone()); c.close()"
如果输出里能看到 PostgreSQL 字样而没有异常堆栈,那恭喜,迁移成功。如果报 OperationalError: (psycopg2.OperationalError) could not translate host name "db_postgres",说明 docker-compose.yaml 里的 service 名称跟环境变量 SQLALCHEMY_DATABASE_URI 里的 host 对不上——回去改配置文件吧,别硬扛。