nginx 为实现反向代理的需求增加了一个 ngx_http_proxy_module 模块。其中 proxy_set_header 指令就是该模块需要读取的配置。
HTTP header 中的 Host 含义为所请求的目的主机名。当 nginx 作为反向代理使用,而后端真实 web 服务器设置有类似 防盗链功能 ,或者根据 HTTP header 中的 Host 字段来进行 路由 或 过滤 功能的话,若作为反向代理的 nginx 不重写请求头中的 Host 字段,将会导致请求失败。
HTTP header 中的 X_Forward_For 表示该条 http 请求是由谁发起的。如果反向代理服务器不重写该请求头的话,那么后端真实 web 服务器在处理时会认为所有的请求都来自反向代理服务器。如果后端 web 服务器有防攻击策略的话,那么反向代理服务器对应的 ip 地址就会被封掉。因此,在配置用作反向代理的 nginx 时,一般会增加以下两条配置修改 http 的请求头:
1
2
|
proxy_set_header Host $http_host;
proxy_set_header X-Forward-For $remote_addr;
|
1
|
proxy_set_header Host $host;
|
即在最前端的 Nginx 上设置:
1
2
3
4
|
location ~ ^
/static
{
proxy_pass ....;
proxy_set_header X-Forward-For $remote_addr ;
}
|
当 nginx 作为反向代理服务器时,X-Forward-For 可以用于把发送者 ip 、代理机器 ip 都记录下来(用逗号分隔)。
经过反向代理后,由于在客户端和 web 服务器之间增加了中间层,因此 web 服务器无法直接拿到客户端的 ip,在 web 服务器上通过 $remote_addr 变量拿到的将是反向代理服务器的 ip 地址当你使用了 nginx 反向代理后,在 web 端使用类似 request.getRemoteAddr() 的 API(本质上就是获取 $remote_addr),取得的实际上是 nginx 的地址,即 $remote_addr 变量中封装的是 nginx 的地址,当然是没法获得用户的真实 ip 的,然而 nginx 本身是可以获得用户的真实 ip 的,也就是说 nginx 使用 $remote_addr 变量可以获得用户的真实 ip ,如果我们想要在 web 端获得用户的真实 ip ,就必须在 nginx 这里作一个赋值操作,如下:
1
|
proxy_set_header X-real-ip $remote_addr;
|
1
|
request.getAttribute(
"X-real-ip"
)
|
X-real-ip 的用途是为了后端 web 服务器可以获取用户的真实 ip , 那么还要 X-Forwarded-For 干啥?
追溯历史,这个 X-Forwarded-For 变量,是 squid 开发的,用于识别请求通过了哪些 HTTP 代理或负载平衡器,记录相应 IP 地址列表的非 rfc 标准,如果设置了 X-Forwarded-For ,那么每次经过 proxy 转发请求后都会有记录,格式就是
1
|
client1, proxy1, proxy2, ...
|
1
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
实际上,当你通过搭建不同 ip 的两台 nginx 构成多级代理时,并且都使用了这段配置,那你会发现在 web 服务器端通过类似 request.getAttribute("X-Forwarded-For") 的 API 获得的将会是客户端 ip 和第一台 nginx 的 ip 。
试验:【以 http 方式通过 nginx 访问 cowboy】
浏览器侧抓包
cowboy 上抓包