rewrite本身不用于屏蔽爬虫,仅重写URL;真正拦截需用return、deny或if+return等终止指令,可配合rewrite将恶意请求归集到受限location中统一处理。

rewrite 本身不用于“过滤或屏蔽”爬虫,它只负责重写 URL 路径。真正实现屏蔽,靠的是 return、deny 或 if + return 这类终止性指令;rewrite 只在特定场景下配合拦截使用,比如把恶意请求重定向到一个空页面、错误页,或统一改写为不可访问路径再交由其他规则处理。
rewrite 不是拦截工具,但能辅助混淆和归集
直接用 rewrite 屏蔽爬虫容易误伤或失效,因为 rewrite 是路径改写,不是访问控制。但它适合做两件事:
- 把已知恶意 UA 的请求,统一重定向到一个无内容的静态页(如
/crawler-blocked.html),避免暴露真实结构 - 将高频扫描路径(如
/phpmyadmin/、/.git/)全部重写成同一个无意义路径,再用 location 匹配该路径并 return 404 或 444
示例:把所有含 sqlmap 或 nikto 的 UA 请求,302 跳转到提示页
if ($http_user_agent ~* "(sqlmap|nikto|dirbuster)") {<br> rewrite ^(.*)$ /crawler-detected.html?from=$1 permanent;<br>}
注意:permanent 发送 301,redirect 发送 302;若不想暴露跳转,可用 last 或 break 配合内部 location 处理,但必须确保目标 location 有明确响应(如 return 404)。
更可靠的做法:rewrite + location + return 组合封禁
单纯重写没用,关键是要让重写后的路径落入一个严格限制的 location 块中。例如:
先用 rewrite 把所有可疑扫描路径“收口”:
rewrite ^/(phpmyadmin|wp-admin|\.env|backup\.zip|config\.php) /_blocked_path last;
再定义对应 location,直接断连:
location = /_blocked_path {<br> return 444;<br>}
这样既隐藏了原始路径是否存在,又避免在每个敏感路径上重复写 return 规则,维护更清晰。
rewrite 不能替代 UA 判断和限流
依赖 rewrite 拦截爬虫有明显短板:
- UA 可伪造,rewrite 无法识别真实意图
- 不校验请求头缺失(如无 Accept、Referer)、不控频、不记日志
- 若 rewrite 后未匹配到有效 location,请求可能意外透传给后端
所以生产环境必须搭配:
- map 定义
$blocked_ua和$no_ua变量,配合 if return 403/444 - limit_req 对 IP 做基础速率限制(如 5r/s)
- 独立 access_log 记录被拦截请求,便于溯源分析
不要在 location 里嵌套 if + rewrite 做拦截
Nginx 官方明确不推荐在 location 中使用 if,尤其当内部含 rewrite、proxy_pass 等指令时,行为不可预测。常见错误写法:
location / {<br> if ($http_user_agent ~* "curl") {<br> rewrite ^ /block.html break;<br> }<br>}
这种写法大概率失效——rewrite 可能被后续 try_files 或 proxy_pass 覆盖。正确方式是把 UA 判断提到 server 顶层,用 return 直接终止,或用 map + if + return 组合。


















