反向代理是自建服务里最容易「配得看起来能跑、实际埋着雷」的一环。Nginx 官方文档里关于 proxy_set_header 的说明,加上几个高频踩坑点,值得逐条抄下来。
一、四个标准头:一个都别少
官方反代示例里给出的基础配置,是这一领域的「最小正确集」:
location / {
proxy_pass http://backend;
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;
}
每一行都在解决一个具体问题:
Host $host:保留客户端请求的原始域名。少了它,后端只能看到proxy_pass里的内网主机名,多域名共用一套后端时直接错乱,也是「登录后跳回内网地址」的经典元凶;X-Real-IP:把真实客户端 IP 传给后端。否则后端日志里全是 Nginx 的地址;X-Forwarded-For:注意这里用的是$proxy_add_x_forwarded_for而不是$remote_addr——前者会把已有链路追加在逗号分隔列表后面,保留多级代理的完整路径;X-Forwarded-Proto:告诉后端「用户那一侧其实是 HTTPS」。少了它,后端生成的重定向会把自己降级回 http,浏览器直接报混合内容。
二、WebSocket 要多两行
默认的 HTTP/1.0 不具备升级连接的能力,反代 WebSocket 必须显式抬高协议版本并透传升级头:
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
典型的症状是:页面能打开,但实时日志、终端、状态推送全部卡住不动——那就是漏了这两行。
三、最容易吃亏的一条:proxy_set_header 不跨层合并
与
add_header不同,proxy_set_header不会从上层继承后合并:只要在更内层的location里写了任意一条proxy_set_header,server层配置的那一整组就会被整体覆盖。
这条反直觉到官方要专门写一段提示。后果是:你在 server 里精心写的四个头,被某个子路径 location 里随手加的一行 proxy_set_header 全部抹掉,而且只有那个子路径出问题,极难排查。
对策只有一条:凡是写了 proxy_set_header 的 location,就把需要的那组头原样补齐,别指望继承。
四、proxy_pass 末尾那个斜杠
少一个斜杠、多一个斜杠,转发结果完全不同:
proxy_pass http://backend;→ 原始 URI 原样拼接;proxy_pass http://backend/;→ 用斜杠后面的部分替换掉 location 匹配到的那段前缀。
子路径挂载(把服务放在 /app/ 下却要它以为自己在根目录)时,这个斜杠就是唯一开关。
五、出处
- Nginx Documentation — NGINX Reverse Proxy
https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/ - Nginx Documentation — ngx_http_proxy_module / proxy_set_header
https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_set_header
六、在自家服务器上的印证
本站前面挂的正是 Nginx Proxy Manager(底层就是 Nginx),上面这些规则天天在生效:
- 十来个域名共用同一台 Nginx,全靠
Host头区分后端——少这一行,所有站点会一起指向第一个后端; - 日志面板和监控面板都是 WebSocket 重依赖,反代里必须开
Upgrade;这两个服务当初「页面能开、数据不动」,根因就在这里; - 博客后台与网盘的登录跳转依赖
X-Forwarded-Proto,否则会从 https 掉回 http 再被浏览器拦下; - 证书统一由 NPM 申请与续签(现在这批有效期到 2026 年 12 月),所以「协议头正确」不只是观感问题,而是能不能正常登录的问题。
评论