Fail2ban结合Nginx error.log实现自动封禁,核心是通过解析error.log中高指向性服务层异常(如upstream timeout、SSL handshake失败)精准识别隐蔽攻击,并配置filter、jail及action三要素完成分钟级IP封禁。

Fail2ban 结合 Nginx 错误日志实现自动封禁,核心在于让 fail2ban “读懂” Nginx 的异常行为信号——不是靠访问日志里的请求频次,而是靠 error.log 中反复出现的错误线索,比如连接拒绝、上游超时、SSL握手失败等。这类错误往往比 access.log 更早暴露真实攻击意图,尤其适合识别扫描器试探、恶意代理探测、协议畸形请求等隐蔽行为。
为什么优先看 error.log 而不是 access.log?
Nginx 的 error.log 记录的是服务层异常,具有更强的攻击指向性:
- access.log 里大量 200 或 302 请求可能是正常爬虫,也可能是伪装成功的爆破;但 error.log 出现连续
connect() failed (111: Connection refused),基本可断定是端口扫描或后端服务被故意击垮 - 高频
upstream timed out往往对应 Slowloris 类慢速攻击,单 IP 占用连接却不发完整请求 - 反复
client sent invalid request或SSL_do_handshake() failed多为工具生成的非法协议流量,传统限流难拦截
配置 error.log 封禁的关键三步
以封禁“1分钟内触发5次 upstream timeout”的IP为例:
-
确认日志路径与格式:确保 Nginx 开启了详细错误日志,例如在 nginx.conf 的 http 块中添加:
error_log /var/log/nginx/error.log warn;(级别设为 warn 或 error,避免 info 级别淹没关键信息) -
编写精准过滤器:新建
/etc/fail2ban/filter.d/nginx-upstream-timeout.conf,内容如下:[Definition]<br>failregex = ^\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] \d+#\d+#\d+#\d+.*upstream timed out.*upstream.*<HOST><br>ignoreregex = -
定义 jail 规则:在
/etc/fail2ban/jail.local中添加:[nginx-upstream-timeout]<br>enabled = true<br>filter = nginx-upstream-timeout<br>logpath = /var/log/nginx/error.log<br>maxretry = 5<br>findtime = 60<br>bantime = 7200<br>action = iptables[name=NGINX_TIMEOUT, port=http,https, protocol=tcp]
常见 error.log 攻击模式及对应正则建议
不同攻击会留下不同 error.log 特征,选对匹配项才能避免误杀:
-
HTTP/2 协议滥用:匹配
http_v2_parse_headers()或zero window相关错误,正则示例:failregex = ^.*http_v2_parse_headers.*<host>|^.*zero window.*<host></host></host> -
恶意 SSL 握手试探:关注
SSL_do_handshake() failed后紧跟 IP 地址,注意日志中 IP 可能出现在行尾,需用<host></host>自动提取 -
伪造 Host 头导致路由失败:error.log 中若出现
no resolver defined to resolve.*<host></host>,说明对方在发非法 Host 请求,可直接封禁
验证与调试技巧
配置完成后别急着重启,先做两件事:
- 用
fail2ban-regex /var/log/nginx/error.log /etc/fail2ban/filter.d/nginx-upstream-timeout.conf测试正则是否真能捕获目标日志行 - 手动触发一次错误(如用 curl 向一个不存在的 upstream 发请求),观察
fail2ban-client status nginx-upstream-timeout是否显示当前 IP 已进入监控队列 - 检查 iptables 规则是否生效:
iptables -L INPUT -n | grep NGINX_TIMEOUT


















