⭐ 推荐:社区规则条款 V1.0

Nginx 返回 444 拦截爬虫的配置教程。

juming
juming 初级会员萌新站长
发布于 2026-10-19 17:53 ·3 浏览 ·0 回复
内容摘要

用 map 匹配 $http_user_agent、命中后执行 return 444 直接断开连接,是成本最低的爬虫拦截方式;相比 403/404 不返回任何响应内容,也不给爬虫反馈。配置时 map 放在 http 块,return 444

在 Nginx 里拦截爬虫最省资源的方式是:用 map 指令匹配 $http_user_agent,命中后执行 return 444;。444 是 Nginx 自己定义的非标准状态码,它不返回任何响应头、不返回响应体,直接关闭 TCP 连接;客户端(比如 curl)看到的是 Empty reply from server。与返回 403 页面相比,444 省掉了全部响应数据的传输和日志中的 body 记录成本,是成本最低的拒绝方式。

444 和 403、404 有什么区别,为什么拦爬虫要用 444

结论:444 表示「已收到请求但直接断开连接」,403 表示「已收到请求但拒绝提供」,404 表示「未找到」。三者中只有 444 不会向对方返回任何内容。

具体区别有三点。第一,403 和 404 都要走完整的响应流程,Nginx 需要构造状态行、响应头和 error page 内容;404 默认还带一个几百字节的 HTML 页面,高频爬虫一天请求 10 万次就是几十 MB 的出网流量,而 444 的 $body_bytes_sent 恒为 0。第二,444 不给爬虫任何反馈信号——返回 403 相当于告诉对方「这个路径存在但被拒了」,返回 404 会诱导爬虫做更多探测,而直接断连会让部分低质量爬虫判定为网络故障并放弃。第三,访问日志里 444 仍会正常记录成 "GET / HTTP/1.1" 444 0,配合 $request_time 极短这一特征,便于事后统计哪些 UA 被拦得最多。

需要注意,444 是 Nginx 的非标准扩展,不是 HTTP 规范的一部分,Apache 和 Caddy 没有等价行为。

具体配置怎么写

结论:把 map 放在 http 块,把 return 444 放在 server 块,map 默认值写 0,命中的 UA 写 1。

第一步,在 nginx.conf 的 http { } 内定义匹配表。~* 表示不区分大小写的正则匹配,"" 单独对应空 User-Agent——相当一部分采集脚本根本不发 UA:

map $http_user_agent $bad_bot {
    default         0;
    ""              1;   # 空 UA 直接拦
    ~*ahrefsbot     1;
    ~*semrushbot    1;
    ~*mj12bot       1;
    ~*dotbot        1;
    ~*petalbot      1;
    ~*bytespider    1;
    ~*gptbot        1;
    ~*ccbot         1;
    ~*claudebot     1;
}

第二步,在需要保护的 server 块里加判断。if 在 Nginx 里被称为「if is evil」,但 return 是 if 中少数完全安全的用法:

server {
    listen 80;
    server_name example.com;

    if ($bad_bot) {
        return 444;
    }

    location / {
        proxy_pass http://127.0.0.1:8080;
    }
}

如果只想拦某个目录,把 if ($bad_bot) { return 444; } 写进对应的 location 块即可,粒度比放在 server 层更细,不会影响静态资源和 API。

第三步,先测试再重载,不要直接 restart:

nginx -t          # 输出 syntax is ok / test is successful 才能继续
nginx -s reload   # 平滑重载,不断现有连接

怎么验证 444 真的生效了

结论:用 curl 伪造 UA 请求一次,如果返回 curl: (52) Empty reply from server 且退出码为 52,说明 444 已经生效。

验证命令:

curl -I -A "Mozilla/5.0 (compatible; AhrefsBot/7.0)" https://example.com

echo $?   # 输出 52

curl -I -A "Mozilla/5.0 (compatible; Googlebot/2.1)" https://example.com
# 预期:正常的 HTTP/1.1 200 或 301/302

同时去 access.log 里确认,被拦的那条记录形如:

1.2.3.4 - - [10/May/2024:10:00:00 +0800] "GET / HTTP/1.1" 444 0 "-" "Mozilla/5.0 (compatible; AhrefsBot/7.0)"

444 后面的 0 就是发出的字节数,这一列全是 0 才算真正省下流量。

配置时最容易踩的三个坑

结论:误伤正规搜索引擎、把 map 放错位置、以为 444 能挡住改 UA 的爬虫,是这套配置最高频的三个问题。

第一,别把 Googlebot、Bingbot、Baiduspider 写进拦截表。 一旦误拦,站点在搜索结果里的抓取会直接停摆,恢复要等几天。如果确实想拦冒充 Googlebot 的请求,正确做法是反向 DNS 解析来源 IP,确认以 .googlebot.com 或 .google.com 结尾,而不是看 UA 字符串——UA 是可以随便伪造的。

第二,map 只能写在 http 块内,写进 server 或 location 会直接报 "map" directive is not allowed here,nginx -t 会立刻失败。改完配置记得先跑 nginx -t。

第三,444 只对「老实的爬虫」有效。 只要对方换一个普通浏览器 UA 就绕过了。想让拦截真正有效,要叠加多层:用 limit_req_zone 按 IP 限速(例如 limit_req zone=req_zone burst=20 nodelay;,配合 limit_req_zone $binary_remote_addr zone=req_zone:10m rate=5r/s;),用 deny 封禁已经确认的恶意 IP 段,再对异常高的 $request_time 或 404 比例做日志告警。444 只是第一道阻力较低的门槛,成本最低、见效最快,但不能指望它单独解决所有问题。

另外建议新配置先统一返回 403 观察 3 到 7 天日志,确认没有误伤正常来源后再切换成 444,切完对比 access.log 中 444 的条数占比,判断拦截比例是否在预期之内。


综上,拦爬虫的配置路径是:http 块里用 map $http_user_agent $bad_bot 建匹配表(含空 UA),server 或 location 块里 if ($bad_bot) { return 444; },nginx -t 通过后 nginx -s reload,用 curl -A 伪造 UA 验证返回 Empty reply 且日志字节数为 0。444 的价值在于零响应开销,代价是不给任何提示、也挡不住改 UA 的对手,必须和限速、IP 封禁一起用才构成完整的防护组合。

本文转载自 GJ站长论坛,原文地址:https://www.gj0.com/thread-2298.html
转载请注明出处,版权归原作者所有。
—/ 5暂无评分
还没有评分,来打第一分吧

全部回复 0

还没有回复,来抢沙发~