nginx反向代理相关

最近在使用nginx反向代理的时候,因为是多层反向代理,遇到一些关于获取真实IP的问题,于是研究了一下反向代理的header设置,记录如下。
参考1:http://tengine.taobao.org/nginx_docs/cn/docs/http/ngx_http_proxy_module.html
参考2:https://blog.csdn.net/broadview2006/article/details/54570943

环境说明

mahua

  • 分别有三台服务器:Nginx Proxy1、Nginx Proxy2、Nginx Backend,都安装了nginx服务
  • 三台服务器都有内外网,Proxy1反向代理到Proxy2,Proxy2反向代理到Backend,Backend返回测试数据
  • 我们会模拟client对三台服务器发出请求

nginx变量:remote_addr

我们先来了解一下nginx中的remote_addr变量

Proxy1 nginx配置如下

1
2
3
location /test {
proxy_pass http://192.168.0.201:80;
}

Proxy2 nginx配置如下

1
2
3
location /test {
proxy_pass http://192.168.0.202:80;
}

Backend nginx配置如下

1
2
3
4
location /test {
default_type text/html;
return 200 "remote_addr:$remote_addr";
}

从Client服务器上请求如下地址,观察返回结果

http://50.50.50.200/test

  • remote_addr:192.168.0.201

http://192.168.0.200/test

  • remote_addr:192.168.0.201

http://50.50.50.201/test

  • remote_addr:192.168.0.201

http://192.168.0.201/test

  • remote_addr:192.168.0.201

http://50.50.50.202/test

  • remote_addr:50.50.50.210

http://192.168.0.202/test

  • remote_addr:192.168.0.210

从上面的请求结果可以看出

  1. remote_addr表示请求本服务器的上一层服务器或client的ip,比如用户请求过来那就是用户的ip,代理服务器方向代理过来,那就是反向代理服务器的ip
  2. 如果请求本服务器的内网,那就是取上一层服务器或client的内网ip
  3. 如果请求本服务器的外网,那就是取上一层服务器或client的外网ip

nginx反向代理:request header自动转发

Proxy1 nginx配置如下

1
2
3
4
location /test {
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://192.168.0.201:80;
}

Proxy2 nginx配置如下

1
2
3
location /test {
proxy_pass http://192.168.0.202:80;
}

Backend nginx配置如下

1
2
3
4
location /test {
default_type text/html;
return 200 "remote_addr:$remote_addr || http_x_real_ip:$http_x_real_ip";
}

从Client服务器上请求如下地址,观察返回结果

http://50.50.50.200/test

  • remote_addr:192.168.0.201 || http_x_real_ip:50.50.50.210

从上面的请求结果可以看出

  1. 我们只在第一层proxy服务器Proxy1上反向代理中设置了header “X-Real-IP”(设置为$remote_addr)
  2. 在第二层proxy服务器Proxy2上,我们并没有设置header “X-Real-IP”
  3. 但是在backend中,我们却返回了正确的header值 $http_x_real_ip
  4. 说明request header在反向代理服务器中是自动转发到后面服务器的,参考如下官方说明:
  5. http://tengine.taobao.org/nginx_docs/cn/docs/http/ngx_http_proxy_module.html#proxy_set_header

nginx反向代理:Host header

默认情况下,反向代理中Host header会被重新设置,默认如下:

1
proxy_set_header Host $proxy_host;

即都重新设置成proxy请求的Host,我们可以实验一下

Proxy1 nginx配置如下

1
2
3
4
location /test {
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://192.168.0.201:80;
}

Proxy2 nginx配置如下

1
2
3
location /test {
proxy_pass http://192.168.0.202:80;
}

Backend nginx配置如下

1
2
3
4
location /test {
default_type text/html;
return 200 "host:$host || remote_addr:$remote_addr || http_x_real_ip:$http_x_real_ip";
}

从Client服务器上请求如下地址,观察返回结果

http://50.50.50.200/test

  • host:192.168.0.202 || remote_addr:192.168.0.201 || http_x_real_ip:50.50.50.210

