Nginx反向代理下的proxy_set_header Host字段有什么用

proxy_set_header 中的host字段的默认值为下 proxy_set_header Host $proxy_host;

假设有如下的location配置:

server {
    listen 80;
    server_name  localhost;
    access_log  /tmp/access_log.log;
    error_log  /tmp/error_log.log;
    location ^~ /pic/ {
        proxy_pass http://img.cherryml.com/;
        proxy_set_header Host $proxy_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header REMOTE-HOST $remote_addr;
    }

那么Host中的$proxy_host就表示proxy_pass中的img.cherryml.com

proxy_set_header Host允许给后端服务器重写Host请求头

通常有两种写法:

proxy_set_header Host $host;

proxy_set_header Host $http_host;

如果请求头中没有设置Host,则$http_host为空,而$hostserver_name,即location,如果server_name也没有指定,则自动从上级别继承,继承顺序为:httpserverlocation


那么说这么多,有什么实际的意义呢?当然有!今天在配置nginx反代的时候出现了问题,来记录一下:

起因

本博客一直缺少一个图床,在综合考虑后选择了七牛云做存储。毕竟每个月有10G的免费流量。为了不掉绿锁(在https协议下发起http请求,浏览器会提示此网站并不完全安全),打算通过nginx把七牛做反代。 于是最初的nginx配置文件是这样的:

server {
    listen 80;
    server_name  localhost;
    access_log  /tmp/access_log.log;
    error_log  /tmp/error_log.log;
    location / {
        proxy_set_header        Host $host;
        proxy_set_header        X-Real-IP $remote_addr;
        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://localhost:1234;
    }

    location ^~ /pic/ {
        proxy_pass http://thirdqq.qlogo.cn/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header REMOTE-HOST $remote_addr;
    }

    location ^~ /qiniu/ {
        proxy_pass http://img.cherryml.com/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header REMOTE-HOST $remote_addr;
    }

重启nginx后发现,同时请求三张图片,路径分别为:

http://img.cherryml.com/1557415617708_2.jpeg

https://cherryml.com/qiniu/1557415617708_2.jpeg

https://cherryml.com/pic/g?b=sdk&k=0MYvEHqBWuYQO7ZrA1ZtAA&s=100

第一张图片直接引用,自然可以正常显示,也自然掉了绿锁。 第二张图片死活显示不出来,看了一眼控制台:服务器返回了403 第三章图片显示正常

一个大写懵逼写在脸上:

图2和图3都是一样的配置,一样做反代,为什么图3可以图2就显示不了!!!

在百度了N久,看了好多千篇一律,你抄我我抄你的csdn、简书依然一无所获。

看来还得靠自己。我开始一段段的注释/qiniu下的nginx配置文件,终于发现了问题:

如果设置proxy_set_header Host $host; 则图二就显示不出来。

如果注释去掉则正常显示了。

原因

说到这里,刚开始的proxy_set_header介绍就能很好的作出解释了:

/qiniu的配置项里面,

proxy_set_header Host $host;

那么对img.cherryml.com来说,请求头里面的Host字段不是它本身的proxy_pass (img.cherryml.com) 而是继承了它上一层的server下的server_name字段,也就是localhost

host是什么

那么又有新问题了:为什么/pic下面反代qq头像就不会有问题呢。

这里有要引出一个概念:http请求头中,Host字段有什么作用?

百度过后做了下总结:

如果一个ip就对应一个域名,那么就会造成极大的浪费。为了解决此问题,就出现了虚拟机和Host的概念。 一个真实机器上可以对应放多个虚拟机,通过host来指定我到底访问的是这个ip下哪台服务器。具体配置文件可以参考windows和mac系统下都有的host文件。

那么就很好解释了,我的域名 img.cherryml.com 是在七牛里面注册绑定的。那么七牛肯定通过host 解析到了我这个域名。 而我在请求图片的时候,Host错误的设置成了localhost而不是img.cherryml.com,那么对于七牛来说,我只能让你在服务器上访问你自己的域名下的东西,七牛自己的localhost当然是做了限制不准我访问的。因此很明显报了403 forbidden。

至于为什么qq头像服务器没有做限制,我想thirdqq.qlogo.cn应该是作为一个通用的api服务器在运行吧。

话已至此,此章已毕,寡人欲休,我们下期再见~