3651 字
18 分钟
Fail2ban 安装与使用终极笔记

Fail2ban 安装与使用终极笔记#

摘要#

本文档旨在提供一个在主流 Linux 服务器 (CentOS/RHEL, Debian/Ubuntu) 上安装、配置和管理 Fail2ban 的完整指南。Fail2ban 是一个入侵防御软件框架,通过监控日志文件,匹配恶意行为模式(如密码暴力破解、漏洞扫描等),并自动调用系统防火墙封禁相应的IP地址。

1. 安装 Fail2ban#

根据您的 Linux 发行版,选择对应的安装命令。

选项 A: 在 CentOS / RHEL 系统上#

在基于 Red Hat 的系统中 (如 CentOS 7/8/9, RHEL),Fail2ban 不在默认软件源中,需要先安装 EPEL (Extra Packages for Enterprise Linux) 扩展源。

Terminal window
# 步骤 1.1: 安装 EPEL 源
sudo yum install -y epel-release
# 步骤 1.2: 安装 Fail2ban
sudo yum install -y fail2ban

选项 B: 在 Debian / Ubuntu 系统上#

在基于 Debian 的系统中 (如 Debian 10/11/12, Ubuntu 18.04/20.04/22.04),Fail2ban 位于官方默认源中,可以直接安装。

Terminal window
# 步骤 1.1: 更新软件包列表 (最佳实践)
sudo apt update
# 步骤 1.2: 安装 Fail2ban
sudo apt install -y fail2ban

步骤 1.3: 启动并设置开机自启 (所有系统通用)#

现代的 Linux 发行版都使用 systemd 来管理服务,因此以下命令是通用的。

Terminal window
# 立即启动 Fail2ban 服务
sudo systemctl start fail2ban
# 将 Fail2ban 服务设置为开机自启
sudo systemctl enable fail2ban

步骤 1.4: 验证服务状态 (所有系统通用)#

检查服务是否已成功启动并处于 active (running) 状态。

Terminal window
# 查看 Fail2ban 服务的当前状态
sudo systemctl status fail2ban

成功标志:看到绿色的 active (running) 字样。


2. 核心配置#

Fail2ban 的配置遵循“覆盖”原则,我们绝对不要修改主配置文件 jail.conf,而应在 jail.local 中进行所有自定义。

步骤 2.1: 创建本地配置文件#

复制一份 jail.conf 作为我们的本地配置文件 jail.local

Terminal window
# 从模板复制配置文件
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

步骤 2.2: 编辑 jail.local 文件#

使用文本编辑器(如 nanovim)打开 jail.local 文件进行配置。

Terminal window
sudo nano /etc/fail2ban/jail.local

步骤 2.4: 粘贴您的自定义配置#

将文件原有内容清空,然后粘贴您自己的配置。

