环境信息:Windows 11 + WSL2 + Docker Compose | Dify 版本:1.13.3
关键词:Dify、WSL2、Docker、PostgreSQL、Ollama、向量数据库、Weaviate、MySQL、工作流
最后更新:2026年4月29日


写在前面

最近在搭建 Dify 开源 LLM 应用开发平台时,从环境部署到模型接入踩了不少坑。这些问题大多是 WSL2 特有的网络和权限问题,网上资料也比较零散,所以特地整理成一份完整的避坑指南,方便后续排查和复用。


目录


一、管理员设置页面 500 错误

1.1 问题现象

访问 http://localhost:8080/install 设置管理员账号时,页面一直加载。

浏览器控制台(F12)报错:

Failed to load resource: the server responded with a status of 500 (INTERNAL SERVER ERROR)

1.2 排查过程

# 查看所有容器运行状态
docker compose ps -a

发现关键问题:docker-db_postgres-1 容器的 STATUS 为 Restarting (1),数据库在不断重启。

# 查看数据库容器日志
docker compose logs db_postgres

核心错误信息:

initdb: error: could not change permissions of directory "/var/lib/postgresql/data/pgdata": Operation not permitted
chmod: /var/lib/postgresql/data/pgdata: Operation not permitted

1.3 根因分析

两个原因叠加导致问题:

原因 说明
WSL2 NTFS 权限问题 项目放在 /mnt/d/(Windows 文件系统)中,PostgreSQL 无法设置 Linux 权限
Profile 未指定 db_postgres 服务配置了 profiles: - postgresql,默认不会启动

1.4 解决方案

Step 1:停止服务
docker compose down
Step 2:修改 docker-compose.yaml

找到 db_postgres 服务(约第 950 行),将:

# 修改前
volumes:
  - ./volumes/db/data:/var/lib/postgresql/data

改为:

# 修改后
volumes:
  - postgres_data:/var/lib/postgresql/data

然后在文件末尾的 volumes: 区域新增一行:

volumes:
  oradata:
  dify_es01_data:
  postgres_data:   # 新增这一行
Step 3:清理损坏的数据
rm -rf ./volumes/db/data
Step 4:重新启动(必须指定 profile)
docker compose --profile postgresql up -d
Step 5:验证状态
docker compose ps

看到 docker-db_postgres-1 状态变为 healthy 即为修复成功。

![修复后所有容器正常运行]

注意:后续启动都要使用 --profile postgresql 参数,否则数据库不会启动。


二、Weaviate 向量数据库连接失败

2.1 问题现象

上传知识库文档时,Dify 提示:

Could not connect to Weaviate: Connection to Weaviate failed.

2.2 排查过程

docker compose ps | grep weaviate
# 没有任何输出,说明 Weaviate 服务根本没启动

2.3 根因分析

和 PostgreSQL 一样,docker-compose.yaml 中 Weaviate 服务也配置了 profiles: - weaviate,启动时被跳过。

2.4 解决方案

启动时同时指定多个 profile:

docker compose --profile weaviate --profile postgresql up -d

建议以后每次启动 Dify 都使用完整命令:

docker compose --profile weaviate --profile postgresql up -d

三、Ollama 模型接入失败

3.1 问题现象

在 Dify 模型供应商配置中,填写基础 URL:

http://host.docker.internal:11434

测试连接时报错:

Failed to resolve 'host.docker.internal'

3.2 根因分析

  • host.docker.internal 是 Docker Desktop(Windows/Mac)的特有功能
  • WSL2 原生 Docker 不支持此 DNS 解析
  • 即使手动找到 Windows 宿主机 IP,Ollama 默认也只监听 127.0.0.1,外部请求会被拒绝

3.3 解决方案

Step 1:让 Ollama 监听所有网络接口

① 关闭 Ollama:右键系统托盘图标,选择 Quit

② 添加 Windows 环境变量

