fail2ban 使用详解

fail2ban 是一款用 Python 编写的入侵防御软件。它通过扫描日志文件(如 /var/log/auth.log)识别多次认证失败的 IP,然后动态更新防火墙规则(如 iptables、nftables)来临时或永久封禁该 IP,有效对抗暴力破解和恶意扫描。当前版本 v1.1.x。

工作原理

fail2ban 由三个核心概念组成:

  • Jail(监狱):一组规则单元,包含一个 Filter 和一个或多个 Action。
  • Filter(过滤器):用正则表达式从日志中提取失败尝试和 IP 地址。
  • Action(动作):定义封禁(ban)与解封(unban)时要执行的命令,如修改 iptables 规则或发送邮件告警。

工作流程:日志文件 → Filter 匹配 → 计数(findtime 内 maxretry 次) → Action 封禁(bantime 时长) → 到期后自动解封。

安装

fail2ban 已包含在大多数 Linux 发行版仓库中,按发行版选择对应命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Debian / Ubuntu
sudo apt update
sudo apt install fail2ban

# CentOS / RHEL / Rocky / AlmaLinux(需先启用 EPEL)
sudo dnf install epel-release
sudo dnf install fail2ban

# 老版本 CentOS 7
sudo yum install epel-release
sudo yum install fail2ban

# Fedora
sudo dnf install fail2ban

# Arch Linux / Manjaro
sudo pacman -S fail2ban

# openSUSE / SLES
sudo zypper install fail2ban

# Alpine Linux
sudo apk add fail2ban

从源码安装(需要 Python 3.6+):

1
2
3
git clone https://github.com/fail2ban/fail2ban.git
cd fail2ban
sudo pip install .

注意:旧教程中的 python setup.py install 在 Python 3.12+ 已被移除,请改用 pip install .。生产环境建议优先使用发行版仓库版本,源码安装仅用于尝鲜新特性。

安装后验证:

1
2
fail2ban-client -h
fail2ban-client --version

Debian / Ubuntu 安装后会自动在 jail.d/ 下生成 debian.conf(或 ubuntu.conf),其中只启用了 sshd jail。若系统未安装 SSH 服务,需要手动跳过相关配置,否则服务可能启动失败。

配置文件结构

fail2ban 的配置文件位于 /etc/fail2ban/:

1
2
3
4
5
6
7
8
/etc/fail2ban/
├── fail2ban.conf # 全局配置(日志级别、socket)
├── fail2ban.d/ # 全局配置补充
├── jail.conf # 监狱定义(默认配置,不应直接修改)
├── jail.d/ # 自定义监狱配置(推荐)
├── jail.local # 本地覆盖(优先级高于 jail.conf)
├── filter.d/ # 过滤器定义(sshd.conf、apache-auth.conf 等)
└── action.d/ # 动作定义(iptables、nftables、mail 等)

持久化数据库默认位于 /var/lib/fail2ban/fail2ban.sqlite3,用于保存封禁记录与日志读取位置。

重要原则:直接在 jail.conf 中修改会导致升级时被覆盖。推荐做法是在 jail.local 或 jail.d/*.local 中只写需要改动的配置项,其余继承自 .conf 文件。

配置文件的加载顺序(后面的覆盖前面的):

  1. jail.conf
  2. jail.d/*.conf(按字母序)
  3. jail.local
  4. jail.d/*.local(按字母序)

全局配置(fail2ban.conf)

/etc/fail2ban/fail2ban.conf 控制 fail2ban 守护进程自身行为:

1
2
3
4
5
6
7
[Definition]
loglevel = INFO
logtarget = /var/log/fail2ban.log
socket = /var/run/fail2ban/fail2ban.sock
pidfile = /var/run/fail2ban/fail2ban.pid
dbfile = /var/lib/fail2ban/fail2ban.sqlite3
dbpurgeage = 86400
  • loglevel:CRITICAL、ERROR、WARNING、NOTICE、INFO、DEBUG、TRACEDEBUG、HEAVYDEBUG
  • dbpurgeage:数据库中的封禁记录保留时间(秒),默认 86400(24 小时)

创建监狱(Jail)

基础 SSH 保护

创建 /etc/fail2ban/jail.local:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[DEFAULT]
# 默认封禁时间
bantime = 1h
# 查找时间窗口
findtime = 10m
# 在此窗口内失败 maxretry 次则封禁
maxretry = 5
# 忽略自身 IP 和信任的 IP 段
ignoreip = 127.0.0.1/8 ::1

[sshd]
enabled = true
port = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s

如果 SSH 端口不是默认的 22,需修改 port:

1
2
3
[sshd]
enabled = true
port = 2222

常用内置 jail

fail2ban 自带大量预配置 jail,在 jail.conf 中默认被 enabled = false,在 jail.local 中启用即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[sshd]
enabled = true

[apache-auth]
enabled = true
logpath = /var/log/apache*/*error.log

