Fail2Ban 工作原理与常用运维操作
Fail2Ban 是 Linux 服务器上很常见的一类安全防护工具,主要用来应对 SSH、Web 登录、邮件服务等场景里的暴力破解和重复异常请求。它不会替代防火墙、密钥登录、最小权限这些基础安全措施,但非常适合做一层自动化封禁:发现某个 IP 在短时间内频繁失败,就把它临时加入黑名单,过一段时间后再自动释放。
这篇记录一下 Fail2Ban 的工作原理、安装和开机启动方式、常用规则配置,以及误封后如何把某个 IP 从黑名单里移出来。
Fail2Ban 的工作原理#
Fail2Ban 的核心逻辑可以概括成四步:
- 监听日志文件或 systemd journal。
- 用 filter 里的正则表达式匹配失败行为。
- 在指定时间窗口内统计同一个 IP 的失败次数。
- 达到阈值后执行 action,把 IP 加入防火墙黑名单。
这里有几个关键概念。
jail#
jail 是 Fail2Ban 的规则单元。一个 jail 通常对应一个服务,例如 SSH、Nginx、Postfix、Dovecot 等。每个 jail 会指定:
- 监控哪个服务。
- 读取哪个日志。
- 使用哪个 filter。
- 允许失败多少次。
- 统计时间窗口是多少。
- 封禁多久。
- 使用什么 action 封禁 IP。
例如 SSH 的 jail 就是监听 SSH 登录日志,匹配登录失败记录,当同一个 IP 在一段时间内失败太多,就通过防火墙封禁。
filter#
filter 负责识别“什么日志算失败”。它通常放在:
/etc/fail2ban/filter.d/
例如 SSH 常见 filter 是:
/etc/fail2ban/filter.d/sshd.conf
filter 文件里最重要的是 failregex,也就是匹配失败日志的正则表达式。Fail2Ban 会从日志行里提取 IP,并把它计入失败次数。
一般情况下,SSH、Nginx、Apache、Postfix 等常见服务已经有内置 filter,不建议一上来就自己写正则。只有业务日志格式比较特殊时,才需要自定义 filter。
action#
action 负责“封禁时具体做什么”。常见动作包括:
- 使用
iptables添加规则。 - 使用
nftables添加规则。 - 使用
firewalld添加规则。 - 发送邮件通知。
- 执行自定义脚本。
在现代 Linux 发行版里,很多系统默认已经转向 nftables,但 Fail2Ban 仍然可以通过不同 action 适配不同防火墙后端。
bantime、findtime、maxretry#
Fail2Ban 最常调的三个参数是:
bantime = 1h
findtime = 10m
maxretry = 5
它们的意思是:
findtime:统计窗口。比如 10 分钟内。maxretry:最大失败次数。比如失败 5 次。bantime:封禁时间。比如封禁 1 小时。
合起来就是:同一个 IP 在 10 分钟内失败 5 次,就封禁 1 小时。
Fail2Ban 支持比较直观的时间写法,例如:
10m
1h
1d
也可以直接写秒数。
安装 Fail2Ban#
Debian / Ubuntu:
sudo apt update
sudo apt install -y fail2ban
RHEL / CentOS / Rocky Linux / AlmaLinux:
sudo dnf install -y epel-release
sudo dnf install -y fail2ban
有些较老系统使用 yum:
sudo yum install -y epel-release
sudo yum install -y fail2ban
安装完成后确认版本:
fail2ban-client version
启动和开机自启#
Fail2Ban 通常由 systemd 管理。启动服务:
sudo systemctl start fail2ban
设置开机自启:
sudo systemctl enable fail2ban
也可以合并成一条:
sudo systemctl enable --now fail2ban
查看服务状态:
sudo systemctl status fail2ban
确认是否开机自启:
systemctl is-enabled fail2ban
如果输出是:
enabled
说明已经设置为开机启动。
配置文件应该怎么改#
Fail2Ban 的主配置文件通常是:
/etc/fail2ban/jail.conf
但不建议直接修改 jail.conf。因为软件升级时它可能被覆盖。推荐做法是使用:
/etc/fail2ban/jail.local
或者拆成多个文件放到:
/etc/fail2ban/jail.d/*.conf
推荐结构是:
/etc/fail2ban/jail.local
/etc/fail2ban/jail.d/sshd.local
/etc/fail2ban/jail.d/nginx.local
小型服务器可以只用 jail.local,规则多了以后再拆到 jail.d/。
一个基础的 jail.local 示例#
可以创建或编辑:
sudo vim /etc/fail2ban/jail.local
写入:
[DEFAULT]
ignoreip = 127.0.0.1/8 ::1
bantime = 1h
findtime = 10m
maxretry = 5
backend = systemd
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = %(sshd_log)s
maxretry = 5
这里的含义是:
[DEFAULT]是全局默认配置。ignoreip是永远不封禁的 IP 或网段。backend = systemd表示从 systemd journal 读取日志。[sshd]是 SSH 服务的 jail。enabled = true表示启用这条规则。filter = sshd表示使用内置的 SSH filter。
如果系统不是通过 journal 读取 SSH 日志,也可以使用传统日志路径。例如 Debian / Ubuntu 常见是:
logpath = /var/log/auth.log
RHEL 系常见是:
logpath = /var/log/secure
具体以系统实际日志位置为准。
配置 SSH 防爆破规则#
SSH 是最常见的 Fail2Ban 使用场景。一个稍严格一点的配置可以这样写:
[sshd]
enabled = true
port = ssh
filter = sshd
backend = systemd
maxretry = 4
findtime = 10m
bantime = 2h
这表示同一个 IP 在 10 分钟内 SSH 登录失败 4 次,就封禁 2 小时。
如果 SSH 使用了非默认端口,可以写成:
port = 2222
或者多个端口:
port = ssh,2222
不过更推荐配合 SSH 自身安全策略一起做:
- 禁止 root 密码登录。
- 优先使用密钥登录。
- 关闭不需要的账号。
- 限制安全组或防火墙来源。
- Fail2Ban 作为自动封禁补充。
配置 Nginx 登录失败规则#
如果 Nginx 后面有登录接口,并且日志里会出现明确的 401、403 或业务失败特征,可以启用或自定义 Nginx 规则。
常见内置规则包括:
[nginx-http-auth]
enabled = true
port = http,https
logpath = /var/log/nginx/error.log
maxretry = 5
findtime = 10m
bantime = 1h
这个规则主要用于 HTTP Basic Auth 失败。
如果是自己的业务登录接口,通常需要自定义 filter。比如创建:
sudo vim /etc/fail2ban/filter.d/app-login.conf
示例:
[Definition]
failregex = ^.*login failed.*client=<HOST>.*$
ignoreregex =
然后在 jail 里引用:
[app-login]
enabled = true
port = http,https
filter = app-login
logpath = /var/log/myapp/login.log
maxretry = 5
findtime = 10m
bantime = 1h
这里的重点不是照抄正则,而是确保业务日志里真的有稳定的失败标识和客户端 IP。否则可能匹配不到,也可能误封。
检查配置是否有效#
修改配置后,先检查配置是否能被加载:
sudo fail2ban-client -d
这个命令会输出 Fail2Ban 解析后的配置。它比较长,但适合排查配置是否生效。
重启服务:
sudo systemctl restart fail2ban
查看服务状态:
sudo systemctl status fail2ban
查看 Fail2Ban 日志:
sudo journalctl -u fail2ban -e
或者:
sudo tail -f /var/log/fail2ban.log
不同系统日志位置可能不同,以实际环境为准。
查看当前启用的 jail#
使用:
sudo fail2ban-client status
输出类似:
Status
|- Number of jail: 1
`- Jail list: sshd
查看某个 jail 的详细状态:
sudo fail2ban-client status sshd
输出里通常会看到:
Currently failed
Total failed
Currently banned
Total banned
Banned IP list
其中 Banned IP list 就是当前被封禁的 IP 列表。
手动封禁某个 IP#
有时发现某个 IP 明显异常,可以手动加入某个 jail:
sudo fail2ban-client set sshd banip 203.0.113.10
这里的 sshd 是 jail 名称,203.0.113.10 是示例 IP。实际使用时替换成目标 IP。
封禁后查看:
sudo fail2ban-client status sshd
将某个 IP 移出黑名单#
如果误封了自己的 IP,或者确认某个 IP 已经不需要继续封禁,可以用 unbanip 移除。
例如从 SSH jail 里移除:
sudo fail2ban-client set sshd unbanip 203.0.113.10
再查看状态:
sudo fail2ban-client status sshd
如果不确定 IP 是被哪个 jail 封禁的,可以先查看全部 jail:
sudo fail2ban-client status
然后逐个查看:
sudo fail2ban-client status sshd
sudo fail2ban-client status nginx-http-auth
sudo fail2ban-client status app-login
找到对应 jail 后再执行 unbanip。
一次性移除某个 jail 的所有封禁#
如果确认要清空某个 jail 的封禁列表,可以执行:
sudo fail2ban-client unban --all
不过这会解除所有 jail 的封禁,影响范围比较大。更稳妥的方式还是针对某个 IP 做 unbanip。
部分版本也支持针对 jail 操作,具体可以先查看帮助:
fail2ban-client --help
生产环境里不要随手全量解封,除非确认封禁规则本身配置错了。
白名单设置#
如果有固定办公出口 IP、堡垒机 IP、监控机 IP,可以加入 ignoreip,避免被误封。
示例:
[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 192.0.2.10 198.51.100.0/24
修改后重启:
sudo systemctl restart fail2ban
注意:已经被封禁的 IP,不一定会因为加入 ignoreip 立刻自动解封。稳妥做法是配置白名单后,再手动执行一次 unbanip。
常见排查思路#
jail 没有启动#
先看状态:
sudo fail2ban-client status
如果 jail list 里没有目标 jail,检查:
- 配置文件是否放在正确位置。
- jail 里是否写了
enabled = true。 - 配置语法是否有错。
- 服务是否已经重启。
一直没有封禁#
检查几个方向:
logpath是否正确。backend是否适合当前系统。- filter 正则是否能匹配日志。
- 失败次数是否达到
maxretry。 - 时间窗口是否落在
findtime内。
可以用 fail2ban-regex 测试日志和 filter 是否匹配:
sudo fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf
如果使用 systemd backend,也可以先确认 journal 里确实有相关日志:
sudo journalctl -u ssh -e
sudo journalctl -u sshd -e
不同发行版服务名可能是 ssh 或 sshd。
误封频繁#
如果误封比较多,可以适当放宽:
maxretry = 8
findtime = 10m
bantime = 30m
也可以把可信 IP 加到 ignoreip。如果是业务登录接口误封,优先检查 filter 正则是否过宽。
防火墙规则没有生效#
检查 action 和系统防火墙后端是否匹配。比如系统使用 nftables,但配置里指定了不合适的 iptables action,就可能出现规则不生效或行为不符合预期。
可以查看当前 action 配置,也可以查看系统防火墙规则:
sudo iptables -S
sudo nft list ruleset
sudo firewall-cmd --list-all
具体使用哪个命令取决于系统防火墙后端。
推荐的基础配置#
如果只是保护 SSH,可以从这个配置开始:
[DEFAULT]
ignoreip = 127.0.0.1/8 ::1
bantime = 1h
findtime = 10m
maxretry = 5
backend = systemd
[sshd]
enabled = true
port = ssh
filter = sshd
maxretry = 5
findtime = 10m
bantime = 1h
如果服务器经常被扫,可以逐步加严:
[sshd]
enabled = true
port = ssh
filter = sshd
maxretry = 4
findtime = 10m
bantime = 6h
如果担心误封,可以先设置短一点的 bantime,观察几天日志,再逐步调整。
生产环境建议#
Fail2Ban 很实用,但不要把它当成唯一安全措施。比较稳妥的组合是:
- SSH 使用密钥登录。
- 禁止 root 远程密码登录。
- 只开放必要端口。
- 安全组或防火墙限制管理入口来源。
- Fail2Ban 自动封禁爆破来源。
- 对业务登录接口做限流、验证码或二次验证。
- 定期查看日志和封禁统计。
Fail2Ban 更像是“自动响应层”。它能降低重复攻击的噪音,也能减少暴力破解带来的风险,但前提是日志可靠、规则准确、防火墙 action 生效。
总结#
Fail2Ban 的工作方式并不复杂:读日志、匹配失败、累计次数、执行封禁。真正需要注意的是规则是否匹配真实日志、封禁动作是否适配当前系统、防误封策略是否合理。
日常使用时,最常用的命令可以记住这几条:
sudo systemctl enable --now fail2ban
sudo fail2ban-client status
sudo fail2ban-client status sshd
sudo fail2ban-client set sshd unbanip 203.0.113.10
sudo journalctl -u fail2ban -e
掌握这些之后,Fail2Ban 就可以作为服务器基础安全配置里很稳定的一环。