http://192.168.0.200/test

  • host:192.168.0.202 || remote_addr:192.168.0.201 || http_x_real_ip:192.168.0.210

http://50.50.50.201/test

  • host:192.168.0.202 || remote_addr:192.168.0.201 || http_x_real_ip:

http://192.168.0.201/test

  • host:192.168.0.202 || remote_addr:192.168.0.201 || http_x_real_ip:

http://50.50.50.202/test

  • host:50.50.50.202 || remote_addr:50.50.50.210 || http_x_real_ip:

http://192.168.0.202/test

  • host:192.168.0.202 || remote_addr:192.168.0.210 || http_x_real_ip:

从上面的请求结果可以看出

  1. Proxy1发送给Proxy2的Host header为”192.168.0.201”,Proxy2发送给Backend的Host header为”192.168.0.202”
  2. 即host header默认会被设置成proxy请求的host

如果想在backend服务器中收到原始用户发送过来的Host header,那么做如下配置即可

Proxy1 nginx配置如下

1
2
3
4
5
location /test {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://192.168.0.201:80;
}

Proxy2 nginx配置如下

1
2
3
4
location /test {
proxy_set_header Host $host;
proxy_pass http://192.168.0.202:80;
}

Backend nginx配置如下

1
2
3
4
location /test {
default_type text/html;
return 200 "host:$host || remote_addr:$remote_addr || http_x_real_ip:$http_x_real_ip";
}

从Client服务器上请求如下地址,观察返回结果

http://50.50.50.200/test

  • host:50.50.50.200 || remote_addr:192.168.0.201 || http_x_real_ip:50.50.50.210

http://192.168.0.200/test

  • host:192.168.0.200 || remote_addr:192.168.0.201 || http_x_real_ip:192.168.0.210

http://50.50.50.201/test

  • host:50.50.50.201 || remote_addr:192.168.0.201 || http_x_real_ip:

http://192.168.0.201/test

  • host:192.168.0.201 || remote_addr:192.168.0.201 || http_x_real_ip:

http://50.50.50.202/test

  • host:50.50.50.202 || remote_addr:50.50.50.210 || http_x_real_ip:

http://192.168.0.202/test

  • host:192.168.0.202 || remote_addr:192.168.0.210 || http_x_real_ip:

从上面的请求结果可以看出

  1. 在backend服务器中收到了原始用户发送过来的Host header

nginx反向代理:X-Real-IP 和 X-Forwarded-For

前面我们其实已经试验过,通过设置X-Real-IP来获取用户真实的ip

下面我们通过设置X-Forwarded-For来获取ip

  • proxy_add_x_forwarded_for变量解释:
  • proxy_add_x_forwarded_for将remote_addr变量值添加在客户端“X-Forwarded-For”请求头的后面,并以逗号分隔。 如果客户端请求未携带“X-Forwarded-For”请求头,proxy_add_x_forwarded_for变量值将与remote_addr变量相同。
  • 简单点说,就是:proxy_add_x_forwarded_for = http_x_forwarded_for + remote_addr

Proxy1 nginx配置如下

1
2
3
4
5
6
location /test {
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://192.168.0.201:80;
}

Proxy2 nginx配置如下

1
2
3
4
5
location /test {
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://192.168.0.202:80;
}

Backend nginx配置如下

1
2
3
4
location /test {
default_type text/html;
return 200 "host:$host || remote_addr:$remote_addr || http_x_real_ip:$http_x_real_ip || http_x_forwarded_for:$http_x_forwarded_for";
}

从Client服务器上请求如下地址,观察返回结果

http://50.50.50.200/test

  • host:50.50.50.210 || remote_addr:192.168.0.201 || http_x_real_ip:50.50.50.210 || http_x_forwarded_for:50.50.50.210, 192.168.0.200

http://192.168.0.200/test

  • host:192.168.0.200 || remote_addr:192.168.0.201 || http_x_real_ip:192.168.0.210 || http_x_forwarded_for:192.168.0.210, 192.168.0.200
坚持原创技术分享,您的支持将鼓励我继续创作!