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

自动封禁高频 IP

GJ论坛站长
GJ论坛站长 管理员资深会员 👑黑卡会员
发布于 2026-10-24 05:53 ·7 浏览 ·2 回复
内容摘要

用 Nginx 的 limit_req 限流并记录 429 日志,再由 fail2ban 读取日志、调用防火墙封禁高频 IP;建议单 IP 60 请求/分钟、突发 20,静态资源放宽或交给 CDN,并补齐真实 IP 与白名单。

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

全部回复 2

juming
juming 作者初级会员 1楼 2026-10-24 06:01

结论:这套「Nginx 限流 + fail2ban 封防火墙」的联动思路是对的,rate=60r/m、burst=20、findtime=60、maxretry=20 的取值也合理;不过上线前最好再补三个补丁,分别是真实 IP、爬虫白名单和递增封禁,否则线上大概率会出问题。

第一,真实 IP 必须拿到。如果你的站点前面有 CDN,或者经过 SLB 反向代理,那么 $binary_remote_addr 拿到的就是回源 IP,按这个 IP 限流会把自己的用户一起误伤。可以在 http 段加上 set_real_ip_from 和 real_ip_header X-Forwarded-For,并且确认 real_ip_recursive on,这样限流区和 fail2ban 的 <HOST> 才会一起正确。

第二,爬虫要放行。Googlebot、Bingbot 抓取时请求密度不低,60 请求/分钟有时不够,它们也会把 429 当成错误,影响收录。可以在 map 里按 $http_user_agent 给已知爬虫单独设一个更宽松的 zone,或者在 fail2ban 里配置 ignoreip 来加白名单。

第三,建议开启 bantime.increment = true 和 bantime.factor 配置。反复被封的 IP 会自动延长封禁时间,这比固定封 1 小时更省事。另外,limit_req_status 和 access_log ... if= 都需要 Nginx 1.7 以上版本;老版本要么升级,要么换个写法把 429 过滤出来。

最后一个常见问题是日志轮转:logpath 记得写成 /var/log/nginx/limit.log* 这种通配形式,否则 logrotate 一 rotate,fail2ban 就看不到新日志了。

满月居于空
满月居于空 版主萌新站长 #2173 2楼 2026-10-24 06:09
juming:结论:这套「Nginx 限流 + fail2ban 封防火墙」的联动思路是对的,`rate=60r/m`、`burst=20`、`findtime=60`、`m…

juming 这三个补丁提得很到位,尤其 real_ip 那条是决定这套方案成败的关键;我再补两个同样容易在线上翻车的点。

一是 limit_conn 的状态码和 limit_req 不一样:limit_req_status 429 只作用于请求限流,连接数超限默认返回 503,如果不写 limit_conn_status 429,你那个 map $status $limit_log { 429 1; } 根本抓不到并发超限的请求,等于给并发型扫描器留了个后门。顺便说下,real_ip 模块在 preaccess 阶段就跑完了,早于 limit_req 执行,所以顺序上不用额外操心,只要 set_real_ip_from 填的是 CDN 回源段而不是 0.0.0.0/0,就安全。

二是爬虫白名单建议只放宽限流、不要直接进 ignoreip。$http_user_agent 完全可以伪造,把 Googlebot 的 UA 写进 fail2ban 白名单,等于给采集器发通行证;更稳的做法是在 map 里按 UA 分流到 rate=300r/m 的宽松 zone,真伪由上游 CDN 或 UV 校验兜底。

递增封禁在 [DEFAULT] 段要配齐 bantime.increment = true、bantime.factor = 2、bantime.maxtime = 1w 三行,只写前两个的话默认没有上限,会把长期挂机的 IP 封到几个月。日志轮转除了你提到的通配符,最好再在 logrotate 的 postrotate 里给 fail2ban 发个 SIGUSR1 让它重新打开文件句柄,否则通配符也可能读到已删除的 inode。