后端生成 URL 总是 http:// 而不是 https://,是因为 Nginx 与后端通信走 HTTP,后端仅感知到内部 http 请求;需在 location 块中配置 proxy_set_header X-Forwarded-Proto $scheme,并在后端显式信任该头且限定可信代理 IP,否则协议信息无法正确传递和识别。

为什么后端生成的 URL 总是 http:// 而不是 https://
因为 Nginx 与后端通信默认走 HTTP(比如 proxy_pass http://127.0.0.1:3000),后端看到的请求协议就是 http,它不知道用户实际用的是 HTTPS。一旦后端拼接跳转地址、API 基础路径或静态资源链接,就会硬编码出 http://example.com/xxx,导致混合内容警告、跳转失败或 Cookie Secure 标志不生效。
proxy_set_header X-Forwarded-Proto $scheme 必须加在 location 块里
这行配置不能写在 server 或 http 块顶层,必须紧贴 proxy_pass 前面,且位于具体 location 内。否则变量 $scheme 可能为空或取值错误。
-
$scheme是 Nginx 内置变量,值为http或https,由当前请求监听的端口决定(listen 443 ssl→https) - 不要写成
proxy_set_header X-Forwarded-Proto https——HTTP 请求也会被标记为 HTTPS,引发重定向循环 - 如果 Nginx 前还有 CDN(如 Cloudflare),要先确认它是否已设
X-Forwarded-Proto;若已设,应改用$http_x_forwarded_proto透传,而非覆盖
后端不信任 X-Forwarded-Proto 就等于白配
只在 Nginx 里加 proxy_set_header 不够,后端框架默认忽略这个头,防止伪造。必须显式开启代理信任,并限定可信来源 IP(通常是 Nginx 所在机器):
- Django:设置
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https'),并确保USE_X_FORWARDED_HOST = True - Flask:用
ProxyFix,例如app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=1),且只信任内网 IP - Spring Boot:设
server.forward-headers-strategy=framework,配合server.tomcat.protocol-header=x-forwarded-proto - Node.js(Express):
app.set('trust proxy', '127.0.0.1'),然后req.protocol才会返回https
验证是否真正生效的三个关键点
别只看 Nginx 配置有没有写,要从请求链路末端反推:
- 在后端加一行日志,打印原始 header:
console.log(req.headers['x-forwarded-proto'])(Node)或request.META.get('HTTP_X_FORWARDED_PROTO')(Django)——HTTPS 访问时必须输出https - 检查后端生成的重定向响应头:
curl -I https://yoursite.com/login,看Location是否为https://...而非http://... - 打开浏览器开发者工具 → Network → 点一个 API 请求 → 查看请求头中
X-Forwarded-Proto是否存在且值正确;再看响应体里的绝对 URL 是否全为 HTTPS
最容易被忽略的是后端信任配置中的 IP 范围——填 0.0.0.0/0 有安全风险,漏掉 IPv6 地址(如 ::1)会导致部分请求协议识别失败。











