记一次 Nginx + frp 多域名转发“串路”故障排查

-
-
2026-05-13 20:47

1. 网络架构现状

  • 物理层:家庭物理机(Docker 部署服务) <-> frpc 客户端

  • 隧道层:frp (HTTP 模式) 映射到云服务器 10800 端口

  • 接入层:云服务器 Nginx 反向代理(多域名 -> 127.0.0.1:10800)

2. 故障现象

  • 域名混淆:访问域名 A,显示的却是已停止运行的容器 B 的前端界面。

  • 状态顽固:重启物理机、云服务器、清空浏览器无痕缓存后,现象依然存在。

  • 协议敏感:HTTPS 访问报错或行为异常,HTTP 访问在特定条件下恢复正常。

3. 核心诱因分析

A. Nginx 代理缓冲与缓存(主要诱因)

这是本次故障的“罪魁祸首”。

  • proxy_buffering(响应缓冲):Nginx 默认开启缓冲。当后端(frp)返回数据时,Nginx 会将其存入内存缓冲区。如果多个域名共享一个后端 IP:Port,在高频刷新或后端异常时,缓冲区内的残余数据可能被错误的关联到下一个请求。

  • proxy_cache(硬盘缓存):如果 Nginx 或宝塔面板默认开启了缓存,由于 proxy_cache_key 设置不当(未包含 $host),Nginx 会认为所有域名的根路径 / 都是同一个页面,导致“张冠李戴”。

B. frp HTTP 模式的 Host 依赖

在 HTTP 模式下,frps 依赖请求头中的 Host 字段来分发流量。

  • 如果 Nginx 配置中缺失 proxy_set_header Host $host;,frps 接收到的 Host 将是 127.0.0.1

  • 此时 frps 会根据内部逻辑随机或按顺序指向第一个可用的代理,导致所有域名访问的都是同一个后端。

C. HTTPS 握手与默认站点

  • 当使用 HTTPS 访问但未配置 SSL 证书时,Nginx 会尝试使用“默认站点”的证书或直接将请求回退给第一个监听 443 的 server 块。

  • 如果该默认块恰好配置了有问题的反代,就会触发上述的缓存逻辑。

4. 解决方案(加固配置)

为了彻底根治该问题,必须在 Nginx 层关闭“记忆”功能,确保其作为“透明管道”运行。

关键配置代码:

在每一个受影响的域名反代配置中,加入以下指令:

location / {
    proxy_pass http://127.0.0.1:10800;
    
    # 1. 禁用缓存与缓冲,确保实时性与隔离性
    proxy_buffering off;
    proxy_cache off;
    proxy_request_buffering off;

    # 2. 显式传递 Host 头,供 frp 正确分发流量
    proxy_set_header Host $host;
    
    # 3. 开启 WebSocket 支持(现代 Web 应用必备)
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";

    # 4. 强制浏览器禁用本地缓存
    add_header Cache-Control "no-store, no-cache, must-revalidate, max-age=0";
}
Nginx
location / {
    proxy_pass http://127.0.0.1:10800;
    
    # 1. 禁用缓存与缓冲,确保实时性与隔离性
    proxy_buffering off;
    proxy_cache off;
    proxy_request_buffering off;

    # 2. 显式传递 Host 头,供 frp 正确分发流量
    proxy_set_header Host $host;
    
    # 3. 开启 WebSocket 支持(现代 Web 应用必备)
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";

    # 4. 强制浏览器禁用本地缓存
    add_header Cache-Control "no-store, no-cache, must-revalidate, max-age=0";
}

5. 运维经验总结

  1. 物理清理:遇到玄学串路,第一时间清理 Nginx 缓存目录:rm -rf /www/server/nginx/proxy_cache_dir/*

  2. 验证工具:不要只依赖浏览器,使用 curl -v -H "Host: domain.com" 127.0.0.1:10800 在服务器本地验证 frp 分发是否正常。