核心是用proxy_redirect将后端返回的内网location头(如http://192.168.1.5:8080/login)重写为公网地址(如https://example.com/login),需配合proxy_pass、proxy_set_header传递x-forwarded-proto和host等头,并通过curl -i验证生效。

核心是让 Nginx 把后端返回的 Location 响应头从内网地址(比如 http://192.168.1.5:8080/login)替换成用户能访问的公网地址(比如 https://example.com/login),而不是靠后端自己改——它通常不知道外面是什么环境。
用 proxy_redirect 重写 Location 头
这是最直接有效的手段。Nginx 不会自动改,必须明确告诉它怎么替换:
- 如果后端固定返回
http://10.0.2.5:8080/,而你想映射到当前请求的协议和域名,写:proxy_redirect http://10.0.2.5:8080/ $scheme://$host/; - 想统一处理所有以
http://或https://开头的内网地址,用正则:proxy_redirect ~^https?://[^/]+(/.*)$ $scheme://$host$1; - 如果是子路径代理(比如
location /admin/),后端返回/login,但用户实际该跳到/admin/login,就写:proxy_redirect / /admin/; - 规则必须和
proxy_pass同级、且写在它之后,只对 301/302/307/308 生效。
透传关键请求头,让后端生成正确跳转
只改响应头是治标;让后端以后也返回公网地址,才是治本:
- 加这行,告诉后端用户用的是 HTTP 还是 HTTPS:
proxy_set_header X-Forwarded-Proto $scheme; - 让后端知道真实访问域名,避免它拼出
localhost或内网 IP:proxy_set_header Host $host;(注意别用$http_host,可能带端口) - 传递真实客户端 IP:
proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - 后端框架要启用对应解析:Spring Boot 配
server.forward-headers-strategy=framework,Django 配SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https'),并确保信任 Nginx 的 IP 段。
验证是否生效
别只看配置,要抓真实响应头:
- 用
curl -I https://your-domain.com/some-path查看返回的Location:是否已是公网地址、协议正确、不含私网 IP - 修改后执行
nginx -s reload重载配置 - 开启 error_log debug 级别,日志里会记录
proxy_redirect是否命中规则
常见踩坑点
这些细节容易忽略,却常导致重定向失败:
-
proxy_redirect的匹配前缀必须严格一致,http://10.0.2.5:8080和http://10.0.2.5:8080/是两个不同字符串 - 没传
X-Forwarded-Proto,后端坚持返回http://地址,和 HTTPS 入口冲突,可能引发跳转死循环 -
proxy_pass末尾斜杠影响 URI 重写逻辑,比如proxy_pass http://backend;和proxy_pass http://backend/;行为不同,需配合proxy_redirect调整 - 内部服务部署在容器或 Kubernetes 中时,检查其监听地址是否设为
0.0.0.0,而非仅127.0.0.1,否则可能收不到 Nginx 透传的头











