Fail2ban:配置防护 SSH 免受密码暴力破解
Fail2ban 读取服务日志,发现重复的失败登录尝试,并通过防火墙临时封锁攻击者的 IP 地址。要保护 SSH,只需安装软件包,创建 /etc/fail2ban/jail.local 文件并写入 [sshd] 段(enabled = true、maxretry、findtime、bantime),然后重启服务;用 fail2ban-client status sshd 检查状态。
Fail2ban 是一个守护进程,它监视服务日志,发现重复的登录失败记录,并临时封锁来源的 IP 地址。对于 SSH 而言,这是防范密码暴力破解最简单的方法:经过几次错误之后,机器人就不会再不停地尝试登录服务器。下面是 fail2ban 配置的完整过程,从安装到检查封禁状态,以及常见错误。
有了 SSH 密钥,为什么还需要 fail2ban
任何开放 22 端口的服务器,几分钟之内就会开始收到机器人的登录尝试。你可以自己看看:
$ sudo journalctl -u ssh --since "1 hour ago" | grep -c "Failed password"
412
如果禁用了密码登录,只允许密钥登录,那么破解访问几乎不可能。但 fail2ban 依然有用:它可以减少日志中的噪音,降低数千次连接带来的负载,并防止配置错误——比如密码登录被意外地保留了下来。它是第二层防护,而不是密钥的替代品。
fail2ban 的工作原理
它由三部分组成:
- 过滤器(filter)——一组正则表达式,用于在日志中找出登录失败的记录,并从中提取 IP 地址。过滤器位于
/etc/fail2ban/filter.d/。 - 动作(action)——对违规者执行的操作:在 iptables、nftables、ufw 或 firewalld 中添加规则。动作位于
/etc/fail2ban/action.d/。 - 监狱(jail)——过滤器、动作、日志来源和阈值的组合。例如,
sshd监狱负责监视 SSH 日志。
如果在 findtime 时间内,同一 IP 的匹配次数达到 maxretry,该地址就会被封禁 bantime 所指定的时长。时间到期后,封禁会自动解除。
安装 fail2ban
在 Debian 和 Ubuntu 上:
sudo apt update
sudo apt install fail2ban
在 RHEL、Rocky、AlmaLinux 上,该软件包位于 EPEL 仓库中:
sudo dnf install epel-release
sudo dnf install fail2ban
启用开机自启并检查服务状态:
sudo systemctl enable --now fail2ban
sudo systemctl status fail2ban
在 Debian 和 Ubuntu 上,SSH 监狱通过 /etc/fail2ban/jail.d/defaults-debian.conf 默认已经启用。在 RHEL 系列中,安装后没有启用任何监狱,需要手动激活。
配置文件存放位置:jail.conf 与 jail.local
主配置文件是 /etc/fail2ban/jail.conf,但不应直接编辑它:软件包更新时会覆盖该文件。自己的设置应放在 /etc/fail2ban/jail.local 中,或者放在单独的 /etc/fail2ban/jail.d/*.local 文件里。fail2ban 按以下顺序读取文件,后面的文件会覆盖前面的设置:
jail.confjail.d/*.confjail.localjail.d/*.local
不要把整个 jail.conf 复制到 jail.local 中——这样会把旧的默认值固定下来。在 jail.local 中只写你需要修改的内容。
SSH 的 fail2ban 配置:最小化的 jail.local
创建文件:
sudo nano /etc/fail2ban/jail.local
并写入以下内容:
[DEFAULT]
# 永远不封禁的自有地址
ignoreip = 127.0.0.1/8 ::1 203.0.113.10
bantime = 1h
findtime = 10m
maxretry = 5
# 日志来源:systemd 日志或文件
backend = systemd
[sshd]
enabled = true
port = ssh
maxretry = 3
重启服务,并确认监狱已经启动:
$ sudo systemctl restart fail2ban
$ sudo fail2ban-client status
Status
|- Number of jail: 1
`- Jail list: sshd
参数说明
| 参数 | 含义 | 示例 |
|---|---|---|
enabled | 是否启用该监狱 | true |
port | 对违规者封锁的端口 | ssh、2222、ssh,2222 |
maxretry | 封禁前允许的错误次数 | 3 |
findtime | 统计错误的时间窗口 | 10m |
bantime | 封禁时长;-1 表示永久 | 1h、1d |
ignoreip | 不会被封禁的地址和子网 | 10.0.0.0/8 |
backend | 日志来源 | systemd、auto |
logpath | 使用文件后端时的日志路径 | /var/log/auth.log |
banaction | 使用哪种防火墙进行封禁 | nftables-multiport、ufw |
时间可以带后缀:s(秒)、m(分)、h(时)、d(天)、w(周)。不带后缀的数字按秒计算。
backend:systemd 还是文件
在较新的 Debian 12 和 Ubuntu 24.04 上,如果没有安装 rsyslog,/var/log/auth.log 文件可能根本不存在:SSH 日志只保存在 systemd 日志中。此时必须使用 backend = systemd,否则 fail2ban 会因找不到日志文件而无法启动。如果安装了 rsyslog,也可以继续使用文件方式:
[sshd]
enabled = true
backend = auto
logpath = /var/log/auth.log
在 RHEL 系统上,对应的文件是 /var/log/secure。
SSH 使用非标准端口
如果 sshd 监听的是 2222 等端口,请在监狱中指定该端口——否则 fail2ban 只会封锁 22 端口,攻击会在 2222 端口上继续进行:
[sshd]
enabled = true
port = 2222
若要对违规者封锁所有端口,可以通过 banaction 使用 iptables-allports 或 nftables-allports 动作。
选择防火墙:iptables、nftables、ufw、firewalld
在 Debian 上默认使用 banaction = nftables(旧版本为 iptables),在 RHEL 上默认使用 firewalld。如果服务器上配置了 ufw,最好让封禁记录也出现在 ufw 中:
[DEFAULT]
banaction = ufw
对于 firewalld:
[DEFAULT]
banaction = firewallcmd-rich-rules
要确认规则确实已添加,可以运行 sudo nft list ruleset | grep f2b 或 sudo iptables -L -n | grep f2b:fail2ban 会创建以 f2b- 为前缀的链。
如何检查运行情况:fail2ban-client status
主要的管理工具是 fail2ban-client。查看某个监狱的状态:
$ sudo fail2ban-client status sshd
Status for the jail: sshd
|- Filter
| |- Currently failed: 2
| |- Total failed: 147
| `- Journal matches: _SYSTEMD_UNIT=sshd.service + _COMM=sshd
`- Actions
|- Currently banned: 4
|- Total banned: 38
`- Banned IP list: 45.148.10.12 92.118.39.7 185.224.128.40 218.92.0.112
从中可以看到当前时间窗口内的错误数量、被封禁的 IP 数量以及具体地址。要实际测试防护效果,可以从另一台机器(而不是 ignoreip 中的那台)用错误的密码多次登录——第三次尝试之后,连接将无法建立。
fail2ban 自身的日志位于 /var/log/fail2ban.log:
$ sudo tail -n 3 /var/log/fail2ban.log
2026-10-14 09:12:41,118 fail2ban.filter [812]: INFO [sshd] Found 218.92.0.112
2026-10-14 09:12:44,302 fail2ban.filter [812]: INFO [sshd] Found 218.92.0.112
2026-10-14 09:12:47,551 fail2ban.actions [812]: NOTICE [sshd] Ban 218.92.0.112
如何在 fail2ban 中解封 IP
如果你把自己或同事封禁了,可以从服务器的控制台(通过托管商的面板或其他 IP)解除封禁:
sudo fail2ban-client set sshd unbanip 203.0.113.25
解除所有监狱中的全部封禁:
sudo fail2ban-client unban --all
无需等待过滤器触发,手动封禁某个地址:
sudo fail2ban-client set sshd banip 198.51.100.7
为避免问题再次发生,请把你的固定地址或办公室子网加入 ignoreip。
对重复违规者延长封禁时间
许多机器人在解封后会立即返回。从 0.11 版本开始,fail2ban 支持为重复违规者逐步延长封禁时间:
[DEFAULT]
bantime = 1h
bantime.increment = true
bantime.factor = 2
bantime.maxtime = 4w
同一 IP 每次被再次封禁,时长都会比上一次更长,但最长不超过四周。旧版本的替代方案是 recidive 监狱:它读取 fail2ban 自身的日志,长时间封锁多次被封禁的地址:
[recidive]
enabled = true
logpath = /var/log/fail2ban.log
bantime = 1w
findtime = 1d
maxretry = 5
检查过滤器:fail2ban-regex
如果监狱已经运行,却没有封禁任何人,请检查过滤器是否能在日志中找到匹配的行。对于文件日志:
sudo fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf
对于 systemd 日志:
sudo fail2ban-regex systemd-journal sshd
在输出中查看 Lines: ... matched 这一行。如果匹配数为零,说明过滤器与日志格式不符,或者指定的来源有误。重启之前,还可以检查整个配置的语法:
sudo fail2ban-client -t
常见错误
- 服务无法启动:“Have not found any log file for sshd jail”。没有
/var/log/auth.log。设置backend = systemd,或安装 rsyslog。 - 状态中有封禁记录,但攻击仍在继续。端口设置错误(SSH 端口已经更改),或者防火墙中有更早的允许规则覆盖了封禁。检查
port以及nft list ruleset的输出。 - 修改没有生效。你修改的是
jail.conf,而jail.local或jail.d/*.local中设置了不同的值。查看最终生效的值:sudo fail2ban-client get sshd maxretry。 - 把自己封禁了。通过控制台解封,并把你的 IP 加入
ignoreip。 - Docker 中的 fail2ban 看不到攻击。容器端口通过 DOCKER 链发布,该链绕过了 INPUT。对于这类服务,需要在动作中使用
chain = DOCKER-USER。
保护 SSH 还需要做什么
fail2ban 与 /etc/ssh/sshd_config 中的基本设置配合使用效果最好:
PasswordAuthentication no
PermitRootLogin no
MaxAuthTries 3
修改之后,用 sudo sshd -t 检查配置,然后重启服务。在确认密钥登录正常之前,不要关闭当前会话。此外,还可以在防火墙层面只允许特定地址访问 SSH。
总结
fail2ban 的配置归结为几个步骤:安装软件包,创建包含 [sshd] 段的 jail.local,选择正确的 backend 和端口,设置 maxretry、findtime 和 bantime,把自己的地址加入 ignoreip,最后用 fail2ban-client status sshd 检查效果。再加上仅允许密钥登录,就能可靠地保护 SSH 免受密码暴力破解。服务器防护与 fail2ban 的实际操作会在 Linux 课程中详细讲解。
常见问题
如果已经禁用了密码登录,还需要 fail2ban 吗?
不是必需的,但仍然有用:它能减少日志中成千上万的无效尝试,降低负载,并在密码登录被意外重新开启时起到保护作用。
如何查看所有监狱中被封禁的 IP?
执行 sudo fail2ban-client banned,该命令会按监狱列出被封禁的地址。若只看某一个监狱,使用 fail2ban-client status sshd。
服务器重启后封禁还会保留吗?
会。fail2ban 把封禁记录保存在 SQLite 数据库(/var/lib/fail2ban/fail2ban.sqlite3)中,启动时会恢复仍然有效的封禁,除非记录已被 dbpurgeage 参数提前清理。
fail2ban 能保护 SSH 以外的服务吗?
能。自带的过滤器支持 nginx、Apache、Postfix、Dovecot 等服务。只需在 jail.local 中启用相应的监狱,例如设置 [nginx-http-auth] 的 enabled = true。
fail2ban 与防火墙的访问限制有什么区别?
防火墙静态地允许或拒绝地址,而 fail2ban 根据日志中的行为动态封禁来源。两者常常结合使用:在防火墙中设置白名单,并由 fail2ban 处理其余的情况。