前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >nginx反向代理中的相关IP

nginx反向代理中的相关IP

作者头像
qsjs
发布2020-06-09 10:41:00
9050
发布2020-06-09 10:41:00
举报

场景一: 没有使用反向代理 配置nginx.conf,添加/修改 log 相关配置如下:

代码语言:javascript
复制
http {
......
    log_format  main  'Parameter remote_addr : $remote_addr\n'
                      'Parameter http_x_forwarded_for: $http_x_forwarded_for\n'
                      'Parameter http_x_real_ip : $http_x_real_ip';
    access_log  /var/log/nginx/access.log  main;
......
}

启动nginx服务,并通过浏览器访问,查看访问日志结果如下: 其中http_x_forwarded_for 的值是“空”,因为server端没有reverse proxy,所以该变量就不存在,该变量仅仅在proxy中才有效. 而http_x_real_ip的值同样为"空“, 也和http_x_forwarded_for是一样的原因,但是remote_addr的值就是client端的IP,remote_addr的值不能进行修改,由系统控制,直接访问就可以引用,如果启用的是nginx容器,那么结果也是一样,对于没有配置反向代理的情况,基于host的Nginx和基于container的nginx,对于上述的验证结果是一致的

代码语言:javascript
复制
[root@instance-6p8qz002 log]# tail -n0 -f access.log
Parameter remote_addr : 119.123.134.165
Parameter http_x_forwarded_for: -
Parameter http_x_real_ip : -

.

场景二:只有一个reverse proxy 在此测试场景中,使用docker 启动一个nginx 容器作为 service provider(映射host主机的8080端口到容器的80端口). 而在host主机上运行的nginx配置反向代理功能,同时在host上创建一个虚拟IP:192.168.0.110,这样在配置反向代理的时候就可以使用 192.168.0.110 来代替localhost 具体步骤如下:

  1. 在server上,创建一个虚拟IP:192.168.0.110/24 .
代码语言:javascript
复制
[root@instance-6p8qz002 ~]# ifconfig eth0:0 192.168.0.110  netmask 255.255.255.0 up
[root@instance-6p8qz002 ~]# ping -c 2 192.168.0.110
PING 192.168.0.110 (192.168.0.110) 56(84) bytes of data.
64 bytes from 192.168.0.110: icmp_seq=1 ttl=64 time=0.048 ms
64 bytes from 192.168.0.110: icmp_seq=2 ttl=64 time=0.066 ms

--- 192.168.0.110 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.048/0.057/0.066/0.009 ms
[root@instance-6p8qz002 ~]#
  1. 配置host主机上的Nginx,开启反向代理功能, 修改/etc/nginx.conf 文件,内容如下:
代码语言:javascript
复制
......
      location / {
      proxy_pass                          http://192.168.0.110:8080/;
      proxy_set_header  X-Real-IP         $remote_addr;
      proxy_set_header  X-Forwarded-For   $proxy_add_x_forwarded_for;
        }
......
#启动host上的nginx服务
[root@instance-6p8qz002 ~]# systemctl start nginx.service
[root@instance-6p8qz002 ~]#
  1. 对于nginx容器,不需要反向代理的配置,但是要保持log 记录的相关配置,和上面 ”场景一“ 的配置一致:
代码语言:javascript
复制
http {
......
    log_format  main  'Parameter remote_addr : $remote_addr\n'
                      'Parameter http_x_forwarded_for: $http_x_forwarded_for\n'
                      'Parameter http_x_real_ip : $http_x_real_ip';
    access_log  /var/log/nginx/access.log  main;
......
}
#启动nginx 容器
[root@instance-6p8qz002 my_project]# docker run -d --rm   -p 8080:8080  -v /root/my_project/nginx/:/etc/nginx -v /tmp/nginx/log:/var/log/nginx/   --name my_nginx  nginx
56a543b71e7c157d9dc736f8c1d3481d31e21db03575d51eadd6ebe980de282d
[root@instance-6p8qz002 my_project]# 
  1. 通过浏览器访问,查看log记录,内容如下:
代码语言:javascript
复制
[root@instance-6p8qz002 log]# tail -n0 -f access.log
Parameter remote_addr: 192.168.0.110
Parameter http_x_forwarded_for: 119.123.134.165
Parameter http_x_real_ip: 119.123.134.165

根据我们前面的理解,remote_addr的值应该是:client的public IP才对,也就是119.123.134.165, 因为我们这里只有这一个reverse proxy. 那为什么实际是 : 192.168.0.110 呢? 因为在docker map host端口到container的端口的时候,其实是一个http请求的转发,所以host_ip:port ---- container: port 之间的关系,就相当于client--server 的直连关系。 http_x_forwarded_for,http_x_real_ip 的值和前面的理论值是一致的,这里不做过多解释; .

场景三:多个reverse proxy的讨论 这里采用三个reverse proxy来作代表多个proxy的情况,其部署环境如下:

  1. 在本地的centos(192.168.0.110) 中安装Nginx,并配置反向代理功能,转发http请求到远端的服务器 remote_host 的8080端口. 对应后面的配置步骤A.
  2. 在远端的服务器remote_host上安装Nginx, 并配置反向代理功能,从8080端口接收请求并转发到该host的Nginx 容器A的8080端口; 在下面的配置中,从8080端口接收到请求后,转发到该host的8088端口,而并不是直接转发到Nginx容器A的8080端口,这是因为:host的8088端口mapping 到了容器A的8080端口, 对应的配置为后面的步骤B.
  3. 在服务器remote_host的容器A(Nginx容器: 172.26.16.8) 上配置反向代理功能,转发请求到另一个Nginx容器B(172.26.16.4). 容器A和B处于同一个子网中,所以可以直接转发,对应后面的配置步骤C.
  4. 服务器remote_host的容器B提供真正的http 服务,该容器不进行端口映射,也没有反向代理的配置,但是需要日志配置 ,我们需要通过日志来验证结果。配置步骤为D.

