云服务器运维实战系列 · 第 7 篇(共 7 篇)
免费流量被爬虫刷爆:用 Nginx 444 精准拦截(附安全配置清单)
免费套餐的服务器,出站流量有额度,超了可能收费。我在面板上看到上行一直有流量、速度还不低,站点没几个人访问,数据却一直在往外发。查了 Nginx 日志,发现是大量 AI 训练爬虫和扫描器在反复抓页面、扫路径。
这篇讲怎么确认是谁在刷、怎么用 Nginx 的 444 状态码在连接层直接掐掉,以及顺手整理的一份安全配置。
第一步:确认流量是谁产生的
先看访问日志里都有哪些 User-Agent、哪些 IP 最活跃:

# 统计访问最多的 IP
sudo awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head
# 统计出现最多的 User-Agent
sudo awk -F'"' '{print $6}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20
我看到大量请求来自这些公开的 AI/采集爬虫和扫描器(UA 里直接带名字):
SemrushBot
meta-externalagent / meta-externalfetcher
ClaudeBot / anthropic
Bytespider
python-requests / Go-http-client / curl(扫描器常用)
它们有的反复抓整站,有的专扫 .env、wp-login、phpmyadmin 这类敏感路径。页面虽然小,但架不住请求量大,累计出站流量很可观。
第二步:为什么用 444,而不是 403
Nginx 有个非标准状态码 444(return 444):它不返回任何 HTTP 响应,直接在 Nginx 这一端关闭连接。

对比:
403 Forbidden:仍然要走完响应,返回一个错误页,客户端还会继续换路径试;444:连接直接断,不发响应体,不产生出站流量,对刷量的爬虫最省事。
第三步:按 User-Agent 拦截
在 http 块(通常放 /etc/nginx/conf.d/ 下的独立文件,或 nginx.conf 的 http 段)用 map 标记恶意 UA:
# 放在 http {} 内
map $http_user_agent $bad_bot {
default 0;
~*SemrushBot 1;
~*meta-externalagent 1;
~*meta-externalfetcher 1;
~*ClaudeBot 1;
~*anthropic-ai 1;
~*Bytespider 1;
~*AhrefsBot 1;
~*MJ12bot 1;
~*DotBot 1;
~*(python-requests|Go-http-client|libwww-perl) 1;
}
然后在需要保护的 server 块里拦截:
server {
listen 443 ssl;
server_name 你的域名;
# 命中恶意 UA 直接断连
if ($bad_bot) {
return 444;
}
# 其余正常配置 ...
}
注意:Nginx 配置里 if 在 location 内容易踩坑,但在 server 层做简单的 return 是安全的官方用法。改完先测试再重载:
sudo nginx -t && sudo systemctl reload nginx
UA 名单按自己日志里实际出现的补,~* 表示不区分大小写。如果你希望自己的内容被某些 AI 检索,就别把对应 Bot 加进去。
第四步:拦截敏感路径扫描
扫描器最爱探测的路径,也直接 444:
server {
# ...
# 常见敏感文件 / 后台扫描
location ~* /\.(env|git|htaccess|htpasswd) { return 444; }
location ~* /(wp-login|wp-admin|xmlrpc\.php) { return 444; }
location ~* /(phpmyadmin|pma|adminer) { return 444; }
location ~* /(vendor|tmp|backup|config)\. { return 444; }
}
这里有个我实际踩过的点:location 的匹配顺序。Nginx 正则 location 按书写顺序匹配、第一个命中即停;如果请求在 server 层已被 rewrite 改写成别的 URI,再用 location 正则去拦原始路径可能拦不到。所以拦截规则要针对最终生效的 URI,或干脆在 server 层用 if ($bad_bot) 这种不受 rewrite 影响的方式处理 UA。
第五步:限速,兜底防刷
对没被直接拉黑、但请求过密的,做连接和请求限速:

# http 块定义限速区
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
limit_conn_zone $binary_remote_addr zone=addrlimit:10m;
server {
limit_req zone=general burst=20 nodelay;
limit_conn addrlimit 20;
}
rate=10r/s 是平均每秒 10 个请求,burst=20 允许短时 20 个排队,正常访客无感,脚本狂刷会被挡。
验证效果
重载后,用被封的 UA 本机测试:
# 用恶意 UA 请求,应直接被断开(无响应)
curl -A "SemrushBot" -I https://你的域名/
# 正常 UA 请求,应返回 200/301
curl -A "Mozilla/5.0" -I https://你的域名/
再观察面板流量和 access.log,被拦的请求不再产生响应流量,上行明显回落。也可以统计日志里 444(若记录了的话)的数量确认命中。
顺手整理的安全清单
结合这次迁移,给服务器定的几条基础防护:
- 只开放必要端口,面板、数据库不直接暴露公网;数据库只监听 127.0.0.1;
- phpMyAdmin 等管理工具不开公网,需要时通过 SSH 隧道或反代 + 访问限制进入;
- SSH 换非默认端口、禁用密码登录改用密钥、限制 root 直接登录;
- 面板用强密码 + 安全入口,及时更新面板和插件;
- Nginx 层拦恶意 UA、敏感路径,并做限速;
- 网站目录权限最小化,删掉不用的站点和默认页;
- 定期自动导出数据库、异地备份,备份文件不放在 web 可访问目录;
- 定期看一眼流量和日志,异常刷量早发现。
小结
防爬虫刷量的关键是先看日志、确认是谁,再在 Nginx 层处理:恶意 UA 和敏感路径用 return 444 直接断连、不产生流量,其余靠限速兜底。免费额度有限,与其等流量超了,不如在入口就把无意义的抓取掐掉。