先看现象。站点同时开着 nginx 的 limit_req 和 fail2ban,用户反馈输错一次密码就被封,实际封禁时长两小时,防火墙里能找到 nginx 限流和 fail2ban 两条规则叠加。

原因不止一个,得分开看。limit_req 返回 503 后 fail2ban 把 503 当成攻击特征一起统计。另一种情况是fail2ban 的 nginx 规则匹配了 4xx 与 5xx,误把正常用户的 404 也计入。

还有一种情况,自动解封依赖 iptables 规则的过期时间,规则被写进了持久化文件不会过期。

另外,限流阈值按每秒计算,用户打开页面时并发十个资源请求就触发了。

上来先看 fail2ban 到底因为哪条记录封禁

fail2ban-client status nginx-http-auth && grep 'Ban ' /var/log/fail2ban.log | tail -5

接着确认封禁来源是不是自家限流

iptables -S | grep -i drop

然后把 5xx 从匹配规则里去掉并放宽阈值

printf '[Definition]\nfailregex = ^<HOST> .* "POST /login .* 401\n' > /etc/fail2ban/filter.d/nginx-login.local && fail2ban-client reload

解封并给限流加突发余量

fail2ban-client unban 203.0.113.9 && printf 'limit_req zone=login burst=10 nodelay;\n' > /etc/nginx/conf.d/limit.conf && nginx -s reload

怎么算真的好了,看的是同一批现象。同一 IP 再输错两次密码不触发封禁,iptables 里该 IP 的 DROP 记录消失,登录接口的 401 计数与 fail2ban 统计对得上。

两层防护叠加时阈值要成倍留余量,否则正常用户先中招;404 扫描和登录失败要分开统计,混在一起必然误封。这类问题最好一次改到位,反复小改反而容易把原因搅混。

作者 9823189