Win + R,输入 sysdm.cpl,进入“高级”→“环境变量”,新增系统变量:

变量名 变量值
OLLAMA_HOST 0.0.0.0

③ 重新启动 Ollama

④ 验证

在 PowerShell 中执行:

netstat -an | findstr 11434

必须显示:

TCP    0.0.0.0:11434          0.0.0.0:0              LISTENING
Step 2:获取 Windows 在 WSL2 中的 IP 地址

WSL2 终端 中执行:

cat /etc/resolv.conf | grep nameserver | awk '{print $2}'

示例输出:

11.255.255.254
Step 3:验证连通性
curl http://11.255.255.254:11434/api/tags

能返回模型列表即表示网络已打通。

Step 4:在 Dify 中配置

基础 URL 填写:

http://11.255.255.254:11434

如果仍然超时,可以临时关闭 Windows 防火墙测试:

netsh advfirewall set allprofiles state off

确认连通后再开启,并添加 11434 端口的入站规则即可。


四、连接 Windows 本地 MySQL 失败

4.1 问题现象

在 Dify 的 Database 工具插件中配置连接字符串:

mysql+pymysql://root:password@172.30.80.1:3306/dify_test

报错信息:

Can't connect to MySQL server on '172.30.80.1:3306'
Host 'xxx' is not allowed to connect to this MySQL server

4.2 根因分析

原因 说明
MySQL 仅监听 127.0.0.1 外部 Docker 容器无法连接
用户权限限制 root 用户默认只允许 localhost 登录
密码特殊字符 密码含 @ # 等字符时需要 URL 编码

4.3 解决方案

Step 1:确认 MySQL 监听 0.0.0.0

在 PowerShell 中检查:

netstat -an | findstr 3306

应显示:

TCP    0.0.0.0:3306          0.0.0.0:0              LISTENING
Step 2:MySQL 用户授权远程访问

登录 MySQL 后执行:

-- 仅允许 Docker 网段访问(172.16.0.0 ~ 172.31.255.255),比 % 更安全
CREATE USER 'root'@'172.%' IDENTIFIED BY '你的密码';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'172.%' WITH GRANT OPTION;
FLUSH PRIVILEGES;
Step 3:密码 URL 编码

如果密码包含特殊字符,需要转义:

字符 URL 编码
@ %40
# %23
% %25
& %26

示例:密码 56JK@#79bbc

mysql+pymysql://root:56JK%40%2379bbc@172.30.80.1:3306/dify_test
Step 4:添加防火墙规则

使用管理员 PowerShell:

netsh advfirewall firewall add rule name="MySQL" dir=in action=allow protocol=TCP localport=3306
Step 5:验证连通性

在 WSL2 中:

curl -v telnet://172.30.80.1:3306

出现 Connected 即为成功。


五、工作流代码执行节点输出为空

5.1 问题现象

代码执行节点状态显示 SUCCESS,但下游条件分支全部跳过,图表无法渲染。

5.2 问题分析

代码依赖正则匹配 ` ```json ````标记来提取大模型输出的 JSON:

match = re.search(r'```json\s*([\s\S]*?)\s*```', args)

但 LLM 输出可能存在:

  • 多余的空格或换行
  • 缺少 ` ```json ````标记
  • 中文标点干扰

这会导致正则匹配失败,返回空默认值。

5.3 解决方案:直接定位 JSON 边界

改进后的健壮代码:

import re
import json

