【声明】本博客所有内容均为个人业余时间创作,所述技术案例均来自公开开源项目(如Github,Apache基金会),不涉及任何企业机密或未公开技术,如有侵权请联系删除
背景
上篇 blog
【Ubuntu】【Gitlab】拉出内网 Web 服务:Gitlab 配置审视(八)
分析了安全的 default_server 配置,然后继续分析了 server 块中的 location 配置项,下面继续
Nginx 配置审视
上篇 blog 分析到了配置项 proxy_set_header Host $host; 的作用是把原始请求的 Host 头传递给后端服务,很多 Web 框架会检查 Host 头来生成绝对 URL(重定向场景)

下面就这个重定向场景再详细展开分析下,比如用户登录后的重定向,假设系统架构如下

- 用户在浏览器输入
http://192.168.1.100/login - Nginx 监听
80端口,并反向代理到http://localhost:8080 - 后端是个 Web 应用
登录时,用户提交用户名和密码,后端验证成功后,想把用户重定向到首页 /dashboard,那么问题来了,后端该怎么写这个重定向响应?按照有没有 Host 头划分,有两种情况:
- 第一种,没 Host 头 :此时后端不知道用户是通过
192.168.1.100访问的,它可能以为自己直接暴露在localhost:8080(也就是以为用户直接访问的localhost:8080),于是返回
bash
HTTP/1.1 302 Found
Location: http://localhost:8080/dashboard
然后浏览器跳转到 http://localhost:8080/dashboard,对于私人使用的端口映射远程服务器,这样当然没问题,但是如果是要提供给更多人使用的公用服务器,这么做就有问题了,此时用户会看到无法访问此网站,因为 localhost 是回环地址**,公用场景下,客户端一般不会把自己端口映射出去**,这时用户访问 http://localhost:8080/dashboard,就相当于访问自己的回环地址,那样当然就没有服务了
- 第二种,有 Host 头 :当 Nginx 设置了
proxy_set_header Host $host;,此时后端收到的请求头包含Host: 192.168.1.100,于是后端知道,用户是通过192.168.1.100访问的,所以生成重定向
bash
HTTP/1.1 302 Found
Location: http://192.168.1.100/dashboard
此时浏览器就能正确跳转到 http://192.168.1.100/dashboard
OK,分析完 proxy_set_header Host $host;,继续看下一个
proxy_set_header X-Real-IP $remote_addr;:表示将真实客户端 IP 传递给后端,$remote_addr是 Nginx 变量,表示直接连接 Nginx 的客户端 IP (注意和$host区别,$host表示服务端的域名,remote_addr表示客户端的 IP),此时后端通过X-Real-IP头就能知道真实用户 IP,否则后端看到的来源 IP 永远是127.0.0.1(本机地址),因为是 Nginx 本地应用在访问后端proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;:用于记录请求经过的代理链 ,如果客户端没发X-Forwarded-For,那么$proxy_add_x_forwarded_for就设为$remote_addr,表示客户端 IP;如果客户端已经发了(比如X-Forwarded-For: A, B),就追加当前 IP 上去,最后X-Forwarded-For可能呈现为
bash
X-Forwarded-For: client-ip, proxy1-ip, proxy2-ip
后端可以通过这个 X-Forwarded-For 追踪原始用户 IP(尤其在多层代理时)
proxy_set_header X-Forwarded-Proto $scheme:让后端知道原始请求用的是什么协议(比如 HTTP 还是 HTTPS),这里$scheme是 Nginx 变量,值为http或https,比如有这么一个场景,用户通过 HTTPS 访问 Nginx(比如https://example.com),但 Nginx 和后端之间走的是 HTTP 协议,此时后端不知道原始请求是 HTTPS,就可能生成http://...的链接,会导致混合内容高级或登录失败,通过$scheme的传递,可以让用户知道原始请求的协议,进而生成正确的安全链接
最后总结一下,location 字段定义如下功能
- 请求转发 :proxy_pass 到
localhost:8080 - 保留原始域名 :
Host $host - 传递真实 IP :
X-Real-IP+X-Forwarded-For - 传递原始协议 :
X-Forwarded-Proto $scheme
这套反向代理配置适用于大多数 Web 应用
OK,本篇先到这里,如有疑问,欢迎评论区留言讨论,祝各位功力大涨,技术更上一层楼!!!更多内容见下篇 blog