Nginx 防爬虫时如何设置搜索引擎白名单?
Nginx 防爬虫应避免用 if 判断 UA,而用 map 按 User-Agent 生成标记并接入 limit_req_zone 的 key,使搜索引擎请求以空 key 跳过限流,同时配合 IP 反向解析防伪造,并建议对白名单分档限速而非
结论:Nginx 防爬虫时的搜索引擎白名单,正确做法是用 map 指令按 User-Agent 匹配蜘蛛标识生成一个标记变量,再把该变量接入 limit_req_zone 的 key——白名单请求的 key 置为空字符串,Nginx 对 key 为空的请求不计入限流;同时必须配合 IP 反向解析校验,因为 UA 可以随意伪造。
为什么不用 if 判断 User-Agent?
结论:在 location 里用 if ($http_user_agent ~* Baiduspider) 放行是错误姿势,if 在 Nginx 中属于“邪恶指令”(if is evil),在 location 上下文里会破坏配置继承顺序,且多个 UA 并列时性能差、难维护。
map 定义在 http 块,只在配置加载时编译一次,运行时是哈希查找,10 个 UA 关键词和 1 个的成本几乎相同。而且 map 产出的变量可以复用到限流、日志、缓存多个环节,比散落的 if 干净得多。
搜索引擎白名单的 Nginx 配置怎么写?
结论:核心是三段——map 匹配 UA、map 生成限流 key、limit_req_zone 引用这个 key。以下配置可直接抄改:
http {
# 1. UA 白名单,命中置 1
map $http_user_agent $engine_ua {
default 0;
"~*Baiduspider" 1;
"~*Googlebot" 1;
"~*bingbot" 1;
"~*Sogou web spider" 1;
"~*360Spider" 1;
"~*YisouSpider" 1;
"~*Bytespider" 1;
"~*YandexBot" 1;
"~*Applebot" 1;
"~*DuckDuckBot" 1;
}
# 2. 生成限流 key:引擎留空,其余按 IP
map $engine_ua $limit_key {
1 "";
0 $binary_remote_addr;
}
# 3. 声明限流区
limit_req_zone $limit_key zone=crawler:10m rate=5r/s;
server {
location / {
limit_req zone=crawler burst=20 nodelay;
# 便于事后审计:日志里带上标记
add_header X-Engine-Hit $engine_ua always;
}
}
}
要点:$binary_remote_addr 比 $remote_addr 省内存,IPv4 固定 4 字节;10m 约可存 16 万个 IP 状态;rate=5r/s 是普通访客基线,burst=20 nodelay 允许 20 个突发请求立即处理。Nginx 官方文档明确写着 “Requests with an empty key value are not accounted”,所以 key 为空的蜘蛛请求完全不进限流桶。
白名单只放宽、不全放,怎么设计?
结论:不建议给搜索引擎完全免限,推荐“分档限速”——普通用户 5r/s、白名单 20r/s 并单独给大 burst,既保证抓取效率,又能挡住伪装成百度蜘蛛的高频 CC。
做法是建两个 limit_req_zone,用 map 再分流出 $limit_key_normal 和 $limit_key_engine,在 location 里写两条 limit_req;Nginx 允许多条 limit_req 并存,任一超限即返回 503。另一个细节:map 里的正则必须加引号包住含空格的关键词(如 "~*Sogou web spider"),否则 Nginx 启动会报 invalid number of the map parameters。
怎么识别伪装成搜索引擎的爬虫?
结论:UA 白名单只是第一道门槛,真正的校验是“反向解析 + 正向解析”双重 DNS 验证,Nginx 自身做不到,需要用定时脚本生成 IP 清单后 include 进配置。
以百度为例,官方验证方法是:对来访 IP 执行 dig +short -x 220.181.108.75,若返回 baiduspider-220-181-108-75.crawl.baidu.com 这类 *.crawl.baidu.com 域名,再对该域名做 dig +short baiduspider-220-181-108-75.crawl.baidu.com,返回的 IP 必须与来访 IP 一致才算真蜘蛛。Googlebot 同理,反解应落在 *.googlebot.com 或 *.google.com。两个方向都对不上,就是伪造。
落地建议:写一个每小时跑的脚本,从 access.log 提取带 $engine_ua=1 的 IP,做双重解析,验证通过的写进 /etc/nginx/conf.d/engine_ips.conf 里的 geo $trusted_engine { default 0; 220.181.108.75 1; ... },然后 nginx -s reload。真实爬虫 IP 段很稳定,一天最多新增几十条,reload 开销可忽略。不要硬编码 Google 的 IP 段——官方 JSON 每季度会变,写死迟早失效。
常见坑有哪些?
结论:最容易踩的三个坑是大小写、编码和日志。
第一,UA 大小写不统一,必用 ~* 而非 ~,Baiduspider 和 baiduspider 都出现过。第二,部分爬虫会带 URL 编码或全角字符,日志里先抓原始 UA 再补关键词,别凭记忆写。第三,务必在 log_format 里加上 $engine_ua,否则被刷了流量你无法区分是白名单误放还是正常抓取。另外 limit_req 超限返回的是 503,如果站点前面还有 CDN,记得把 503 也纳入缓存穿透保护。
整体思路归结成一句:map 定白名单、空 key 免限流、DNS 反解析保真伪、日志留痕做审计。四步走完,搜索引擎抓取不受影响,伪装爬虫照样被限。
转载请注明出处,版权归原作者所有。