Fail2Ban 防护 Nginx

Nginx 被爆力扫描时的防护,本文示例也有点爆力,可以自行设计。

默认 Nginx 的过滤器

/etc/fail2ban/filter.d/nginx-*.conf

文件名监控日志核心作用触发条件
nginx-error-common.conf公共基础配置,不直接作为 filter 使用被其他 nginx error log 类 filter include,提供统一的日志行前缀正则
nginx-bad-request.confaccess.log拦截畸形 / 无效 HTTP 请求匹配 nginx 返回 400 Bad Request 的请求(空请求、编码垃圾数据、方法缺失等)
nginx-botsearch.confaccess.log + error.log拦截漏洞扫描器 / 爬虫匹配请求特定不存在路径(WordPress、phpMyAdmin 等常见扫描目标)返回 404 的行为
nginx-forbidden.conferror.log拦截访问被禁止路径的行为匹配 nginx 输出 access forbidden by rule(即 403 Forbidden,比如访问 .user.ini、.git 等被 deny all 屏蔽的路径)
nginx-http-auth.conferror.log拦截 HTTP Basic Auth 暴力破解匹配 password mismatch、user not found、Authentication failure 等认证失败日志;aggressive 模式还包含 SSL 握手失败
nginx-limit-req.conferror.log拦截触发 nginx 限流的高频请求 IP匹配 nginx ngx_http_limit_req_module 输出的 limiting requests / delaying requests 日志(请求速率超过 limit_req_zone 阈值)

自定义 Nginx 过滤器

业务目标:对响应4xx的做自动封禁。

分析nginx日志内容

403 Forbidden :access.log

183.1x.1x.1x - zyx 2026-07-12 12:48:48 "GET /FileManager.html HTTP/2.0" 403 175 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36 Edg/150.0.0.0"

183.1x.1x.1x - abc 2026-07-12 13:10:05 "GET /dav/ HTTP/2.0" 401 581 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36"

403 Forbidden :error.log

2026/07/12 13:10:05 [error] 2457#2457: *14 user "abc" was not found in "/etc/nginx/conf.d/module.htpasswd", client: 183.1x.1x.1x, server: t725.cn, request: "GET /dav/ HTTP/2.0", host: "t725.cn"

404 :access.log

91.148.245.81 - - 2026-07-14 02:56:10 "GET /.bash_history HTTP/1.1" 404 51270 "-" "Go-http-client/1.1"

404 :error.log
但可配置 log_not_found off; # 关闭 404 在 error.log 中的额外记录(默认 on)

4330 2026/07/17 10:32:10 [error] 3073#3073: *8696 open() "/data/www/html/sitemap.xml" failed (2: No such file or directory), client: 216.73.216.140, server: [t725.cn](https://link.wtturl.cn/?target=https%3A%2F%2Ft725.cn&scene=im&aid=497858&lang=zh "autolink"), requ est: "GET /sitemap.xml HTTP/2.0", host: "[t725.cn](https://link.wtturl.cn/?target=https%3A%2F%2Ft725.cn&scene=im&aid=497858&lang=zh "autolink")"

配置过滤器

/etc/fail2ban/filter.d/nginx-t725_4xx.local

# 前提 Nginx 日志格式为:log_format main '$remote_addr - $remote_user $time_fmt "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"';
# Nginx 日志示例1:91.148.245.81 - - 2026-07-14 02:56:10 "GET /.bash_history HTTP/1.1" 404 51270 "-" "Go-http-client/1.1"
# Nginx 日志示例2:183.1x.1x.1x - abc 2026-07-12 13:10:05 "GET /dav/ HTTP/2.0" 401 581 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36"

[Definition]

# failregex 用于从符合条件的记录中,抽取IP;所以表达式里有ip,也有时间,也有响应码4xx。
failregex = ^<HOST> - \S+ \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} "[^"]*" 4\d{2} \d+ "[^"]*" "[^"]*"$

ignoreregex =

# datepattern 用于从符合条件的记录中,抽取时间;表达式里ip,是用来定位的。
datepattern = ^<HOST> - \S+ (%%Y-%%m-%%d %%H:%%M:%%S)

验证过滤器内容

$ fail2ban-regex /var/log/nginx/access_t725.cn.log /etc/fail2ban/filter.d/nginx-t725_4xx.local

主配置文件

/etc/fail2ban/jail.local

# ---------- Nginx (4xx)暴力扫描 ----------
[nginx-4xx]
enabled  = true
port     = http,https
filter   = nginx-t725_4xx
# logpath 还有默认的变量 %(nginx_error_log)s 与 %(nginx_access_log)s ,但不适用,另外要使用*通配符。
logpath  = /var/log/nginx/access_t725.cn.log
           /var/log/nginx/access_s3.t725.cn.log
           /var/log/nginx/access.log
maxretry = 10
#findtime = 600
#bantime  = 3600

生效配置文件

$ sudo fail2ban-client reload
$ sudo fail2ban-client status nginx-4xx

发表回复