[nginx-http-auth]
enabled = true
logpath = /var/log/nginx/error.log

[nginx-botsearch]
enabled = true
logpath = /var/log/nginx/access.log

[postfix-sasl]
enabled = true
logpath = /var/log/mail.log

自定义 jail

1
2
3
4
5
6
7
8
9
[my-custom-jail]
enabled = true
filter = my-custom-filter
logpath = /var/log/myapp/error.log
port = 3000
maxretry = 3
findtime = 5m
bantime = 24h
action = iptables-multiport[name=myapp, port="3000"]

常用命令(fail2ban-client)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 启动 / 停止 / 重启服务
sudo systemctl start fail2ban
sudo systemctl stop fail2ban
sudo systemctl restart fail2ban

# 查看 fail2ban 状态
sudo fail2ban-client status

# 查看指定 jail 的封禁状态
sudo fail2ban-client status sshd

# 手动封禁一个 IP
sudo fail2ban-client set sshd banip 192.168.1.100

# 手动解封一个 IP
sudo fail2ban-client set sshd unbanip 192.168.1.100

# 查看封禁列表
sudo fail2ban-client status sshd

# 重新加载所有配置(不中断已有封禁)
sudo fail2ban-client reload

# 重新加载指定 jail
sudo fail2ban-client reload sshd

# 查看日志尾部
sudo tail -f /var/log/fail2ban.log

status sshd 的典型输出:

