nginx防爬虫核心是分层防御:ua识别须用map预定义变量并置于http块,拦截逻辑必须放在server块顶层(listen和server_name之后),空ua需用= ""单独匹配,配合limit_req限流与白名单兜底,否则易失效或误杀。

在 Nginx 的 server 块中屏蔽恶意爬虫,核心不是堆砌规则,而是分层防御:先精准识别、再刚性拦截、最后兜底限流。单纯靠 if ($http_user_agent ~* "...") 很容易失效或误杀,必须放在正确位置并配合其他机制。
把 UA 拦截逻辑放在 server 块顶层
if 指令在 location 内部是伪指令,极易被后续配置覆盖,官方明确建议避免使用。正确做法是将 UA 判断写在 server { 开头之后、所有 location 之前的位置:
- 例如:
listen 80;和server_name example.com;下方直接写if ($blocked_ua) { return 444; } - 空 UA 必须单独处理:
if ($http_user_agent = "") { return 403; }(不能用正则匹配) - 大小写敏感要用
~*,比如~* "python-requests|curl|scrapy"
用 map 预定义黑名单变量(推荐)
把 UA 匹配逻辑从 if 移到 http 块的 map 中,性能更高、顺序可控、启动即编译,避免运行时反复解析正则:
- 在
http {块里添加:
default 0;
~* (sqlmap|nikto|gobuster) 1;
~* (python-requests|curl|wget|httpie) 1;
~* (scanner|crawler|exploit) 1;
~* (^$|^\s*$|^-$) 1;
}
- 然后在
server块中启用:if ($blocked_ua) { return 444; } - 白名单要后置:如放行 Bingbot,加一行
~* Bingbot 0;并放在所有黑名单规则之后
对高频行为做刚性限流(关键防线)
封 UA 只能拦住“懒爬虫”,真正耗资源的是每秒几十次请求的自动化脚本。必须用 limit_req 从源头掐断:
- 在
http块定义限速区:limit_req_zone $binary_remote_addr zone=ip_limit:10m rate=5r/s; - 在
server块中启用(不建议全局,可选敏感路径):limit_req zone=ip_limit burst=10 nodelay; - 登录类接口建议更严:
rate=1r/s burst=0,彻底禁止连试 - Nginx 1.23+ 支持
reject=503,确保返回明确错误码而非静默丢弃
补充防护:限制请求方法与连接并发
很多爬虫不用标准浏览器方法,也不守连接规范:
- 禁止非标请求方法:
if ($request_method !~ ^(GET|HEAD|POST|OPTIONS)$) { return 403; } - 防多线程扫荡:在
http块定义limit_conn_zone $binary_remote_addr zone=conn_limit:10m;,再在server块加limit_conn conn_limit 3;(单 IP 最多 3 个并发连接) - 缩短超时时间:
client_header_timeout 5;、client_body_timeout 5;,快速释放恶意空连接











