一、为什么反向代理最容易踩这两个坑

原笔记把两个高频问题单独拎了出来:

  • 后端 Web 有多个虚拟主机时,代理后访问到的不是预期站点
  • Web 访问日志里记录到的是代理服务器 IP,而不是用户真实 IP

这两个问题看起来不同,但本质都和“代理转发请求时请求头被改变了什么”有关。

二、故障一:多个虚拟主机时为什么会访问错站点

原笔记描述的现象是:

  • Web 服务器上配置了多个虚拟主机
  • 经过代理访问后,却没有进入想要的站点

问题根源在于:

  • 代理转发给后端时,请求头里的 Host 可能被改成了 IP 形式
  • 这相当于后端 Web 接收到的是“按 IP 访问”
  • Nginx 会因此落到默认虚拟主机,或者命中错误的 server {}

也就是说,真正丢失的不是页面,而是“域名上下文”。

三、怎么修复 Host 头问题

原笔记给出的修复方向非常明确:
代理转发给后端时,要主动把 Host 头改回用户原始访问的域名。

常见写法有两种:

proxy_set_header Host $http_host;

或者直接写死:

proxy_set_header Host "proxy.oldboylinux.cn";

原笔记更推荐使用变量:

proxy_set_header Host $http_host;

原因是 $http_host 会取出客户端请求头里的 Host 内容,通常就是用户真正访问的域名。

这条配置的实际意义就是:
让代理到 Web 的这次请求,在后端看来仍然像一次“按域名访问”的正常请求。

四、故障二:为什么 Web 日志里看到的是代理 IP

第二个问题更常见。
用户先访问代理服务器,再由代理访问后端 Web,所以如果不做额外处理,后端只能看到“直接和自己通信的上游”,也就是代理服务器。

于是日志里记录到的就会是:

  • 代理服务器的地址
  • 而不是用户浏览器的真实来源地址

这会直接影响:

  • 日志分析
  • 用户来源统计
  • 安全审计
  • 后续访问控制

五、怎么把真实客户端 IP 传给后端

原笔记给出的解决方法是在代理配置里增加:

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

示例配置如下:

server {
  listen 80;
  server_name proxy.oldboylinux.cn;

  error_log /var/log/nginx/proxy-error.log notice;
  access_log /var/log/nginx/proxy-access.log main;

  location / {
    proxy_pass http://192.168.1.20:80;
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}

这里的关键点是:

  • X-Forwarded-For 是代理链路里记录客户端真实来源地址的常见头部
  • $proxy_add_x_forwarded_for 会把当前客户端地址追加进去

这样后端 Web 在日志或应用层就有机会读取到真正的用户来源 IP。

六、如何验证真实 IP 透传是否成功

原笔记的验证步骤很直接:

1、修改代理配置
2、执行 nginx -t
3、systemctl restart nginx
4、在 Web 服务器上查看访问日志
5、再通过浏览器访问代理域名

示例:

tail -f /var/log/nginx/proxy-access.log

然后访问:

http://proxy.oldboylinux.cn/

如果日志中出现的是客户端真实 IP,而不是代理 IP,说明透传已经生效。

七、生产中更推荐的反向代理头部写法

原笔记最后总结了一组更完整的生产建议配置:

proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

三者的分工可以这样理解:

  • Host:保留原始访问域名,保证后端虚拟主机匹配正确
  • X-Real-IP:直接记录当前客户端 IP
  • X-Forwarded-For:在多层代理场景中保留完整来源链

对于大多数反向代理站点,这三行基本都很常见。

八、小结

反向代理里最容易忽视的,不是 proxy_pass 本身,而是“请求头该怎么传”。
原笔记这两个故障案例其实说明了同一个道理:

  • 不传对 Host,虚拟主机就可能匹配错
  • 不传对来源 IP,日志和业务层就看不到真实用户

把这两类头部处理好,Nginx 反向代理配置才算真正完整。