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_networksto_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 | 入口脚本,读取环境变量动态生成白名单 |
.env | Dify 环境变量配置文件 |
入口脚本白名单机制
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_proxy。restart不会重新读取.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 代理是否拦截- 先确认宿主机自身能访问 MCP 服务
- 用
docker exec进入容器测试直连(排除 Docker 网络问题) - 用
--proxy参数测试代理链路(定位 SSRF 拦截) - 查看 Squid 日志:
docker logs docker-ssrf_proxy-1
常见错误码速查
| 响应 | 含义 |
|---|---|
400 Bad Request | MCP 服务正常(curl 未带 Session ID) |
403 ERR_ACCESS_DENIED | SSRF 代理拦截,检查白名单配置 |
Connection refused | 端口未监听或防火墙阻断 |
Could not resolve host | DNS 解析失败,检查 IP 是否正确 |