关键的配置过程如下: A. 在本地的centos中,对nginx做如下的配置:

代码语言:javascript
复制
#监听端口采用默认的80端口;
......
#remotee_host 对应的IP写在/etc/hosts中
    location / {
      proxy_pass                          http://remote_host:8080/;
      proxy_set_header  X-Real-IP         $remote_addr;
      proxy_set_header  X-Forwarded-For   $proxy_add_x_forwarded_for;
    }
......
[root@localhost conf.d]# systemctl restart nginx.service
[root@localhost conf.d]#

B. 在remote_host中,做如下的配置:

代码语言:javascript
复制
   server {
       listen       8080 default_server;
......
  location / {
  proxy_pass                          http://localhost:8088/;
  proxy_set_header  X-Forwarded-For   $proxy_add_x_forwarded_for;
       }
...
}
......
[root@instance-6p8qz002 nginx]# systemctl restart nginx.service
[root@instance-6p8qz002 nginx]#

C. 在容器A(172.26.16.8) 中配置 nginx反向代理,转发请求到容器B(172.26.16.4)中. 并启动容器A. 这里要注意以下的几点: 1). 在nginx容器中,upstream不能使用ip地址,必须使用name,为了能够实现name到地址的解析,所以把host主机的/etc/hosts mapping为container A中相应文件, 如下的配置中,主机的/etc/hosts中有:"172.26.16.4 container_b" 之间的映射关系 2). 要使用自定义IP,必须要使用自定义的docker 网络

代码语言:javascript
复制
......
    server {
    listen 8080;
......
   location / {
   proxy_pass                          http://container_b:8080/;
   proxy_set_header  X-Forwarded-For   $proxy_add_x_forwarded_for;
        }
......
}
......
#启动容器A的步骤如下,命令如下:
[root@instance-6p8qz002 nginx_b]# docker network create -d bridge --subnet=172.26.0.0/16 --ip-range=172.26.16.0/24    mynetwork
[root@instance-6p8qz002 nginx_b]# docker run -d --rm --network="mynetwork" --ip 172.26.16.8  -p 8088:8080 -v /root/my_project/nginx_a/:/etc/nginx -v /etc/hosts:/etc/hosts   --name nginx_a   nginx

D. 通过容器B提供http服务,这里没有反向代理的配置,其监听端口为8080,不做host到容器B的端口映射. 虽然这里没有反向代理的配置,但是需要配置log记录,同时需要把容器中的log目录 mapping 到host主机的特定目录 ;

代码语言:javascript
复制
#配置监听端口为8080. 配置参数忽略
access_log  /var/log/nginx/access.log  main;  #配置log. 
......
    log_format  main  'Parameter remote_addr : $remote_addr\n'
                      'Parameter http_x_forwarded_for: $http_x_forwarded_for\n'
                      'Parameter http_x_real_ip : $http_x_real_ip';
......
#启动容器B
[root@instance-6p8qz002 my_project]# docker run -d --rm  --network="mynetwork" --ip 172.26.16.4   -v /root/my_project/nginx/:/etc/nginx -v /tmp/nginx/log:/var/log/nginx/   --name nginx_b  nginx

在这个过程中用到的端口如下: 1.centos 主机192.168.0.110的80端口,提供用户访问接口; 2.remote_host的8080端口,用于接收centos转发过来的请求; 3.remote_host的8088端口,用于接收remote_host的8080端口转发过来的请求; 4.启动容器A(172.26.16.8)时,要mapping port 8088:8080,也就是指定-p 参数; 5.容器A的8080端口转发到容器B(172.26.16.4)的8080端口, 容器; 验证结果: 首先在remote_host上用命令: tail -n0 -f /tmp/nginx/log/access.log, 然后使用浏览器访问192.168.0.110, tail的结果如下:

代码语言:javascript
复制
[root@instance-6p8qz002 nginx]# tail -n0 -f /tmp/nginx/log/access.log
Parameter remote_addr: 172.26.16.8
Parameter http_x_forwarded_for: 192.168.0.101, 119.123.132.73, 172.26.16.0
Parameter http_x_real_ip: 192.168.0.101

对于结果的分析如下: remote_addr: log 是在172.26.16.4上产生的,其前一级为容器A(172.26.16.8), 所以remote_addr的地址是 172.26.16.8 http_x_real_ip: 就是浏览器设备对应的地址,在本实验中,就是本机的IP地址:192.168.0.101 ,与理论值一致; http_x_forwarded_for: 第一次反向代理是发生在访问192.168.0.110时候,被代理的客户端为192.168.0.101; 第二次反向代理是remote_host上发生的,被代理的请求来自Public的IP:119.123.132.73 第三次反向代理是容器A(172.26.16.8)上配置的,其直接请求docker 中的网桥转发的,但是为什么会是 172.26.16.0 呢?小弟不才,不是很明白这里的原因,希望读者你能够帮忙解答一二 .

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档