Last Updated on

前言

nginx作为高性能反向代理服务器,在反向代理中,获取和传递真实IP是一个常用且重要的事情,下面我就记录说明如果在nginx中获取到真实IP,并传递到后端。

正文

1. 环境

首先,我这里的环境为nginx-1.1.2.2,通过yum安装。如果想要源码安装,需要通过如下参数,启用ngx_http_realip_module模块。

--with-http_realip_module

而传递真实IP到后端,需要使用到ngx_http_proxy_module模块,此模块默认会编译。

对于Nginx的安装和添加nginx模块等,有问题可参考:

《centos7 nginx 安装与配置实现负载均衡》

《Centos7 nginx 不中断服务添加新模块或第三方模块》

2. 配置nginx

然后修改nginx的配置,在http{}的配置中,按如下添加配置:

# 编译nginx配置文件,我这里是yum安装的。
$ vim /etc/nginx/nginx.conf
-------------------------------------------------------------------
http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    log_format weblog '$msec | $time_local | $host | $status | $bytes_sent | $remote_addr | $upstream_addr | $request | $request_time | $upstream_response_time | $request_length | $http_referer | $http_user_agent';

    # 注意,这里我使用的日志格式为我自定义的weblog日志格式,其中会输出$remote_addr 远程客户端地址。
    access_log  /var/log/nginx/access.log  weblog;

    # 下面三行为重点,添加后就可以获取到客户端真实IP
    set_real_ip_from 0.0.0.0/0;
    real_ip_header  X-Forwarded-For;
    real_ip_recursive on;

    # 下面三行为常见反向代理传递真实客户端IP的配置,配置在http{}中,则全局应用在下面的所有server中
    proxy_set_header Host      $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    # Load modular configuration files from the /etc/nginx/conf.d directory.
    # See http://nginx.org/en/docs/ngx_core_module.html#include
    # for more information.
    include /etc/nginx/conf.d/*.conf;

}
-------------------------------------------------------------------

# 重载配置生效,我这里是yum安装
$ systemctl reload nginx

获取真实IP

获取真实IP使用到的ngx_http_realip_module模块,会通过配置提取用户真实IP,并将其负值到$remote_addr,共有三个配置参数,分别是:

  • set_real_ip_from:定义接受从哪个信任前代理处获得真实用户ip,可以定义多行,可定义为ip,ip段,支持ipv4和ipv6
  • real_ip_header:定义从接收到报文的哪个http头部去获取前代理传送的用户ip,默认为X-Real-IP
  • real_ip_recursive:递归搜索,默认为off

参数配置说明:

set_real_ip_from为定义信任ip,如果发送方的ip不在信任中,则不处理,$remote_addr就还会是发送发的地址。如果ip在信任中,则会根据下一个参数real_ip_header的设定,将指定的header头字段的数据作为$remote_addr。

如果real_ip_header中定义的header头字段,只传来了一个IP,比如默认的X-Real-Ip,则会直接将这个ip作为$remote_addr。这时候,如果像阿里云SLB,CDN,或者别的nginx等这类代理传来的,其真实IP可以是通过别的header字段传来的,那么跟去实际情况,定义此字段,这里我用的常见的X-Forwarded-For字段

这里需要说明一下X-Forwarded-For这个header信息,用于记录此请求所进过的ip,假设本nginx为第3层代理,那么获取到的X-Forwarded-For就会记录3个ip,分别顺序为:

用户IP 第一层代理IP 第二层代理IP

这时候就会用到real_ip_recursive参数,如果此参数不开启,就会从右往左,取第一个出现在信任中的IP的左边一位的IP作为$remote_addr,我们这里是全信任,所以就会取到第一层代理IP,这明显就并不一定对。如果开启了real_ip_recursive,那么就会从右边往左一直取到第一个不信任的IP作为$remote_addr,如果像我这里是全部信任,那么最左边的IP则会被作为$remote_addr。

传递真实IP

在上面的配置中,使用proxy_set_header,通过设置header信息来传递真实IP,由于上面我们获取到了真实IP,然后可以通过默认的X-Real-IP头,将获取到的$remote_addr传递过去。也可以通过X-Forwarded-For 使用$proxy_add_x_forwarded_for在获取到的X-Forwarded-For末尾添加上自身的IP然后传递到下一层。设置Host为主机名,当发送发发来的header中有Host的header信息,则会作为$Host传递,如果没有则为nginx服务器主机名。这也是一种传递客户端信息的方式。

上面三行proxy_set_header为最常见的传递参数,注意由于很多时候header中不一定有Host字段,所以基本都是以IP作为客户端标识。

结束

OK,就这么简单,就能获取到真实IP,并传递到后端,同时将其打印到nginx日志中,以方便记录查看分析。

有任何问题,欢迎留言