# =================================================================================
# Fail2ban Ultimate Configuration - v3.3 (Final Stability-Focused Version)
# 修正了“日志文件未找到”的启动错误,采用最稳妥的日志路径
# =================================================================================
[DEFAULT]
# --- 全局默认设置 ---
# 这些设置将应用于所有未明确覆盖它们的 "Jail" (监狱)。
# 忽略的 IP 地址,这些 IP 永远不会被封禁。
# 127.0.0.1/8 是本机回环地址,::1 是 IPv6 的本机回环地址。建议将您自己的固定 IP 也加入此列表。
ignoreip = 127.0.0.1/8 ::1 你的可信ip_1 你的可信ip_2
# 默认封禁时长。单位可以是 s(秒), m(分钟), h(小时), d(天), w(周)。这里是 1 天。
bantime = 1d
# 查找时间窗口。Fail2ban 会在此时间段内统计客户端的失败次数。这里是 10 分钟。
findtime = 10m
# 最大重试次数。在 `findtime` 时间窗口内,如果失败次数达到此值,客户端 IP 将被封禁。这里是 5 次。
# 结合上面的 findtime,意味着“10分钟内失败5次”。
maxretry = 5
# 触发封禁时执行的动作。%(action_)s 是一个变量,通常指向默认的封禁动作(如 iptables-multiport)。
action = %(action_)s
# 对于 Debian 或 Ubuntu 并且你希望它和 UFW 集成 请删除 banaction = ufw 的注释
# banaction = ufw
# =================================================================================
# JAILS (监狱) - 职责明确,策略清晰
# 每个 [section] 都是一个独立的 "监狱",用于监控一种特定的服务或攻击行为。
# =================================================================================
# --- 基础安全 (SSH) ---
[sshd]
# 是否启用此监狱。true 为启用,false 为禁用。
enabled = true
# SSH 服务的端口号。 【重要】请务必修改为您服务器上实际的 SSH 端口!
port = 22
# 覆盖默认的 maxretry。SSH 是核心服务,策略更严格,3次失败就封禁。
maxretry = 3
# 覆盖默认的 bantime。对于攻击 SSH 的 IP,封禁更长时间,这里是 1 周。
bantime = 1w
# --- Nginx 核心防护:恶意扫描器 ---
# 监控并阻止常见的目录扫描、漏洞扫描工具。
[nginx-pro-scanner]
enabled = true
# 监控的端口,http (80) 和 https (443)。
port = http,https
# 使用的过滤器规则文件名 (位于 /etc/fail2ban/filter.d/nginx-pro-scanner.conf)。【注意】此为自定义过滤器。
filter = nginx-pro-scanner
# 监控的 Nginx 日志文件路径。【重要】此路径通常用于宝塔面板,请根据您的实际情况修改。
logpath = /www/wwwlogs/*.log
# --- Nginx 核心防护:恶意机器人与脚本 ---
# 监控并阻止已知的恶意 User-Agent 或爬虫。
[nginx-badbots]
enabled = true
port = http,https
# 使用的过滤器规则文件名 (位于 /etc/fail2ban/filter.d/nginx-badbots.conf)。【注意】此为自定义过滤器。
filter = nginx-badbots
logpath = /www/wwwlogs/*.log
# 策略非常严格,只要匹配到 1 次就封禁。
maxretry = 1
# 时间窗口缩短到 1 分钟,反应更迅速。
findtime = 1m
# 封禁 1 周。
bantime = 1w
# --- Nginx 核心防护:SQL注入 & XSS 攻击尝试 ---
# 监控 URL 或请求体中包含的典型 SQLi 和 XSS 攻击代码。
[nginx-sqli-xss]
enabled = true
port = http,https
# 使用的过滤器规则文件名 (位于 /etc/fail2ban/filter.d/nginx-sqli-xss.conf)。【注意】此为自定义过滤器。
filter = nginx-sqli-xss
logpath = /www/wwwlogs/*.log
# 策略严格,5 分钟内尝试 2 次就封禁。
maxretry = 2
findtime = 5m
# 封禁 1 周。
bantime = 1w
# --- Nginx 辅助防护:畸形请求 (4xx 错误) ---
# 监控产生大量 4xx 客户端错误(如 404 Not Found, 403 Forbidden)的 IP。
[nginx-4xx-errors]
enabled = true
port = http,https
# 使用的过滤器规则文件名 (位于 /etc/fail2ban/filter.d/nginx-4xx-errors.conf)。【注意】此为自定义过滤器。
filter = nginx-4xx-errors
logpath = /www/wwwlogs/*.log
# 策略相对宽松,允许一定程度的错误,防止误封正常用户。5 分钟内 15 次 4xx 错误才封禁。
maxretry = 15
findtime = 5m
# 封禁时间较短,6 小时,因为误封的可能性相对较高。
bantime = 6h
# --- Nginx 辅助防护:HTTP Basic Auth 爆破 ---
# 监控 Nginx 的 HTTP 基本认证失败日志。
[nginx-http-auth]
enabled = true
# 【最终修正】为保证服务稳定启动,只监控最核心且确定存在的 nginx_error.log。
# HTTP 认证失败通常记录在错误日志中,而不是访问日志。
logpath = /www/wwwlogs/nginx_error.log
# 3 次认证失败就封禁。
maxretry = 3
# 封禁 1 周。
bantime = 1w
# --- 累犯加重处罚规则 (Recidive) ---
# 这是一个特殊的“元监狱”,它不监控服务日志,而是监控 Fail2ban 自己的日志。
# 用来惩罚那些在短时间内被多次封禁的“惯犯” IP。
[recidive]
enabled = true
# 监控 Fail2ban 自己的日志文件。路径在各系统上可能不同,但 /var/log/fail2ban.log 是最常见的。
logpath = /var/log/fail2ban.log
# 执行更严厉的封禁动作,通常是封禁所有端口 (allports),而不仅仅是触发的那个端口。
action = %(banaction_allports)s
# 时间窗口为 1 天。
findtime = 1d
# 如果一个 IP 在 1 天内被其他任何监狱封禁了 3 次...
maxretry = 3
# ...那么它将被这个监狱处以更长的封禁时间:2 周,并且是所有端口。
bantime = 2w

步骤 2.5: 创建一个全新的、更强大的 Nginx 过滤器#

创建一个新文件 /etc/fail2ban/filter.d/nginx-pro-scanner.conf,并将以下内容完整复制进去:

[Definition]
# 匹配各种恶意扫描行为,状态码可以是 3xx, 4xx
failregex = ^<HOST> .* "(GET|POST) .*/\.(git|env|svn|htpasswd|sql|bak|conf|ini|rar|zip|tgz|gz|bz2)[^"]*" (30|40)\d .*
^<HOST> .* "(GET|POST) .*/(phpmyadmin|pma|admin|db|mysql|websql|backup|dump)[^"]*" (30|40)\d .*
^<HOST> .* "(GET|POST) .*/(wp-admin|wp-login|wp-content|wp-includes|wordpress|wp)[^"]*" (30|40)\d .*
^<HOST> .* "(GET|POST) /xmlrpc\.php" (30|40)\d .*
^<HOST> .* "(GET|POST) /vendor/phpunit/phpunit/src/Util/PHP/eval-stdin\.php" (30|40)\d .*
^<HOST> .* "GET .*\?phpinfo=.*" .*
^<HOST> .* "GET .*/(console|invokefunction|api/jsonws/invoke)" .*
ignoreregex =