def main(args: str) -> dict:
    default_output = {
        "results": "",
        "ECHarts": "0",
        "chartType": "",
        "chartTitle": "",
        "chartData": "",
        "chartXAxis": ""
    }

    try:
        # 核心优化:直接找第一个 { 和最后一个 }
        start = args.find('{')
        end = args.rfind('}')
        if start != -1 and end != -1 and end > start:
            json_str = args[start:end+1]
        else:
            raise ValueError("未找到有效的 JSON 数据")

        results_dict = json.loads(json_str)
    except:
        # 降级方案:尝试正则匹配
        try:
            match = re.search(r'```json\s*\n?(.*?)\n?\s*```', args, re.DOTALL)
            if not match:
                raise ValueError("未找到有效的 JSON 数据")
            results_dict = json.loads(match.group(1).strip())
        except:
            return default_output

    # 补全缺失字段
    if "ECHarts" not in results_dict:
        results_dict["ECHarts"] = "0"

    if results_dict["ECHarts"] == "1":
        for field in ["chartType", "chartTitle", "chartData", "chartXAxis"]:
            if field not in results_dict:
                results_dict[field] = ""

    return {
        "results": str(results_dict.get("results", "")),
        "ECHarts": str(results_dict.get("ECHarts", "0")),
        "chartType": str(results_dict.get("chartType", "")),
        "chartTitle": str(results_dict.get("chartTitle", "")),
        "chartData": str(results_dict.get("chartData", "")),
        "chartXAxis": str(results_dict.get("chartXAxis", ""))
    }

核心思路是先尝试直接截取 { ... } 内容,失败后再降级使用正则匹配,兼容性会更好。


六、API 调用 curl 示例

6.1 同步请求(Blocking)

curl -X POST http://localhost:8080/v1/chat-messages \
  -H "Authorization: Bearer 你的API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "inputs": {},
    "query": "你好,请帮我分析数据",
    "response_mode": "blocking",
    "conversation_id": "",
    "user": "user-001"
  }'

6.2 流式请求(Streaming)

curl -X POST http://localhost:8080/v1/chat-messages \
  -H "Authorization: Bearer 你的API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "inputs": {},
    "query": "你好,请帮我分析数据",
    "response_mode": "streaming",
    "conversation_id": "",
    "user": "user-001"
  }'

6.3 参数说明

参数 说明
API_KEY 在 Dify “发布” → “API 访问” 页面获取
query 用户输入的问题
response_mode blocking(同步返回完整结果) / streaming(流式逐字返回)
conversation_id 首次对话留空,后续传入返回的 ID 可保持上下文
user 终端用户标识,由开发者自定义

提示:Windows PowerShell 的语法与 Bash 不完全一致,建议在 WSL2 终端中运行上述 curl 命令。


七、常见问题速查表

问题 一键定位命令 根因 快速修复
PostgreSQL 反复重启 docker compose logs db_postgres NTFS 权限问题 改用 Docker 命名卷
Weaviate 连接失败 docker compose ps | grep weaviate 未指定 profile 启动加 --profile weaviate
Ollama DNS 解析失败 docker compose logs api | grep host.docker WSL2 不支持 host.docker.internal 使用 cat /etc/resolv.conf 获取的 IP
Ollama 连接超时 curl http://<IP>:11434/api/tags 监听 127.0.0.1 / 防火墙 设置 OLLAMA_HOST=0.0.0.0
MySQL 连接被拒 curl -v telnet://<IP>:3306 用户无远程权限 授权 root@'172.%'
密码含特殊字符报错 - @ # 未编码 @%40#%23
代码节点输出为空 查看节点运行日志 JSON 提取正则失效 find('{') 直接截取
API 调用失败 查看浏览器 Network 面板 端口或路径错误 确认 URL 为 http://localhost:8080/v1/...

总结

这些问题的根源大多在于 WSL2 与 Windows 的网络隔离,再加上 Docker Profile 机制 的影响。掌握下面两个核心点,就能避免大部分坑:

  1. WSL2 访问 Windows 服务:使用 cat /etc/resolv.conf 获取的 IP,而不是 localhosthost.docker.internal
  2. Docker Profile:启动命令需要加上 --profile weaviate --profile postgresql

如果这篇文章对你有帮助,欢迎点赞收藏。遇到其他问题,也可以继续交流。


原创整理,转载请注明出处

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