Dify 1.1.3 自部署完整指南 — 从空白 Linux 到上线
✅ 本帖是基于实际部署经验整理的一站式教程,全部踩坑记录都在,照着走一定能跑起来。
环境:Linux + Docker Compose,单机部署,nginx 统一入口 + 可选 NPS 内网穿透。
目录
- 前置要求
- 安装 Docker 环境
- 目录规划
- 编写 docker-compose.yaml
- 编写 nginx 配置
- 启动全部容器
- 数据库迁移
- 首次访问与初始化
- 外网访问(NPS 内网穿透)
- 常见问题与踩坑记录
- 日常运维命令
1. 前置要求
| 项目 | 最低配置 | 推荐配置 |
|---|---|---|
| CPU | 2 核 | 4 核 |
| 内存 | 4 GB | 8 GB |
| 磁盘 | 20 GB | 50 GB+(向量数据和文件存储比较吃空间) |
| 系统 | Ubuntu 20.04+ / Debian 11+ / CentOS 7+ | 同左 |
| Docker | 24+ | 最新版 |
需要开放的端口(按需):
| 端口 | 用途 |
|---|---|
3199 | Dify 主入口(nginx 统一代理) |
33099 | 仅 NPS 隧道使用时映射到外网 |
80 / 443 | 如果有独立公网 IP 直接反代 |
2. 安装 Docker 环境
# ----- Docker -----
curl -fsSL https://get.docker.com | bash
sudo systemctl enable --now docker
# ----- Docker Compose 插件 -----
# Docker 24+ 自带 compose 插件,验证:
docker compose version
# 如果是旧版 Docker,单独安装:
# sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# sudo chmod +x /usr/local/bin/docker-compose
3. 目录规划
# 创建部署目录
sudo mkdir -p /data/dify
cd /data/dify
数据存储目录(建议放到大分区):
# 假设 /data 是大数据盘
sudo mkdir -p /data/dify/storage
sudo mkdir -p /data/dify/db/data
sudo mkdir -p /data/dify/redis/data
sudo mkdir -p /data/dify/weaviate/data
sudo mkdir -p /data/dify/plugin_daemon
# 或者直接用 docker-compose 同级目录:
# sudo mkdir -p ./storage ./db/data ./redis/data ./weaviate/data ./plugin_daemon
最终目录结构:
/data/dify/
├── docker-compose.yaml # 主配置
├── nginx.conf # nginx 反向代理配置
├── storage/ # 上传文件
├── db/data/ # PostgreSQL 数据
├── redis/data/ # Redis 数据
├── weaviate/data/ # Weaviate 向量数据
└── plugin_daemon/ # 插件存储
4. 编写 docker-compose.yaml
⚠️ 这是全教程最关键的部分。 Dify 官方文档给的 docker-compose 用了大量
.env文件拆分,新手容易漏配。下面这份是整合好的单文件版本,包含所有 8 个容器,直接复制就能用。
文件:/data/dify/docker-compose.yaml
name: dify
x-shared-env: &shared-api-worker-env
LOG_LEVEL: INFO
DEBUG: "false"
EDITION: SELF_HOSTED
DEPLOY_ENV: PRODUCTION
SECRET_KEY: your-secret-key-change-in-prod # ← 改掉!
INIT_PASSWORD: your-admin-password # ← 改掉!初始化管理员用
DB_USERNAME: postgres
DB_PASSWORD: dify123456 # ← 建议改掉
DB_HOST: db
DB_PORT: 5432
DB_DATABASE: dify
REDIS_HOST: redis
REDIS_PORT: 6379
REDIS_PASSWORD: dify123456 # ← 建议改掉
CELERY_BROKER_URL: redis://:dify123456@redis:6379/1
STORAGE_TYPE: local
STORAGE_LOCAL_PATH: storage
VECTOR_STORE: weaviate
WEAVIATE_HOST: weaviate
WEAVIATE_PORT: 8080
WEAVIATE_SCHEME: http
WEAVIATE_BATCH_SIZE: 100
WEAVIATE_TEXT_KEY: text
PLUGIN_DAEMON_URL: http://plugin_daemon:5002
PLUGIN_DAEMON_KEY: your-plugin-daemon-key # ← 改掉!插件 daemon 密钥
DIFY_INNER_API_KEY: your-inner-api-key # ← 改掉!内部通信密钥
services:
api:
image: langgenius/dify-api:1.1.3
restart: always
environment:
<<: *shared-api-worker-env
MODE: normal
volumes:
- /data/dify/storage:/app/api/storage
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
networks:
- dify-network
worker:
image: langgenius/dify-api:1.1.3
restart: always
environment:
<<: *shared-api-worker-env
MODE: worker
command: celery -A app.celery worker --pool=gevent --concurrency=10 -n worker@%h
volumes:
- /data/dify/storage:/app/api/storage
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
networks:
- dify-network
web:
image: langgenius/dify-web:1.1.3
restart: always
environment:
NEXT_TELEMETRY_DISABLED: "1"
# 这俩设空,让前端走同源相对路径,靠 nginx 代理
CONSOLE_API_URL: ""
APP_API_URL: ""
depends_on:
- api
networks:
- dify-network
db:
image: postgres:15-alpine
restart: always
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: dify123456
POSTGRES_DB: dify
PGDATA: /var/lib/postgresql/data/pgdata
volumes:
- /data/dify/db/data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
networks:
- dify-network
redis:
image: redis:7-alpine
restart: always
command: redis-server --requirepass dify123456 --appendonly yes
volumes:
- /data/dify/redis/data:/data
healthcheck:
test: ["CMD", "redis-cli", "-a", "dify123456", "ping"]
interval: 10s
timeout: 5s
retries: 5
networks:
- dify-network
weaviate:
image: semitechnologies/weaviate:1.19.0
restart: always
volumes:
- /data/dify/weaviate/data:/var/lib/weaviate
environment:
AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: "true"
PERSISTENCE_DATA_PATH: /var/lib/weaviate
DEFAULT_VECTORIZER_MODULE: "none"
CLUSTER_HOSTNAME: node1
networks:
- dify-network
nginx:
image: nginx:alpine
restart: always
ports:
- "3199:80"
volumes:
- /data/dify/storage:/app/api/storage
- /data/dify/nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- api
- web
networks:
- dify-network
plugin_daemon:
image: langgenius/dify-plugin-daemon:0.0.6-local
restart: always
environment:
<<: *shared-api-worker-env
SERVER_PORT: 5002
SERVER_KEY: your-plugin-daemon-key # ← 和上面 PLUGIN_DAEMON_KEY 保持一致
DIFY_INNER_API_URL: http://api:5001
DIFY_INNER_API_KEY: your-inner-api-key # ← 和上面保持一致
MAX_PLUGIN_PACKAGE_SIZE: 52428800
PLUGIN_REMOTE_INSTALLING_HOST: your-domain-or-ip # ← 外网域名或 IP
PLUGIN_REMOTE_INSTALLING_PORT: 3199 # ← 外网端口
PLUGIN_WORKING_PATH: /app/storage/cwd
DB_DATABASE: dify
DB_SSL_MODE: disable
FORCE_VERIFYING_SIGNATURE: "true"
volumes:
- /data/dify/plugin_daemon:/app/storage
depends_on:
- db
networks:
- dify-network
networks:
dify-network:
driver: bridge
需要改的配置项
| 配置项 | 说明 |
|---|---|
SECRET_KEY | 应用加密密钥,生成随机字符串 |
INIT_PASSWORD | 首次初始化管理员密码 |
DB_PASSWORD | PostgreSQL 密码 |
REDIS_PASSWORD | Redis 密码 |
PLUGIN_DAEMON_KEY / SERVER_KEY | 插件 daemon 密钥,两处保持一致 |
DIFY_INNER_API_KEY | API 与插件 daemon 内部通信密钥,两处保持一致 |
PLUGIN_REMOTE_INSTALLING_HOST | 外网可访问的域名或 IP |
PLUGIN_REMOTE_INSTALLING_PORT | 外网端口 |
生成随机密钥的快捷命令:
# Linux
openssl rand -base64 32
# 或者直接用
date +%s | md5sum | head -c 32
5. 编写 nginx 配置
为什么要用 nginx?因为 Dify 的 API 和 Web 前端是分开的容器(api:5001 和 web:3000),直接暴露哪个都不对。nginx 做统一入口,按路径分流。
文件:/data/dify/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
# API upstream
upstream api {
server api:5001;
}
# Web upstream
upstream web {
server web:3000;
}
server {
listen 80 default_server;
server_name _;
# API 路由(后台管理 API)
location /console/api/ {
proxy_pass http://api/console/api/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 600s;
}
# API 路由(应用 API)
location /api/ {
proxy_pass http://api/api/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 600s;
}
# 文件服务
location /files/ {
proxy_pass http://api/files/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 600s;
}
# Web 前端(兜底路由,所有其他请求走前端)
location / {
proxy_pass http://web/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}
6. 启动全部容器
cd /data/dify
# 启动
docker compose up -d
# 查看状态(所有 8 个容器都应该是 Up)
docker compose ps
# 看看日志有没有报错
docker compose logs --tail=30
正常输出应该长这样:
NAME STATUS PORTS
dify-api-1 Up ~
dify-worker-1 Up ~
dify-web-1 Up ~
dify-db-1 Up (healthy) ~
dify-redis-1 Up (healthy) ~
dify-weaviate-1 Up ~
dify-nginx-1 Up 0.0.0.0:3199->80/tcp
dify-plugin_daemon-1 Up ~
⚠️ 如果某个容器状态是
Restarting,用docker logs <容器名>查看具体报错。常见问题见第 10 节。
7. 数据库迁移
API 容器启动后,需要执行数据库迁移来创建表结构:
# 执行数据库迁移
docker compose exec api flask db upgrade
# 成功输出示例:
# INFO [alembic.runtime.migration] Running migrate...
# INFO [alembic.runtime.migration] Running upgrade -> xxxx, init
如果没有报错就说明迁移完成。可以进数据库验证:
docker compose exec db psql -U postgres -d dify -c "\dt"
8. 首次访问与初始化
本地访问:
http://你的服务器IP:3199
初始化步骤:
- 打开页面 → 看到 Dify 初始化设置页
- 输入管理员邮箱和密码(对应
INIT_PASSWORD环境变量里设置的值) - 点击确认 → 设置完成
- 用刚刚设置的邮箱+密码登录
登录成功后,可以看到 Dify 的工作台首页,就可以开始创建应用了 🎉
9. 外网访问(NPS 内网穿透)
如果你没有公网 IP,需要用 frp / NPS / ngrok 这类工具做内网穿透。
NPS 隧道配置示例
以 NPS 为例,隧道映射关系:
| NPS 端口 | 目标 |
|---|---|
33099 | 127.0.0.1:3199(nginx 统一入口) |
⚠️ 不要映射到 web:3000 或 api:5001 的独立端口,一定要走 nginx 的入口。
在 Dify 后台的「设置 → 模型供应商」中配置 LLM 时,注意回调地址也要用外网域名:
http://你的域名:33099/v1
10. 常见问题与踩坑记录
10.1 前端白屏 / API 404
症状: 页面打开了但全是白色,控制台 JS 报 404。
原因: CONSOLE_API_URL 和 APP_API_URL 没设空,前端 JS 尝试请求 http://127.0.0.1:5001。
解决: web 容器 environment 中加:
CONSOLE_API_URL: ""
APP_API_URL: ""
这样前端走同源相对路径,由 nginx 代理到正确后端。
10.2 插件报 500 / PluginDaemonInnerError
症状: 打开模型设置或插件页面时 API 返回 500,日志报:
Failed to resolve 'plugin_daemon' - Name or service not known
原因: plugin_daemon 容器启动失败或未启动。
排查:
docker compose ps plugin_daemon
# 如果是 Restarting,看日志
docker logs dify-plugin_daemon-1
10.3 plugin_daemon 启动崩溃
症状: plugin_daemon 不断重启,日志依次报:
[PANIC] DifyInnerApiKey... required tag
[PANIC] plugin remote installing host is empty
[PANIC] plugin remote installing port is empty
[PANIC] plugin working path is empty
原因: 0.0.6-local 版本的 plugin_daemon 对配置检查非常严格,按顺序检查,缺一个就 panic 一次。必须补全以下环境变量:
DIFY_INNER_API_KEY: xxx # api 和 plugin_daemon 都要有
DIFY_INNER_API_URL: http://api:5001
PLUGIN_REMOTE_INSTALLING_HOST: your-domain
PLUGIN_REMOTE_INSTALLING_PORT: 3199
PLUGIN_WORKING_PATH: /app/storage/cwd
DB_DATABASE: dify
DB_SSL_MODE: disable
10.4 存储空间不足
症状: 用了一段时间后磁盘满了,容器写不进数据。
原因: 默认配置下数据都写在 docker-compose 同级目录,如果系统盘小(比如 32GB),很容易撑爆。
解决: 所有 volumes 映射到大分区,上面的配置已经做了这件事。
检查磁盘空间:
df -h
du -sh /data/dify/*
10.5 跨域问题
症状: 浏览器控制台报 CORS 错误。
原因: 前端域名和后端 API 域名不一致,或者 nginx 没配好。
解决: 确保 nginx 配置了正确的 proxy_set_header,并且前端 CONSOLE_API_URL / APP_API_URL 设为空字符串走同源。
10.6 API 返回 502 Bad Gateway
原因: api 容器还没启动好,nginx 代理不到。
解决: 等几秒重试,或者检查 api 容器日志:
docker compose logs api --tail=20
11. 日常运维命令
# 进入部署目录
cd /data/dify
# 启动/停止全部
docker compose up -d
docker compose down
# 重启单个服务
docker compose restart api
docker compose restart web
docker compose restart nginx
docker compose restart plugin_daemon
# 查看日志
docker compose logs api --tail=50
docker compose logs web --tail=50
docker compose logs plugin_daemon --tail=50
# 查看所有容器状态
docker compose ps
# 更新容器(先拉新镜像)
docker compose pull api web
docker compose up -d
# 升级前备份数据库
docker compose exec db pg_dump -U postgres dify > dify_backup_$(date +%Y%m%d).sql
# 进入数据库
docker compose exec db psql -U postgres -d dify
# 查看资源占用
docker stats
附:整体架构图
用户
│
▼
http://域名:3199(或外网穿透端口)
│
├── nginx (监听 3199)
│ │
│ ├── /console/api/* ──→ api:5001
│ ├── /api/* ──→ api:5001
│ ├── /files/* ──→ api:5001
│ └── /* ──→ web:3000
│
├── api:5001 ← Dify API 服务
├── worker ← Celery 异步任务
├── web:3000 ← Next.js 前端
├── plugin_daemon:5002 ← 插件后台
│
├── db:5432 ← PostgreSQL 15
├── redis:6379 ← 缓存 / Celery Broker
└── weaviate:8080 ← 向量数据库
总结
Dify 自部署核心就三点:
- nginx 统一入口 — 解决跨域和端口暴露问题
- plugin_daemon 环境变量补全 — 这版 daemon 配置检查很严格,缺一个就崩
- 数据挂载到大分区 — 避免系统盘撑爆
照着上面一步步走,半小时内应该能跑起来。遇到问题先看第 10 节,基本覆盖了所有常见坑。
如果对你有帮助,点个 👍~