Nginx拦截恶意爬虫时,需将if指令放在server块顶层,利用map模块预编译用户代理黑名单,配合limit_req限流,同时设置白名单做兜底,并单独处理空用户代理。要避免在location块内使用if,否则配置失效。正确配置能提升服务器性能,防止误封合法流量。
Linux Nginx拦截恶意爬虫配置方法
时间:2026-06-29
浏览:325
文章目录
在Nginx中,通过一条if语句拦截恶意爬虫,往往难以奏效。例如,if ($http_user_agent ~* "scrapy")这类配置,大多数情况下并不能真正生效。问题在于if指令在location块中的行为与常规条件判断不同,它更接近“伪指令”,容易被后续的proxy_pass、try_files等指令覆盖或跳过。正确的做法是将if放在server块的顶层,并配合map预编译、limit_req限流、白名单兜底,同时单独处理空User-Agent,才能有效拦截恶意爬虫。

因此,单纯使用if ($http_user_agent ~* "scrapy")来拦截恶意爬虫,90%的配置要么失效,要么误杀。正确做法是放在server块顶层,同时配上限流和白名单,并持续监控日志。
为什么if在location里基本不生效
Nginx的if指令在location内部并非简单的条件判断,它本质上是一个“伪指令”,很容易被后续的proxy_pass、try_files或fastcgi_pass覆盖或跳过。更麻烦的是,多个if嵌套时,逻辑会变得不可预测,官方文档也明确标注了“a void”。
- 错误写法:
location /api { if ($http_user_agent ~* "curl") { return 403; } }—— 这条规则大概率被忽略,等于白写。 - 正确位置:紧贴
server {下方,在listen和server_name之后、所有location之前。 - 空UA必须单独处理:
if ($http_user_agent = "") { return 403; },不能用正则匹配。 - 大小写敏感问题:
~*才能匹配Python-urllib和python-requests,如果用了~,会漏掉一半。
用map定义$blocked_ua更可靠
将UA黑名单从if搬到http块里的map,是更明智的做法。性能更高、顺序可控、语法更安全。Nginx启动时就编译好映射表,不依赖运行时判断。
- 在
http块中添加(注意分号和空格):map $http_user_agent $blocked_ua { default 0; ~* (sqlmap|nikto|gobuster|nuclei) 1; ~* (python-requests|curl|wget|httpie) 1; ~* (scanner|crawler|exploit|pentest) 1; ~* (^$|^s*$|^-$) 1; } - 在
server块中启用:if ($blocked_ua) { return 403 "Access denied."; } - 白名单必须后置:若要放行
Bingbot,需在map中写成~* Bingbot 0;,且放在黑名单规则之后。 - 别匹配泛化词:
~* python会误伤CPython或内部监控脚本,应该写具体工具名。
limit_req才是防高频爬虫的核心
封UA只能拦住“懒爬虫”。真正让服务器吃紧的,是那些每秒发几十次请求的自动化脚本。此时,limit_req才是主力。它基于IP地址做漏桶限速,硬性掐断流量。
- 定义区(
http块):limit_req_zone $binary_remote_addr zone=ip_limit:10m rate=5r/s;(注意$binary_remote_addr比$remote_addr更节省内存) - 启用位置(推荐放在敏感
location中):limit_req zone=ip_limit burst=10 nodelay; burst=10表示允许瞬时最多15次请求(基础5 + 缓冲10),nodelay让这10次立刻处理,不排队。- 登录接口建议:
rate=1r/s burst=0,彻底禁止连试;静态资源可设rate=100r/s,防止页面卡顿。 - 必须显式声明拒绝码:
limit_req_status 429;(Nginx ≥1.23可用reject=429)
robots.txt必须用location = /robots.txt精确匹配
直接返回内容比读磁盘文件快。但写错匹配方式,可能泄露路径或返回错误内容。
- 错误写法:
location /robots.txt { ... }—— 会意外匹配/robots.txt.bak或/robots.txt/xxx - 正确写法:
location = /robots.txt { default_type text/plain; add_header Content-Type "text/plain; charset=UTF-8"; return 200 "User-agent: *nDisallow: /adminnDisallow: /wp-login.phpn"; } - 换行必须用LF(
n),Windows的rn会让部分爬虫解析失败。 - 如果只屏蔽百度、搜狗等个别爬虫,
User-Agent规则必须按“具体→泛化”顺序写,User-Agent: *放最后,否则会提前终止匹配。
最后想说:最容易被忽略的其实是白名单兜底。盲目封禁含bot、spider的UA,会直接阻断Googlebot、Applebot、Zabbix、Prometheus这些合法流量——后果比爬虫本身还严重。所以,得先建白名单变量,再拦黑名单,而不是简单粗暴地“非白即黑”。
实用工具推荐
绿化、压缩、噪点和虚拟水印,自由调节做旧程度。
选择画质和输出格式,预览压缩前后的大小。