Ubuntu 24.04 安装 Fail2ban 并阻止 SSH 扫描
Ubuntu 24.04 中,直接运行 apt install 即可封禁 SSH 暴力破解。用 fail2ban-client status sshd 验证;若 Total failed 始终为 0,本文给出修复方法。
Fail2ban 的实际作用
Fail2ban 是一个读取日志的守护进程。它监控 SSH 身份验证消息。如果同一地址在短时间内连续多次验证失败,Fail2ban 就会运行防火墙命令,暂时阻止该地址。这就是它的全部工作原理。配置文件中大约只有 30 行配置。在 Ubuntu 24.04 上,只需运行一个 apt 命令即可安装,而且无需修改任何配置就能提供基本保护。
需要明确它能做什么,以及不能做什么。Fail2ban 不负责身份验证,也不负责加密。它无法阻止单次且有针对性的登录尝试,只能处理来自同一来源的重复尝试。它是噪声过滤器和速率限制器,不是锁。它的作用是让对 22 端口持续进行的后台扫描不再浪费 CPU、带宽和日志空间,并减缓必须一次从一个地址发起攻击的攻击者。
Fail2ban 无法替代什么
Fail2ban 是第三层防护,而不是第一层。如果服务器仍接受 SSH 密码登录,分布在数千个地址上的僵尸网络仍可持续尝试登录,因为每个地址的尝试次数都低于封禁阈值,无法触发封禁。真正的防护措施是仅使用密钥进行身份验证。无论攻击者尝试多少次,这都能阻止密码猜测。
在仅使用密钥进行身份验证的基础上部署 Fail2ban,可以发挥两个作用:减少日志中的暴力破解噪声,并尽早驱逐扫描器,使其停止持续攻击端口。应将其视为纵深防御的一部分。它位于密钥身份验证和防火墙之后,绝不能替代或置于二者之前。
前置条件,以及 Ubuntu 24.04 的实际情况
您需要一台运行 Ubuntu 24.04 的 VPS,具备 root 或 sudo 权限,并且 SSH 已可用,最好使用密钥认证。Fail2ban 资源占用很低:只需几十 MB 内存,无需调整限制。
现在说明一个所有旧教程都会弄错的问题。多年来,标准建议一直是“安装 Fail2ban,然后添加 backend = systemd,因为 Ubuntu 已停止写入 /var/log/auth.log。”这种说法描述的是一次真实变更:现代服务器和云镜像默认不再包含 rsyslog,因此 SSH 只写入 systemd journal,这个文本文件已经不存在。但在 Ubuntu 24.04 中,Fail2ban 软件包已经处理了这一情况。该软件包会提供 /etc/fail2ban/jail.d/defaults-debian.conf;服务器实际运行的就是这个文件中的配置,而不是上游默认配置:
[DEFAULT]
banaction = nftables
banaction_allports = nftables[type=allports]
backend = systemd
[sshd]
enabled = true请仔细阅读,因为这会在您进行任何修改前解决两个问题。backend = systemd 表示 SSH jail 会读取 journal,因此缺少 auth.log 不会造成影响。banaction = nftables 表示封禁通过 nftables 强制执行;这是 Ubuntu 24.04 实际使用的防火墙,而不是旧版 iptables。[sshd] enabled = true 表示该 jail 从首次启动起就已启用。结论是:Ubuntu 24.04 中的默认 apt install fail2ban 开箱即用即可阻止 SSH 暴力破解。您大部分工作是确认这一点、调整策略,并确保不会将自己锁在服务器之外。
旧的 auth.log 陷阱仍会在以下 3 种情况下导致问题,值得提前识别:您使用 pip 而不是 apt 安装了 Fail2ban,因此没有 defaults-debian.conf;您位于没有 systemd journal 可供读取的非特权容器中;或者您按照旧教程操作,将 backend = auto 粘贴到自己的 jail.local 中,从而覆盖了正常工作的默认配置。故障模式部分会准确说明每种情况的表现。
第 1 步:安装并确认它已经在执行封禁
sudo apt update
sudo apt install -y fail2banUbuntu 24.04 自带 Fail2ban 1.0.2,软件包将 python3-systemd 作为硬依赖,因此 journal 后端所需的组件都已具备。该服务会自动启用并启动:
sudo systemctl status fail2ban您应看到 active (running)。然后查看已经在执行工作的 jail:
sudo fail2ban-client status sshd在已对公网开放几分钟的 VPS 上,通常已经能看到失败次数和被封禁的地址。互联网会持续扫描端口 22。这就证明默认配置有效。接下来只需对其进行优化,而不是从零开始构建。
第 2 步:编辑 jail.local,不要编辑 jail.conf
Fail2ban 将上游默认配置保存在 /etc/fail2ban/jail.conf 中。不要编辑该文件。软件包的每次 apt upgrade 都可能替换它,您的修改也会在不发出警告的情况下消失。Fail2ban 按固定顺序读取文件:首先读取 jail.conf,然后读取 jail.d/ 中的所有文件,最后读取 jail.local,后读取的值会覆盖先读取的值。.local 文件由您管理,软件包升级不会修改它。过滤器也遵循相同规则:*.local 文件会覆盖软件包提供的 filter.d/*.conf。
因此,您只需编写一个小型 jail.local,仅覆盖少量需要调整的设置,并保留 jail.conf 和软件包提供的 jail.d/defaults-debian.conf 作为参考,不要修改它们。
第 3 步:编写 /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.local将以下内容写入文件,并将 ignoreip 行中的地址改为您自己的公网 IP:
[DEFAULT]
# Ubuntu 24.04 already sets these two in jail.d/defaults-debian.conf.
# Pinning them here documents the dependency and survives if that
# file is ever removed or changed by an upgrade.
backend = systemd
banaction = nftables
# Ban for one hour ...
bantime = 1h
# ... if an address fails ...
maxretry = 5
# ... 5 times within 10 minutes.
findtime = 10m
# Never ban these. PUT YOUR OWN IP HERE.
ignoreip = 127.0.0.1/8 ::1 10.0.0.24
# Longer bans for repeat offenders: 1h, 2h, 4h ... up to a week.
bantime.increment = true
bantime.maxtime = 1w
[sshd]
enabled = true每一行都有明确作用:
bantime、findtime、maxretry定义策略。随软件发布的默认值bantime只有十分钟;设置为一小时更合理。某个地址在十分钟内失败五次后将被封禁。正常用户可能会输错密码一两次;十分钟内失败五次通常表示这是脚本。ignoreip是安全保护措施。将您连接来源的公网地址填写在这里,这样 Fail2ban 就不会将您自己锁在服务器之外。家庭网络连接的 IP 可能会变化,这正是应优先采用文末 VPN 方案的理由,而不是跳过此行。bantime.increment = true会让每次重复封禁的时长都比上一次更长:先是一小时,然后是两小时,再到四小时,最长为bantime.maxtime。反复发起连接的地址会逐步被延长封禁时间。
请在用于 SSH 连接来源的计算机上查找要加入白名单的地址,而不是在服务器上查找:
curl -s ifconfig.me您可以在此处生成针对您的端口和封禁策略调整好的 jail.local,然后将其粘贴到文件中:
第 4 步:重启并确认它正在读取日志
sudo fail2ban-client -t
sudo systemctl restart fail2ban
sudo fail2ban-client status sshd-t 会先执行配置测试,因此 jail.local 中的拼写错误会在此处明确报错,而不是导致服务保持停止状态。正常的 jail 状态如下:
Status for the jail: sshd
|- Filter
| |- Currently failed: 0
| |- Total failed: 14
| `- Journal matches: _SYSTEMD_UNIT=sshd.service + _COMM=sshd
`- Actions
|- Currently banned: 1
|- Total banned: 3
`- Banned IP list: 10.0.0.66能够证明 Fail2ban 确实正在读取登录记录的数字是 Total failed。如果该值大于 0,或者您从另一台计算机故意使登录失败时该值会增加,说明系统正在读取日志,配置已完成。如果无论登录失败多少次,该值都保持为 0,并且您确认测试来源地址不在 ignoreip 中,请跳转到下面的故障模式部分。
请注意,Journal matches 行仍然使用 sshd.service。在 Ubuntu 上,SSH 单元实际是 ssh.service,但随软件发布的过滤器也会匹配 _COMM=sshd;此外,OpenSSH 24.04 会记录由名为 sshd 的进程产生的失败,因此匹配仍然有效。只有在使用更新版本的 OpenSSH(9.8 或更高版本)时才需要关注这一点,因为该版本中每个连接的工作进程是 sshd-session;故障模式部分涵盖了这种情况。
第 5 步:观察实际封禁生效,或强制触发一次进行测试
在任何公网 VPS 上,真实封禁通常会在几分钟内自动发生。要观察封禁过程,请持续跟踪日志:
sudo tail -f /var/log/fail2ban.log封禁记录如下所示:
2026-07-15 10:31:40,502 fail2ban.filter [812]: INFO [sshd] Found 10.0.0.66 - 2026-07-15 10:31:40
2026-07-15 10:31:44,118 fail2ban.actions [812]: NOTICE [sshd] Ban 10.0.0.66如需在不等待的情况下端到端验证整个机制,请手动封禁一个文档地址。不要封禁您自己的地址:
sudo fail2ban-client set sshd banip 10.0.0.66命令会输出 1,并且该地址会出现在 fail2ban-client status sshd 的 Banned IP list 下。现在确认防火墙中确实存在这条阻断规则。在 Ubuntu 24.04 上使用的是 nftables,而不是 iptables:
sudo nft list table inet f2b-table您将看到一个名为 addr-set-sshd 的集合,其中包含 10.0.0.66;还会看到一个名为 f2b-chain 的链,该链会拒绝来源地址属于该集合的流量。如果 fail2ban-client 显示某个地址已被封禁,但在 nft list 中看不到任何内容,说明您的封禁操作与防火墙不匹配。请参阅故障模式中的 nftables/iptables 说明。
第 6 步:解除对自身的封禁,并在被锁定时恢复访问
如果误封了某个地址,包括您自己的地址,请将其移除:
sudo fail2ban-client set sshd unbanip 10.0.0.66成功时返回 1。要清除所有 jail 中的全部封禁:
sudo fail2ban-client unban --all不要指望已经建立的 SSH 会话能够保护您:nftables 封禁会拒绝来自被封禁地址发往端口 22 的所有数据包,包括已建立连接中的数据包。因此,封禁生效后,现有会话会立即冻结。如果您封禁了自己的地址,且没有 ignoreip 条目,就会被锁定,直到封禁过期。请通过服务商的 Web 控制台(VNC 或串口)恢复访问;该控制台不经过 SSH。然后等待 bantime 结束,或在那里运行解除封禁命令。
步骤 7:让封禁持久化并逐步升级
Fail2ban 会将当前封禁记录保存在 /var/lib/fail2ban/fail2ban.sqlite3 的小型 SQLite 数据库中,因此服务重启或系统重启后这些封禁仍然有效,不会丢失。您之前添加的 bantime.increment 行会让每个重复违规者面临逐步升级的封禁,封禁时长大致会从一小时翻倍,直到接近一周。
在此基础上,如果要实施系统范围的“三次违规”策略,Fail2ban 提供了一个 recidive jail。它会监控自身的 /var/log/fail2ban.log,并将跨所有 jail 多次被封禁的地址列入长期封禁。由于您的 [DEFAULT] 现在使用 systemd 后端,请将此 jail 固定为读取它所针对的日志文件:
[recidive]
enabled = true
backend = auto
logpath = /var/log/fail2ban.log
bantime = 1w
findtime = 1d
maxretry = 5带有显式 logpath 的 backend = auto 会让 recidive 读取普通的 fail2ban.log。它统计的 Ban 行实际出现在该文件中,而您全局设置的 systemd 默认值会将其指向 journal;这些日志行并不在那里。
步骤 8:配合仅密钥 SSH,更好的是使用 VPN
Fail2ban 只有与密钥身份验证配合使用时才真正有效。在 /etc/ssh/sshd_config.d/ 下创建一个 drop-in 文件,例如 /etc/ssh/sshd_config.d/00-hardening.conf,并设置:
PasswordAuthentication no
KbdInteractiveAuthentication no然后执行 sudo systemctl restart ssh。禁用密码后,暴力破解根本无法成功;此时 Fail2ban 的作用是减少日志噪声,并尽早驱逐扫描器。更安全的做法是让 SSH 完全不暴露在公网:将 SSH 放在自托管的 WireGuard VPN 后面,并配置防火墙,使端口 22 只能通过隧道响应。攻击者无法暴力破解无法访问的端口,因此 Fail2ban 只需作为后备防护,而不是第一道防线。
Fail2ban 不仅适用于 SSH。任何记录登录失败的服务都可以配置 jail,例如邮件服务器、nginx 站点,或 自托管的 Vaultwarden 密码管理器;如果不希望其 Web 登录入口暴露给凭据填充攻击,就应为其配置防护。当 Web 应用位于 使用 Let's Encrypt 证书的 nginx 站点后面时,可以采用与 SSH jail 监控 journal 相同的方式,让 Fail2ban 过滤器监控其访问日志。
故障模式及其对应的确切报错字符串
“Have not found any log file for sshd jail”,Fail2ban 无法启动。 这是旧版 auth.log 问题。在 Ubuntu 24.04 上,只有以下情况会触发该问题:某项配置覆盖了软件包默认值、安装了 pip 但没有 defaults-debian.conf、容器中没有 journal,或者您将多余的 backend = auto 粘贴到了 jail.local。在没有 /var/log/auth.log 的文件后端中,sshd jail 找不到日志,整个 daemon 会中止。fail2ban.log 显示:
ERROR Failed during configuration: Have not found any log file for sshd jail由于该错误属于致命错误,服务不会启动,随后 fail2ban-client status 会报告下游症状:
ERROR Failed to access socket path: /var/run/fail2ban/fail2ban.sock. Is fail2ban running?“socket path”这一行不表示 Fail2ban 本身损坏,而表示某个 jail 找不到日志,导致 Fail2ban 根本没有启动。在 [DEFAULT] 中设置 backend = systemd 后即可同时修复这两条消息;Ubuntu 软件包已经为您完成了该设置。
Jail 处于活动状态,但 Total failed 始终不变。 daemon 正在运行,journal 也在读取,但真实的失败记录不断写入 journalctl -u ssh,计数器却停留在 0。先排除最常见的原因:您正在使用 ignoreip 中列出的地址进行测试,因此按设计,您自己的失败不会触发封禁。如果不是这个原因,则可能是您使用的 OpenSSH 构建版本中,每个连接的 worker 为 sshd-session(9.8 及更高版本),其 journal _COMM 是 sshd-session,而不是 sshd,因此软件包提供的匹配规则无法匹配。扩大 [sshd] 块中的匹配范围:
[sshd]
enabled = true
backend = systemd
journalmatch = _SYSTEMD_UNIT=ssh.service + _COMM=sshd + _COMM=sshd-session重启服务,然后从不在 ignoreip 中的地址故意进行一次失败登录,并确认 Total failed 最终开始递增。
您封禁了自己的地址:Connection refused。 您没有将自己的地址加入 ignoreip,并测试了几次错误登录,现在出现:
ssh: connect to host 10.0.0.10 port 22: Connection refused这是 nftables action 默认的 reject 判定生效的结果。连接被拒绝,而不是静默超时。按照第 6 步中的方法修复:从另一个未被封禁的地址建立会话后解除封禁,或使用服务提供商控制台操作。被封禁地址上已经打开的会话也会冻结。然后将您的地址加入 ignoreip,避免再次发生。
Fail2ban 显示地址已被封禁,但该地址仍能连接。 status sshd 中的计数器不断增加,但该地址仍能访问端口 22。这是封禁 action 与防火墙不匹配导致的问题。在 Ubuntu 24.04 上,这几乎总是因为您用旧指南中的 banaction = iptables-multiport 覆盖了可正常工作的 banaction = nftables,而当前服务器没有 iptables 层。fail2ban.log 显示:
fail2ban.actions [812]: ERROR Failed to execute ban jail 'sshd' action 'iptables-multiport'删除该覆盖配置,让软件包提供的 nftables action 生效。如果您完全通过 ufw 管理防火墙,并希望封禁规则显示在 ufw 中,则在 [DEFAULT] 中设置 banaction = ufw。重启服务,并使用 sudo nft list ruleset | grep f2b 确认规则已出现。
编辑 jail.local 后 Fail2ban 无法启动。 拼写错误、多余的标题或无效的时间值都会导致服务拒绝启动。先让 Fail2ban 在运行前检查配置:
sudo fail2ban-client -t它会指出存在问题的文件和 jail,例如 Errors in jail 'sshd'. Skipping...。这样您可以直接修复源配置,而不必猜测原因。
FAQ
默认安装的 Ubuntu 24.04 Fail2ban 确实会封禁 SSH 攻击吗?
会。该软件包提供 /etc/fail2ban/jail.d/defaults-debian.conf,启用 sshd jail,设置 backend = systemd,使其读取 systemd journal,而不是不存在的 /var/log/auth.log;同时设置 banaction = nftables,通过 Ubuntu 实际使用的防火墙执行封禁。直接使用 apt install fail2ban 即可从首次启动开始保护 SSH。使用 sudo fail2ban-client status sshd 确认,并检查 Total failed 是否为非零值。
为什么 Fail2ban 在我的服务器上没有封禁任何地址?
按顺序排查三个常见原因。您可能正在从 ignoreip 中的地址进行测试,该地址按设计被豁免。您也可能按照旧指南,将 backend = auto 粘贴到 jail.local,覆盖了正常工作的默认配置;对于没有 auth.log 的镜像,这会导致 journal 读取失败。或者,您可能位于完全没有 systemd journal 可供读取的容器中。检查 fail2ban-client status sshd 中的 Total failed:如果 journalctl -u ssh 显示确实存在失败记录,而该值始终不增长,说明 jail 读取了错误的位置。
如何解除对我自己 IP 地址的封禁?
运行 sudo fail2ban-client set sshd unbanip YOUR.IP.HERE;成功时会返回 1。也可以运行 sudo fail2ban-client unban --all 清除所有封禁。如果您已无法通过 SSH 登录,请使用服务提供商的 Web 控制台或 VNC 控制台运行相同的命令。封禁会拒绝来自您地址、发往端口 22 的所有数据包,因此即使已经建立的会话也会停止工作。然后将您的地址加入 ignoreip,避免再次被封禁。
jail.conf 和 jail.local 有什么区别?
jail.conf 保存 Fail2ban 的上游默认配置,并会在每次软件包升级时被覆盖,因此其中的修改最终都会丢失。Debian/Ubuntu 软件包通过 jail.d/defaults-debian.conf 在此基础上叠加自身设置。您应将修改写入 jail.local;该文件最后读取,其设置会覆盖前两者,并且不会在升级时被修改。将 jail.conf 保留为只读参考文件。
Fail2ban 会取代基于密钥的 SSH 身份验证吗?
不会。Fail2ban 会限制来自同一地址的重复失败请求速率;对于缓慢的分布式猜测攻击,如果每个地址都低于阈值,它无法发挥作用。仅使用密钥进行身份验证(PasswordAuthentication no)可以直接杜绝密码猜测;Fail2ban 则可减少日志噪声,并尽早清除扫描器。两者应同时使用;理想情况下,还应完全避免让 SSH 暴露在公网中。