创建一个新文件 /etc/fail2ban/filter.d/nginx-badbots.conf,并将以下内容完整复制进去:

[Definition]
# User-Agent 黑名单,不区分大小写 (?i)
# 包含常见扫描工具、脚本语言、某些过于激进的爬虫
failregex = ^<HOST> .* "(?i).*(Go-http-client|AhrefsBot|SemrushBot|MegaIndex|BLEXBot|DotBot|Nmap|masscan|zgrab|sqlmap|nikto|python-requests|curl|wget|scan|spider|bot|crawler).*"$
^<HOST> .* "-" "-"$
# 忽略主流搜索引擎爬虫,防止误伤
ignoreregex = (?i).*(googlebot|bingbot|baidu|slurp|duckduckbot|applebot|yandex|facebookexternalhit)

创建一个新文件 /etc/fail2ban/filter.d/nginx-sqli-xss.conf,并将以下内容完整复制进去:

[Definition]
# 解码后的URL中包含SQL注入或XSS攻击的典型关键字
# (?i) 不区分大小写,\s 代表空格
failregex = ^<HOST> .* "(?i).*(union\s*select|select.*from|insert\s*into|<\s*script>|%%3Cscript%%3E|<\s*img|onmouseover|javascript:).*" .*
ignoreregex =

创建一个新文件 /etc/fail2ban/filter.d/nginx-4xx-errors.conf,并将以下内容完整复制进去:

[Definition]
# 捕获返回 4xx 客户端错误的请求,例如 400, 403, 404, 405 等
failregex = ^<HOST> -.*- .* 4\d\d .*
# 忽略对 favicon.ico 和 robots.txt 的 404 请求,这些很常见
ignoreregex = .*(GET|HEAD) /(favicon.ico|robots.txt) .*

