必须配三行:proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 否则后端收不到真实Host和客户端IP,易报400或日志全为127.0.0.1。

proxy_set_header 必须配哪几行
只写 proxy_pass 而不配 proxy_set_header,后端大概率收不到真实 Host 和客户端 IP,直接报 400 Bad Request 或日志里全是 127.0.0.1。
以下三行是底线配置,必须放在 location 块内、proxy_pass 之前:
-
proxy_set_header Host $host;—— 用$host而不是硬编码值,避免子域名或端口丢失;更严谨可选$http_host(保留原始端口) -
proxy_set_header X-Real-IP $remote_addr;—— 直接传递最外层可信客户端 IP -
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;—— 不要用$remote_addr替代,否则多级代理(如 CDN → Nginx)时链路会断
HTTPS 和协议识别必须加 X-Forwarded-Proto
如果 Nginx 终止 HTTPS(即用户访问 https://,但转发给后端的是 http://),后端默认认为是 HTTP 请求,会导致重定向跳 http://、Secure Cookie 不生效、HSTS 失效等问题。
必须加这一行:
安装并运行 Aperture(Lightning Labs 的 L402 闪电反向代理),用于创建 L402 付费墙、配置付费 API 端点、为其他代理托管付费内容或测试 L402 认证流程。
-
proxy_set_header X-Forwarded-Proto $scheme;——$scheme动态取值,HTTP 时为http,HTTPS 时为https - 这行必须写在
proxy_pass之前,否则不生效 - 后端框架也得配合:Django 要设
SECURE_PROXY_SSL_HEADER,Flask 用ProxyFix,Spring Boot 配forward-headers-strategy=framework
WebSocket 连接失败?Upgrade 和 Connection 头不能少
Nginx 默认会丢掉 WebSocket 握手必需的两个头,导致连接建立后频繁断开或根本连不上。
只要后端用 WebSocket(比如 Socket.IO、SSE、实时协作服务),就必须加这两行:
-
proxy_set_header Upgrade $http_upgrade;—— 把客户端发来的Upgrade: websocket原样透传 -
proxy_set_header Connection "upgrade";—— 注意引号,固定值必须加双引号,否则 Nginx 会当成变量解析失败 - 这两行要和前面的
Host、X-Forwarded-*放在同一location块里,顺序无关紧要
容易被忽略的细节:重复设置、变量误用、位置错乱
proxy_set_header 看似简单,但实际部署中最常出问题的不是漏写,而是写错位置或用错变量。
- 不要在
http或server块里全局写proxy_set_header Host example.com;—— 这会让所有子域名、路径都变成同一个 Host,路由全崩 - 不要在多个嵌套块里重复写同一 header(比如
server和location都设Host)—— Nginx 只认最内层(location)的值,外层会被覆盖 -
proxy_set_header必须在proxy_pass之前,写在后面等于没写 - 别用
$http_x_forwarded_for替代$proxy_add_x_forwarded_for—— 前者可能被客户端伪造,后者会在可信链路上追加真实 IP,更安全
真正麻烦的从来不是加几行配置,而是某一行变量写错、位置放反、或者后端没同步适配,结果问题藏在整条链路里,查半天才发现是 $scheme 漏了下划线,或是 Connection 少了引号。

















