凌晨两点十七分,我盯着宝塔面板里那个刺眼的“今日PV:48217”,又看了眼网站后台统计的“真实访客:326”,差点把嘴里的红牛喷在键盘上,差了一百多倍!这要是给老板汇报,说我们这破企业站日活五万,估计明天就得被叫去喝茶——这流量用脚趾头想都知道是假的。
先说下环境,服务器是台2核4G的廉价云主机,跑着宝塔7.9.8,网站是个用WordPress搭的产品展示站,日发文章两三篇,从三天前开始,面板首页那个PV数字就像打了鸡血,从稳定的两三千突然飙到三万多,CPU负载却几乎没动,带宽也没见顶,我当时还以为服务器被当成肉鸡去攻击别人了,吓得赶紧截图发给机房,结果人家查完说“你这入站流量没问题,就是包比较多,也没攻击特征”。
问题肯定出在统计口径上,我第一反应是装了那些乱七八糟的统计插件冲突了,宝塔面板的PV统计,默认是靠读取网站的访问日志文件(Nginx的access.log)来算的,我随手点开日志文件,好家伙,一个IP叫xxx.xxx.5的“勤劳小蜜蜂”,在十分钟内GET了同一个文章页URL整整四百次,每次的User-Agent还在伪装成谷歌蜘蛛和百度爬虫之间反复横跳,这他妈是采集站还是谁家写烂了的爬虫脚本?
宝塔面板PV虚高吓人?我花了一整夜,终于揪出了那个假流量元凶
排坑第一步,我先怀疑是“回环请求”。 我查了下宝塔的Nginx配置,发现网站开了gzip和日志缓冲,但问题不在这,我直接在SSH里敲了tail -f /www/wwwlogs/xxx.log | awk '{print $1}' | sort | uniq -c | sort -nr | head -20,结果吓人,前十的IP全是同一网段,而且User-Agent里带着python-requests的裸奔痕迹,这不就有鬼了,我立马在宝塔面板的“Nginx防火墙”里,找到了“恶意User-Agent拦截”模块,把python-requests、Go-http-client、Java/1.8.0_xxx这几个常用脚本头全部拉黑。报错截图描述:当时防火墙日志里清一色的红色405状态码,我截了张图发给朋友,他还嘲笑我说“你网站是不是被程序员拿来练手了”。
但拉黑之后PV只掉了三分之一,还有大头。 这时候我怀疑是网站内部自己动了手脚,WordPress后台我装了个“WP Super Cache”插件,开了“预缓存模式”,正常情况下,爬虫来请求,PHP不去查数据库,直接返回静态的HTML缓存,这确实会消耗PV但没有动态进程,但问题来了——之前为了做“优化”,我在宝塔的“网站设置”->“配置文件”里,往缓存规则里加了这么一段:
if ($request_uri ~* ".(gif|jpg|png|js|css)$") {
access_log off;
}
乍一看没毛病,可以不打日志,但宝塔的PV统计不看这个,它统计的是$request_uri有多少个请求,而诡异的是,我后来翻日志发现,那个爬虫不仅GET页面,还疯狂地GET一个叫/wp-content/uploads/2024/xx.jpg的随机图片地址,每次带不同的?ver=3.1.2参数,这些图片请求都命中缓存,返回200,但都算进了PV里。解决方案就是砍掉“带参数请求”的统计,这不难,我在宝塔的Nginx配置http{}块里加了一行:
map $request_uri $pv_ignore {
default 0;
~*\.(gif|jpg|png|js|css|map|svg)(\?.*)?$ 1;
}
然后在日志格式变量里,用if ($pv_ignore) { access_log off; }把静态资源请求全给丢了。不过这只是治标。
真正让我炸毛的,是第二天早上起来,PV到了恐怖的11万,原来那爬虫学聪明了,它把User-Agent改成了真实浏览器,而且专门挑我文章页/archives/123.html刷,每次间隔0.3秒,看着CPU还是1%,但我心里明白,这是被恶意“刷量”了。这里必须说一个宝塔的隐蔽坑:默认的访问日志如果不开“日志切割”,文件会越来越大,tail命令查起来巨慢,而且高并发写入会占满IO。 我顺手把日志切割改成每天一次,压缩归档,彻底卸载了那个统计PV的旧插件。
最后排查到根源,居然是我服务器上另一个站点的反向代理配置写错了,那个站点是给客户做的伪静态网页,Nginx配置里有一行:
proxy_pass http://127.0.0.1:8080;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
但我没注意,8080端口是那台WordPress站的PHP-FPM的状态监听端口,结果就是,外部访问那个客户站域名时,Nginx把请求转发到了本地的WordPress站点上,WordPress收到请求,解析URL,发现域名不匹配,又302跳回主域名,但每次跳转都算一次PV。也就是说,我等于自己人刷自己人的PV,还刷爆了。 解决方式特简单:去宝塔“软件商店”里找到那个站点的PHP-FPM,把它监听端口改成/tmp/php-cgi-82.sock(Unix socket),然后Nginx反代配置里proxy_pass http://127.0.0.1:8080改成socket地址,改完重启PHP和Nginx,PV瞬间打回原形。
最后给同行提个醒,宝塔面板的PV只是参考,它统计的是Nginx请求数,不是真实访客,真要准确看流量,请用官方统计插件(如:前端JS统计)或者独立的自建统计(如Umami)。务必开启宝塔的“日志计划任务”,每周清一次旧日志,否则日志文件大于2G时,access_log off就没用了,因为Nginx会先写入再判断。
现在凌晨四点,我关了防火墙的“CC防护”提示,看着PV稳稳停在3,826,心里踏实了,社区里那些天天吹“日IP百万”的,八成也是被这种假数据骗了,还沾沾自喜地发教程呢,少走点弯路吧,先检查你的反代端口,再谈优化。



发表评论