3. 生效与验证#

配置完成后,必须重启服务才能让新配置生效。

步骤 3.1: 重启 Fail2ban 服务#

Terminal window
# 重启服务以加载 jail.local 中的新配置
sudo systemctl restart fail2ban

步骤 3.2: 验证规则是否加载成功#

使用 fail2ban-client 工具检查所有规则(Jail)是否已成功加载并运行。

Terminal window
# 查看 Fail2ban 整体状态
sudo fail2ban-client status

成功标志:在输出的 Jail list 中,能看到您在 jail.local 里启用了 enabled = true 的所有规则名称,例如 sshd, nginx-bad-requests 等。

常见问题:如果发现某个自定义的 Jail (如 nginx-bad-requests) 没有出现在列表中,通常是因为缺少 filter 定义。请返回 jail.local 文件,在该 Jail 段落中添加一行 filter = nginx-botsearch


4. 日常管理与维护#

4.1 查看封禁状态#

查看特定规则的封禁IP(最常用)#

Terminal window
# 查看 SSH 服务的封禁列表
sudo fail2ban-client status sshd
# 查看核心漏洞扫描(最常用)
sudo fail2ban-client status nginx-pro-scanner
# 查看恶意机器人封禁列表
sudo fail2ban-client status nginx-badbots
# 看 SQL 注入 / XSS 攻击尝试
sudo fail2ban-client status nginx-sqli-xss
# 看“骚扰型”扫描
sudo fail2ban-client status nginx-4xx-errors

关键信息:在输出结果中查找 Banned IP list,后面就是被封禁的IP地址。

查看所有规则的封禁IP(概览)#

Terminal window
# 使用一行命令遍历并显示所有已启用规则的状态
sudo fail2ban-client status | grep "Jail list:" | sed -e 's/.*Jail list:[ \t]*//' -e 's/,//g' | xargs -n1 sudo fail2ban-client status

4.2 手动解封 IP#

如果您需要解封某个IP(例如误封了自己或合作伙伴的IP)。

Terminal window
# 命令格式: sudo fail2ban-client set <规则名> unbanip <要解封的IP>
# 示例:解封被 sshd 规则封禁的IP 123.123.123.123
sudo fail2ban-client set sshd unbanip 123.123.123.123

4.3 紧急情况处理:解救被锁在外的自己#

如果您不慎被封禁,无法通过SSH登录,请按以下步骤操作。

  1. 通过服务商后台登录:使用云服务商提供的 VNC 控制台网页版紧急终端 登录服务器。这是您的“救命稻草”,可以绕过网络防火墙。
  2. 执行解封命令:在VNC控制台中,执行 4.2 中的解封命令。
  3. 终极手段:如果解封命令不奏效,可以临时停止Fail2ban服务。服务停止时,它会自动移除所有防火墙封禁规则。
    Terminal window
    # 临时停止服务,所有封禁会立即解除
    sudo systemctl stop fail2ban
    成功通过SSH登录后,别忘了回来把服务重新启动:
    Terminal window
    sudo systemctl start fail2ban

5. 核心概念回顾#

  • 工作原理:监控日志 -> 匹配模式 -> 执行动作 (Ban)。
  • 封禁机制:Fail2ban 自身不拦截流量,而是通过调用系统防火墙 (firewalld/iptables) 来添加/删除规则以实现IP的封禁和解封。
  • 封禁记录位置:实时记录在内存中,历史记录在 /var/lib/fail2ban/fail2ban.sqlite3 数据库中,实际拦截规则在防火墙中。
  • 黄金法则永远只修改 jail.local 文件,保持 jail.conf 的原始状态。

6. 常见问题与故障排查 (Troubleshooting)#

本章节记录了在使用 Fail2ban 过程中可能遇到的常见问题及其解决方案。

问题一:修改配置并重启后,Fail2ban 启动失败#

