2021.3.15更新

网站套上了Cloudflare CDN后,因为服务器隐藏在cloudflare的后端,所以网站实际接收到访问请求都是Cloudflare的节点服务器发送过来的,那么访客IP也都是Cloudflare的节点服务器的IP,不是访客真实的IP。

如果只是需要nginx的日志记录访客的真实IP,那么不需要开启ngx_http_realip_module模块,只需要调整一下nginx的日志格式log_format即可。

Cloudflare 会将原始访问者 IP 地址包含在 X-Forwarded-For 和 CF-Connecting-IP 请求标头header中,我们只需要增加一个新的nginx log_format。

Nginx的log_format有一个默认的combined格式,具体可以参考nginx的帮助文档http://nginx.org/en/docs/http/ngx_http_log_module.html#log_format

log_format combined '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    '"$http_referer" "$http_user_agent"';

增加一个新的log_format:

1、编辑nginx.conf文件 sudo vim /usr/local/nginx/conf/nginx.conf

2、在sever指令加载前添加新的log_format,并保存

log_format csf '$http_x_forwarded_for - $remote_user [$time_local] '
               '"$request" $status $body_bytes_sent '
               '"$http_referer" "$http_user_agent"';

3、对需要开启access log的网站,编辑对应的配置文件 sudo vim /usr/local/nginx/conf/vhost/example.site.conf

4、在对应的sever指令中加入相应的access_log设置

access_log /home/wwwlogs/example.site.access.log csf;

5、重启Nginx,sudo lnmp nginx restart

这样,Nginx的访问日志记录的就是访客的真实IP了,当然如果不只是需要在access log中记录访客真实IP,那可以继续往下看哦。


2018.8.20分割线

写了一个小网站,刚开始估计也没什么流量,打算开启一下nginx的访问日志access_log,不过问题来了,因为上线时直接套上了Cloudflare CDN,结果发现访问日志里的IP全是Cloudflare节点服务器IP,不是访客的真实IP,这有点尴尬了,拿不到真实IP访问日志就没啥用了,不好分析哪个访问是蜘蛛,哪个访问是真实访客,想着这个问题应该有解决方案,直接在Cloudflare帮助里搜了一下,可以可以,确实有,https://support.cloudflare.com/hc/en-us/articles/200170706-How-do-I-restore-original-visitor-IP-with-Nginx,可以用nginx的 ngx_http_realip_module 模块来获取访客的真实IP,那还说什么,赶紧操作起来。

在网站的nginx配置文件里,加上Cloudflare提供的配置参数

set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 104.16.0.0/12;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 131.0.72.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2606:4700::/32;
set_real_ip_from 2803:f800::/32;
set_real_ip_from 2405:b500::/32;
set_real_ip_from 2405:8100::/32;
set_real_ip_from 2c0f:f248::/32;
set_real_ip_from 2a06:98c0::/29;

# use any of the following two
real_ip_header CF-Connecting-IP;
#real_ip_header X-Forwarded-For;

大概意思就是列表里的ip访问时,会在请求的header参数CF-Connecting-IPX-Forwarded-For中添加访客的真实IP,ngx_http_realip_module模块会在列表中的IP访问时,直接从CF-Connecting-IP中获取访客的真实IP,这些IP是Cloudflare的节点服务器IP,可能会不定时的更新,在这里 https://www.cloudflare.com/ips/ 可以获取到最新的Cloudflare节点服务器IP列表。

配置好后,重载nginx,/etc/init.d/nginx reload,报错

Reload service nginx... nginx: [emerg] unknown directive "set_real_ip_from" in /usr/local/nginx/conf/vhost/xxx.com.conf:10
 done

这是因为ngx_http_realip_module模块默认是不启用的,需要在编译安装时添加配置参数 --with-http_realip_module 开启,然后重新编译安装一下nginx。

如果用的是lnmp一键安装脚本,那就改一下脚本里的nginx编译配置参数,lnmp1.5版本的在 include/nginx.sh 文件的70行

   if echo ${Nginx_Ver} | grep -Eqi 'nginx-[0-1].[5-8].[0-9]' || echo ${Nginx_Ver} | grep -Eqi 'nginx-1.9.[1-4]$'; then
        ./configure --user=www --group=www --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_spdy_module --with-http_gzip_static_module --with-ipv6 --with-http_sub_module ${Nginx_With_Openssl} ${Nginx_Module_Lua} ${NginxMAOpt} ${Nginx_Modules_Options}
    else
        ./configure --user=www --group=www --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_v2_module --with-http_gzip_static_module --with-http_sub_module --with-stream --with-stream_ssl_module ${Nginx_With_Openssl} ${Nginx_Module_Lua} ${NginxMAOpt} ${Nginx_Modules_Options}
    fi  

在编译配置参数里加上 --with-http_realip_module

   if echo ${Nginx_Ver} | grep -Eqi 'nginx-[0-1].[5-8].[0-9]' || echo ${Nginx_Ver} | grep -Eqi 'nginx-1.9.[1-4]$'; then
        ./configure --user=www --group=www --prefix=/usr/local/nginx --with-http_realip_module --with-http_stub_status_module --with-http_ssl_module --with-http_spdy_module --with-http_gzip_static_module --with-ipv6 --with-http_sub_module ${Nginx_With_Openssl} ${Nginx_Module_Lua} ${NginxMAOpt} ${Nginx_Modules_Options}
    else
        ./configure --user=www --group=www --prefix=/usr/local/nginx --with-http_realip_module --with-http_stub_status_module --with-http_ssl_module --with-http_v2_module --with-http_gzip_static_module --with-http_sub_module --with-stream --with-stream_ssl_module ${Nginx_With_Openssl} ${Nginx_Module_Lua} ${NginxMAOpt} ${Nginx_Modules_Options}
    fi  

lnmp1.5支持单独安装nginx,所以只需要重新编译安装一下nginx即可,安装包目录下运行

./install.sh nginx

等上几分钟,编译安装nginx完成,OK,nginx的访问日志记录的是访客的真实IP了,当然不只是Cloudflare CDN,如果用其他的CDN,这种方法也可以的,不过配置里相应的节点IP要换成对应的CDN服务商提供的IP。

PS,如果跑affiliate markting的话,可能会用到追踪系统,比如iMobiTrax这样的可以自建的追踪系统,然后会发现在加上cloudfalre后,访客日志报表里记录的IP全是cloudflare的节点服务器IP,不是真实的访客IP,哈哈,是不是很尴尬,而且iMobiTrax又是加密的,没有办法通过修改源代码来获取真实IP,之前用的时候遇到过,找了很久,没有找到一个可用的解决方案,最后不了了之只好把cloudflare去掉了,不过,今天遇到这个问题正好想到了,也测试了一下,用上边的修改nginx的方式是可以的哦,给nginx添加ngx_http_realip_module模块,然后修改一下相应配置,就可以愉快的给iMobiTrax这样的追踪系统套上Cloudflare CDN了,再也不怕获取不到访客的真实IP了,当然不仅是iMobiTrax,其他的程序也一样,因为这样nginx会直接把真实IP传递给程序,不需要在程序里修改代码来获取真实IP了。

标签: nginx, Cloudflare

添加新评论