给站点套上CDN之后,很多人第一件事是打开访问日志看流量,结果发现整天的记录里只有五六个IP来回出现,地理统计也从全国各地缩到了某几个机房所在的城市。不是统计工具坏了,是请求根本没从访客那里直接到你的服务器:浏览器连的是CDN节点,节点再回源,nginx看到的对端地址自然就是节点的地址。这一段链路里,访客的真实IP只存在HTTP头里,服务器得自己从头上把它捞出来。
先确认是不是这个原因。把日志里的地址段去重数一下,如果集中在几个固定网段,而同一时段的访客数远大于这几个地址,基本可以定性。
nginx这一侧有现成的realip模块,三个指令配好就行:set_real_ip_from后面写CDN的回源IP段,real_ip_header指定从哪个头取地址,real_ip_recursive设成on。配好之后$remote_addr会直接变成真实IP,日志格式和后面的统计脚本一行都不用改。
set_real_ip_from是唯一必须较真的地方:只能写CDN官方公布的回源段,绝对不能图省事写成0.0.0.0/0。写宽了,任何人自己带一个X-Forwarded-For头打过来,日志里就记成他伪造的地址,后面所有基于IP的限制、封禁、统计全部失效。回源段一般能在CDN控制台的文档里查到,厂商加了新节点之后要跟着补,漏掉的那一段会退化成节点IP,同一批访客又缩回一个地址。
头名不一定都叫X-Forwarded-For。Cloudflare回源带的是CF-Connecting-IP,部分国内厂商带X-Real-IP,real_ip_header要按实际回源头改,改错了症状是日志仍然一片节点地址。站点前面挂了两层代理时,把real_ip_recursive打开,模块会从右往左跳过可信地址,取第一个不可信的,避免拿到中间层伪造的那一段。
日志修好了,程序里未必跟着好。PHP读REMOTE_ADDR拿到的还是节点IP,要真实地址得解析X-Forwarded-For并取最左边那个值;WordPress这类程序判断当前是不是HTTPS也会出错,需要在反代层把X-Forwarded-Proto传过去,否则后台一直跳回http。评论、登录、下单这些要记来源IP的功能,都得按这个口径改一遍,改漏一处,那一处的风控就等于开着门。
改完别急着看统计报表。用curl带一个假的转发头打一条请求,看日志记成什么;再翻CDN控制台核对回源段清单。nginx改完reload就生效,PHP那侧要重启进程池。日志里同时记两份地址也是常见做法,$remote_addr和$http_x_forwarded_for各占一列,排查时一眼能看出问题卡在哪一层,代价是日志体积涨一截。
申请创业报道,分享创业好点子。点击此处,共同探讨创业新机遇!