症状 (Symptom)#

在你修改了任何 .conf.local 文件并执行 sudo systemctl restart fail2ban 后,所有 fail2ban-client 命令都返回错误:

ERROR Failed to access socket path: /var/run/fail2ban/fail2ban.sock. Is fail2ban running?

这表明 Fail2ban 主服务在启动过程中遇到了致命错误,导致启动失败。

诊断 (Diagnosis)#

要找出根本原因,我们需要查看 Fail2ban 的详细启动日志。执行以下命令:

Terminal window
sudo journalctl -xeu fail2ban

请重点关注日志末尾的红色错误信息。最常见的一个错误是:

ERROR Failed during configuration: Have not found any log file for recidive jail

错误原因:这个错误意味着 [recidive] 监狱需要监控的日志文件 /var/log/fail2ban.log 不存在。在很多系统的默认安装中,这个文件并不会被自动创建。当 Fail2ban 严格重启并加载配置时,找不到这个依赖文件,就会导致整个服务启动失败。

解决方案 (Solution)#

我们只需要手动创建这个空的日志文件,然后再次重启服务即可。

Terminal window
# 步骤 1: 手动创建空的日志文件
sudo touch /var/log/fail2ban.log
# 步骤 2: 再次重启 Fail2ban 服务
sudo systemctl restart fail2ban

最佳实践:为了从根源上避免此问题,建议在任何新服务器上安装完 Fail2ban 后,立即执行 sudo touch /var/log/fail2ban.log 作为初始化步骤的一部分。


7. 高级应用案例:豁免特定应用流量 (如 X-UI 面板)#

场景 (Scenario)#

我们强大而严格的 [nginx-badbots] 规则,可能会“误伤”一些行为类似脚本的正常应用。例如,X-UI 面板的 VLESS 等协议,其客户端的 User-Agent 可能是 Go-http-client,这会被我们的规则识别为恶意机器人并立即封禁。

当你的 IP 地址是动态变化的,使用 ignoreip 白名单不再可行。此时,我们需要创建一条精准的豁免规则。

解决方案:通过 ignoreregex 豁免特定 URL 路径#

我们的策略是:不降低整体安全性,仅为这些特殊应用的合法流量打开一个“特殊通道”。

操作步骤

  1. 编辑 nginx-badbots 过滤器文件:
    Terminal window
    sudo nano /etc/fail2ban/filter.d/nginx-badbots.conf
  2. 找到 ignoreregex 这一行,并在末尾添加对你特定路径的豁免。

案例 A: 豁免单个路径#

如果你的 VLESS 流量都通过 /bwgx 这个路径,你需要将 ignoreregex 修改为:

# 注意末尾用 | 分隔,并添加了 GET /your_path HTTP 的模式
ignoreregex = (?i).*(googlebot|bingbot|baidu|slurp|duckduckbot|applebot|yandex|facebookexternalhit)|GET /bwgx HTTP

这行规则的意思是:忽略主流搜索引擎,或者忽略所有访问 /bwgx 路径的请求。


案例 B: 豁免多个路径#

如果你有多个路径需要豁免,例如 /bwgx, /bwgv, 和 /wyf,你需要使用 () 进行分组,并用 | 分隔:

# 使用 (path1|path2|...) 的格式来豁免多个路径
ignoreregex = (?i).*(googlebot|bingbot|baidu|slurp|duckduckbot|applebot|yandex|facebookexternalhit)|GET /(bwgx|bwgv|bwgo) HTTP

这个 (bwgx|bwgv|bwgo) 正则表达式会匹配这三个路径中的任意一个。


最后一步:修改完过滤器后,务必重启 Fail2ban 以使新规则生效。

Terminal window
sudo systemctl restart fail2ban
Fail2ban 安装与使用终极笔记
https://blog.wlens.top/posts/fail2ban-安装与使用终极笔记/
作者
Lao Wang
发布于
2025-10-14
许可协议
CC BY-NC-SA 4.0