有的读者可能会问,什么是客户端真实IP地址呢?下面我们通过一张图来简单介绍。
上图中,浏览器请求某个页面,浏览器请求的是代理服务器,所有请求都由代理服务器替他完成。这就导致 Web 服务器不知道客户端的真实 IP 地址,获取到的 IP 地址为代理服务器的 IP 地址。nginx 为我们提供了获取客户端 IP 地址的功能,默认是没有开启的,及 nginx 默认获取的是直接上级服务器的 IP 地址,上图中获取的是代理服务器的 IP 地址。
有的读者可能还会问,为什么一定要获取客户端的真实 IP 地址呢?原因很简单,现在大部分互联网公司通过客户端的真实 IP 地址,可以分析出该公司的产品主要地域等信息。
下面我们将详细介绍怎样在 nginx 中配置获取客户端真实 IP。详细步骤如下:
(1)nginx 要获取客户端真实 IP 需要依赖 ngx_http_realip_module 模块,默认该模块是没有被编译到 nginx 的。需要我们使用 --with-http_realip_module 去编译 nginx,使 nginx 支持 ngx_http_realip_module 模块。先查看当前 nginx 有哪些编译参数,如下:
[root@S0 sbin]# ./nginx -V nginx version: nginx/1.16.1 built by gcc 4.4.7 20120313 (Red Hat 4.4.7-23) (GCC) built with OpenSSL 1.0.1e-fips 11 Feb 2013 TLS SNI support enabled configure arguments: --with-http_ssl_module
运行 ./configure --with-http_ssl_module --with-http_realip_module 命令去预编译 nginx。如下:
[root@S0 nginx-1.16.1]# ./configure --with-http_ssl_module --with-http_realip_module checking for OS + Linux 2.6.32-358.el6.i686 i686 checking for C compiler ... found + using GNU C compiler + gcc version: 4.4.7 20120313 (Red Hat 4.4.7-23) (GCC) ... Configuration summary + using system PCRE library + using system OpenSSL library + using system zlib library nginx path prefix: "/usr/local/nginx" nginx binary file: "/usr/local/nginx/sbin/nginx" nginx modules path: "/usr/local/nginx/modules" nginx configuration prefix: "/usr/local/nginx/conf" nginx configuration file: "/usr/local/nginx/conf/nginx.conf" nginx pid file: "/usr/local/nginx/logs/nginx.pid" nginx error log file: "/usr/local/nginx/logs/error.log" nginx http access log file: "/usr/local/nginx/logs/access.log" nginx http client request body temporary files: "client_body_temp" nginx http proxy temporary files: "proxy_temp" nginx http fastcgi temporary files: "fastcgi_temp" nginx http uwsgi temporary files: "uwsgi_temp" nginx http scgi temporary files: "scgi_temp" [root@S0 nginx-1.16.1]#
预编译成功后,我们就可以运行 make 命令去编译 nginx 了。如下:
[root@S0 nginx-1.16.1]# make make -f objs/Makefile make[1]: Entering directory `/root/nginx-1.16.1' make[1]: Warning: File `src/core/nginx.h' has modification time 3.5e+07 s in the future ... sed -e "s|%%PREFIX%%|/usr/local/nginx|" -e "s|%%PID_PATH%%|/usr/local/nginx/logs/nginx.pid|" -e "s|%%CONF_PATH%%|/usr/local/nginx/conf/nginx.conf|" -e "s|%%ERROR_LOG_PATH%%|/usr/local/nginx/logs/error.log|" < man/nginx.8 > objs/nginx.8 make[1]: warning: Clock skew detected. Your build may be incomplete. make[1]: Leaving directory `/root/nginx-1.16.1'
编译成功后。进入到当前目录的 objs 目录,将 nginx 拷贝到已有的 nginx 的 sbin 目录,替换掉旧的 nginx。如下:
[root@S0 objs]# cp nginx /usr/local/nginx/sbin/ cp: overwrite `/usr/local/nginx/sbin/nginx'? y
(2)修改 nginx.conf 配置文件。修改配置文件如下:
server { listen 80; server_name s0.example.com; set_real_ip_from 192.168.238.0/24; set_real_ip_from 192.168.238.180; real_ip_header X-Forwarded-For; real_ip_recursive on; location / { return 200 "client real ip: $remote_addr "; } }
其中:
set_real_ip_from —— 设置真实的 IP 地址(忽略解析 X-Forwarded-For 头)。如果 IP 地址为该命令设置的 IP 地址或 IP 段,则解析 X-Forwarded-For 头字段。如果不是,则递归解析 X-Forwarded-For 字段,获取客户端真实IP地址。
real_ip_header —— 解析真实客户端 IP 地址需要用到的 HTTP 头字段。
real_ip_recursive —— 递归解析 X-Forwarded-For 头字段。
我们可以借助浏览器插件运行,例如在 Chrome 上运行:
地址栏运行 https://s0.example.com,返回结果如下:
client real ip: 192.168.38.100
客户端真实IP地址是我们通过 X-Forwarded-For 头字段指定的。
如果你有条件,可以在真实场景下面运行试一试。