1
2
3
4
5
6
7
8
9
Status for the jail: sshd
|- Filter
| |- Currently failed: 2
| |- Total failed: 137
| `- File list: /var/log/auth.log
`- Actions
|- Currently banned: 1
|- Total banned: 12
`- Banned IP list: 203.0.113.45

其中 Currently failed 是当前统计窗口内的失败次数,Banned IP list 就是已封禁的 IP。

过滤器(Filter)

过滤器定义在 /etc/fail2ban/filter.d/ 中,用正则表达式识别日志中的失败尝试并提取 IP。

内置过滤器示例(sshd.conf)

1
2
3
4
[Definition]
failregex = ^%(__prefix_line)s(?:error: PAM: )?Authentication failure for .* from <HOST>\s*$
^%(__prefix_line)s(?:error: PAM: )?User .+ from <HOST> not allowed because not listed in AllowUsers\s*$
ignoreregex =

关键标签:

  • <HOST>:匹配 IP 地址或主机名
  • <ADDR>:匹配 IP 地址
  • <F-USER>...</F-USER>:提取用户名
  • <F-ID>...</F-ID>:提取标识符用于封禁(替代 IP)

测试过滤器

用 fail2ban-regex 工具测试正则表达式是否匹配日志:

1
sudo fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf

或直接指定正则:

1
sudo fail2ban-regex /var/log/auth.log "Authentication failure for .* from <HOST>"

自定义过滤器

创建 /etc/fail2ban/filter.d/myapp.conf:

1
2
3
[Definition]
failregex = ^.*ERROR: Failed login from <HOST> for user <F-USER>\S+</F-USER>\s*$
ignoreregex = ^.*DEBUG.*$

动作(Action)

动作定义在 /etc/fail2ban/action.d/ 中,指定封禁/解封时执行的命令。

常用内置动作

  • iptables-multiport:基于 iptables 的多端口封禁
  • nftables-multiport:基于 nftables(新版防火墙)
  • ufw:使用 UFW 封禁
  • mail-whois:封禁时发送含 whois 信息的邮件
  • firewallcmd-ipset:使用 firewalld + ipset

如何选择防火墙动作

先确认系统实际使用的防火墙,再选对应动作,否则封禁命令会失效:

1
2
3
4
5
# 判断当前防火墙类型
sudo systemctl is-active firewalld
sudo systemctl is-active ufw
sudo nft list ruleset > /dev/null 2>&1 && echo "nftables available"
sudo iptables -L -n | head -5
系统防火墙 推荐动作
原生 iptables iptables-multiport 或 iptables-ipset-proto6
nftables nftables-multiport
Ubuntu/Debian + UFW ufw
CentOS/RHEL + firewalld firewallcmd-ipset

新版 Ubuntu / Debian 已默认使用 nftables 后端,但 iptables 命令仍可通过兼容层工作,因此 iptables-multiport 通常仍可用。

动作配置示例

1
2
3
4
[sshd]
enabled = true
action = iptables-multiport[name=sshd, port="ssh", protocol=tcp]
mail-whois[name=sshd, [email protected], [email protected]]

后台监控方式(Backend)

fail2ban 支持多种日志监控后端,通过 backend 配置:

  • pyinotify:Linux 内核 inotify 机制,实时高效(推荐 Linux)
  • systemd:直接从 systemd journal 读取,不依赖日志文件
  • polling:轮询方式,兼容性最好但效率最低
  • auto:自动选择(默认)

systemd 后端示例:

1
2
3
4
[sshd]
enabled = true
backend = systemd
journalmatch = _SYSTEMD_UNIT=sshd.service + _COMM=sshd

journalmatch 语法与 journalctl 一致。

时间格式

fail2ban 配置中的时间值(bantime、findtime)接受易读格式:

1
2
3
4
5
6
bantime = 1h        # 1 小时
findtime = 10m # 10 分钟
bantime = 1d # 1 天
bantime = 1w # 1 周
bantime = 30s # 30 秒
bantime = 1y 6mo # 1 年 6 个月

支持单位:y(年)、mo(月)、w(周)、d(天)、h(小时)、m(分钟)、s(秒)。用 fail2ban-client --str2sec 测试:

1
fail2ban-client --str2sec 1d12h

数据库持久化

fail2ban 默认使用 SQLite 数据库(/var/lib/fail2ban/fail2ban.sqlite3)持久化封禁记录和日志读取位置。重启服务后:

  • 当前封禁自动恢复生效
  • 日志文件从上次读取位置继续追踪
  • 不重复处理已读过的内容

若需彻底清空所有状态:

1
2
3
sudo systemctl stop fail2ban
sudo rm /var/lib/fail2ban/fail2ban.sqlite3
sudo systemctl start fail2ban

实践:保护 SSH 防暴力破解

完整配置示例(/etc/fail2ban/jail.local):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5
ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24
destemail = [email protected]
sender = [email protected]
action = iptables-multiport[name=default, port="ssh"]
mail-whois[name=default, dest=%(destemail)s]

[sshd]
enabled = true
port = ssh
logpath = %(sshd_log)s

[sshd-ddos]
enabled = true
port = ssh
logpath = %(sshd_log)s
maxretry = 3
findtime = 1m
bantime = 24h

sshd-ddos 是一个更严格的辅助 jail,在短时间内检测到 3 次失败就封禁 24 小时,可有效应对高频爆破。注意它并非所有发行版都内置(Debian/Ubuntu 的 jail.conf 中带有),如果启动时报 Found no accessible config files for 'filter.d/sshd-ddos',说明当前版本没有该 jail,需要自行在 jail.local 和 filter.d/ 中定义,或改用更长的 bantime 替代。

实践:封禁频繁扫描的 IP

1
2
3
4
5
6
7
[nginx-botsearch]
enabled = true
port = http,https
logpath = /var/log/nginx/access.log
maxretry = 10
findtime = 1m
bantime = 1d

实践:自定义递归封禁(recidive)

recidive jail 用于封禁已被封禁过的屡犯 IP,设置更长的封禁时间:

1
2
3
4
5
6
[recidive]
enabled = true
logpath = /var/log/fail2ban.log
maxretry = 3
findtime = 1d
bantime = 1w

安全建议

  • 不要依赖 fail2ban 作为唯一安全措施,它只是暴力破解的减速带。
  • 推荐使用 SSH 密钥认证或双因素认证作为主要手段。
  • 定期检查 fail2ban 日志 /var/log/fail2ban.log 关注封禁趋势。
  • 将 maxretry 设为合理值(3~5 次),过低可能导致误封正常用户。
  • 使用 ignoreip 排除信任 IP 段,避免把自己封在外面。
  • 若 SSH 端口暴露在公网,考虑改用非标准端口 + fail2ban 双重防护。
  • 启用 mail-whois 动作,被封禁时收到邮件通知。
  • 配置 logrotate 时注意不要误删 fail2ban 日志,或调整 logtarget 路径。

故障排查

  • fail2ban 未启动:检查 systemctl status fail2ban,查看日志 /var/log/fail2ban.log。
  • 日志不匹配:用 fail2ban-regex 测试过滤正则是否匹配实际日志行。
  • 封禁未生效:确认防火墙规则链存在(iptables -L -n),或检查 action 配置是否正确。
  • IP 未解封:检查数据库是否损坏,可尝试清空数据库后重启。
  • 误封自己:确保 ignoreip 包含自己的 IP 或所在网段。
  • 日志文件轮转:fail2ban 自动处理 logrotate,若发现异常检查 logpath 通配符是否匹配轮转后的文件。

总结

fail2ban 的配置遵循「Filter 匹配日志 → Action 执行封禁」的模型。多数场景只需在 jail.local 中启用内置 jail 并调整 bantime/findtime/maxretry 参数即可。配合 fail2ban-client 监控状态、fail2ban-regex 调试正则,就能高效地防御暴力破解攻击。更多细节参阅 man jail.conf 或 fail2ban 官方文档。