Dify Docker 连接宿主机 MCP 服务 403 排障指南

📅 2026/7/30 15:15:01 👁️ 阅读次数 📝 编程学习
Dify Docker 连接宿主机 MCP 服务 403 排障指南

Dify Docker 连接宿主机 MCP 服务 403 排障指南

问题场景

  • Dify通过 Docker Compose 部署在宿主机
  • MCP 服务(如 searXNG-mcp)运行在宿主机,监听0.0.0.0:3456
  • 宿主机本地测试 MCP 服务正常
  • Dify 界面添加 MCP 服务时报错:
Failed to connect to MCP server: code=403 message="Client error '403 Forbidden' for url http://192.168.31.184:3456/mcp"

根因分析

Dify 的 docker-compose 中包含一个ssrf_proxy容器(基于 Squid),用于防止 SSRF 攻击。Squid 配置中默认拦截所有内网 IP 段的请求:

  • squid.conf.template第 13 行:http_access deny to_private_networks
  • to_private_networksACL 包含192.168.0.0/16,宿主机 IP192.168.31.184被命中

Dify 内部发出的外部请求走ssrf_proxy:3128代理,因此 MCP 请求在到达宿主机前被 Squid 拦截返回 403。

关键文件

文件作用
docker/ssrf_proxy/squid.conf.template主配置模板,第 12 行 include 白名单,第 13 行 deny 私网
docker/ssrf_proxy/docker-entrypoint.sh入口脚本,读取环境变量动态生成白名单
.envDify 环境变量配置文件

入口脚本白名单机制

docker-entrypoint.sh第 55 行:

write_optional_private_allowlist"SSRF_PROXY_ALLOW_PRIVATE_IPS""dify_allowed_private_networks""dst"

该函数读取SSRF_PROXY_ALLOW_PRIVATE_IPS环境变量(逗号分隔的 IP 列表),动态生成/etc/squid/dify_allow_private.conf,内容格式:

acl dify_allowed_private_networks dst 192.168.31.184 http_access allow client_localnet dify_allowed_private_networks

该文件在deny to_private_networks之前被 include,因此匹配的请求会被提前放行。

解决步骤

第一步:确保 MCP 服务绑定 0.0.0.0

部分 MCP 服务默认绑定127.0.0.1,来自外部(包括 Docker)的请求无法到达。

mcp-searxng 示例:

dockerrun--rm-p3456:3000\-eMCP_HTTP_PORT=3000\-eMCP_HTTP_HOST=0.0.0.0\-eSEARXNG_URL=http://192.168.31.184:8080\isokoliuk/mcp-searxng:latest

验证:

netstat-ano|findstr :3456# 应显示 0.0.0.0:3456 或 [::]:3456,而非 127.0.0.1:3456

第二步:配置 SSRF 代理白名单

在 Dify 的.env文件中添加:

SSRF_PROXY_ALLOW_PRIVATE_IPS=192.168.31.184

多个 IP 用逗号分隔:

SSRF_PROXY_ALLOW_PRIVATE_IPS=192.168.31.184,192.168.31.185

第三步:完整重启 Dify(必须)

dockercompose downdockercompose up-d

重要:不能使用docker compose restart ssrf_proxyrestart不会重新读取.env文件的环境变量,白名单配置不会生效。

第四步:验证代理链路

# 测试直连(不走代理)dockerexec-itdocker-api-1curl-vhttp://192.168.31.184:3456/mcp# 测试代理链路(走 ssrf_proxy)dockerexec-itdocker-api-1curl-v--proxyhttp://ssrf_proxy:3128 http://192.168.31.184:3456/mcp

预期结果:两条命令都应返回HTTP/1.1 400 Bad Request+"Invalid or missing session ID"

  • 400是 MCP 服务正常响应(curl 未携带 MCP 协议头)
  • 如果仍返回403 Forbidden+ERR_ACCESS_DENIED,说明环境变量未生效

排障方法论

宿主机 curl → MCP 服务 → 确认服务可用 Dify 容器 curl 直连 → MCP 服务 → 确认网络通 Dify 容器 curl 代理 → MCP 服务 → 确认 SSRF 代理是否拦截
  1. 先确认宿主机自身能访问 MCP 服务
  2. docker exec进入容器测试直连(排除 Docker 网络问题)
  3. --proxy参数测试代理链路(定位 SSRF 拦截)
  4. 查看 Squid 日志:docker logs docker-ssrf_proxy-1

常见错误码速查

响应含义
400 Bad RequestMCP 服务正常(curl 未带 Session ID)
403 ERR_ACCESS_DENIEDSSRF 代理拦截,检查白名单配置
Connection refused端口未监听或防火墙阻断
Could not resolve hostDNS 解析失败,检查 IP 是否正确