中文 English

避坑指南:新装 Ubuntu 26.04 与 PVE 9.2 别急着用!Fail2Ban 无法启动与拦截失效的终极解决办法

发布时间: 2026-05-26
Ubuntu Proxmox VE PVE Fail2Ban nftables systemd 安全加固 故障排查

先说结论

随着 Ubuntu 26.04 LTS 与 Proxmox VE (PVE) 9.2 的相继发布,许多运维工程师与 Host 玩家在第一时间完成了系统升级或新装。然而,在进行服务器安全加固时,你会发现一个令人抓狂的现象:直接沿用旧版本(如 Ubuntu 20.04/22.04 或 PVE 7.x/8.x)的 Fail2Ban 配置,不仅服务可能直接报错无法启动,甚至即使显示 Running,外部恶意扫描也根本无法被成功拦截!

这并不是 Fail2Ban 软件本身出了 Bug,而是因为新版系统在底层日志架构、服务激活机制和防火墙后端上默默丢下了三颗“隐形炸弹”。本文将深度剖析这三个底层变化,并提供一套完美的、基于 systemd-journald + nftables 的 Fail2Ban 现代配置方案。


1. 现代 Linux 系统的三大底层“隐形炸弹”

要在 Ubuntu 26.04 或 PVE 9.2 上完美部署 Fail2Ban,我们必须首先看清系统底层的重大变革。传统依赖 /var/log/auth.logiptables 的老旧教程,在新系统上注定折戟。

Fail2Ban nftables systemd 架构流图 图 1:Fail2Ban 在 Ubuntu 26.04 / PVE 9.2 下的现代日志与防火墙联动架构

💣 炸弹一:rsyslog 默认被移除,再无 /var/log/auth.log

在传统的 Debian/Ubuntu 教程中,配置 Fail2Ban 拦截 SSH 暴力破解的首要步骤往往是指定日志路径:logpath = /var/log/auth.log

然而,自 Ubuntu 24.04 起,官方已默认不再安装 rsyslog 软件包,这一设计在最新的 Ubuntu 26.04 中得到了彻底贯彻。这也意味着:

💣 炸弹二:SSH 默认启用 systemd 套接字激活(Socket Activation)

在 Ubuntu 26.04 中,如果你执行 systemctl status sshd,大概率会看到该服务处于 inactive (dead) 状态,但你依然能用 SSH 顺畅地连上服务器。这是因为系统默认启用了 systemd 套接字激活

💣 炸弹三:iptables 彻底沦为历史,全面转向 nftables

无论是 Ubuntu 26.04 还是基于 Debian 13 演进的 PVE 9.2,底层的防火墙后端都已经完全由 nftables 统治。


2. 破局之道:全栈拥抱 systemd 与 nftables

既然看清了底层的变化,解决方案也就呼之欲出了:

  1. 日志读取:放弃文本文件监控,全量使用 backend = systemd,直接读取二进制 Journal 日志。
  2. 服务匹配:重新修正 SSH 的日志过滤条件,支持匹配套接字激活下的动态服务名。
  3. 拦截动作:彻底抛弃 iptables,全面使用 Fail2Ban 内置的 nftables[type=multiport] 动作,在内核态通过 nft 集合(Set)实现毫秒级的高性能拦截。

下面,我们开始实战配置。


3. 实战部署指南

第一步:安装 Fail2Ban 及其依赖

虽然在新版系统上我们不再依赖文本日志,但要让 Fail2Ban 能够高效地读取 systemd 日志,我们需要确保其 Python 的 systemd 绑定库已正确安装。

# 更新源并安装 fail2ban
sudo apt update
sudo apt install -y fail2ban python3-systemd

安装完成后,不要急着启动服务。我们先来进行配置。


第二步:编写 /etc/fail2ban/jail.local

Fail2Ban 的默认配置文件是 /etc/fail2ban/jail.conf,我们强烈建议不要直接修改该文件,因为每次软件包更新都可能覆盖它。正确的做法是创建并编辑 /etc/fail2ban/jail.local

sudo nano /etc/fail2ban/jail.local

写入以下经过生产环境严格验证的配置内容:

[DEFAULT]
# 封禁时间设置:默认封禁 1 小时,如果在 10 分钟内失败 5 次
bantime  = 1h
findtime = 10m
maxretry = 5

# 防火墙后端:彻底拥抱 nftables,使用 multiport 模式进行多端口拦截
banaction = nftables[type=multiport]
banaction_allports = nftables[type=allports]

# 日志读取后端:默认全量使用 systemd 方式,直接对接 systemd-journald
backend = systemd

# 排除的 IP 地址,避免自己把自己锁在外面(请根据你的内网网段修改)
ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24 192.168.101.0/24

# ====================
# 针对 SSH 的安全加固
# ====================
[sshd]
enabled = true
port    = ssh
# 重点:为了适配 systemd socket activation,必须精准指定匹配单元
# 同时匹配传统的 sshd.service, 独立的 ssh.service 以及套接字激活生成的 ssh@*.service
journalmatch = _SYSTEMD_UNIT=sshd.service + _SYSTEMD_UNIT=ssh.service + _SYSTEMD_UNIT=ssh.socket + _SYSTEMD_UNIT=ssh@*.service
maxretry = 3
bantime  = 24h

# ====================
# Proxmox VE 9.2 专属防御
# ====================
[proxmox]
enabled = true
port    = 8006
filter  = proxmox
# PVE 的管理后台认证日志由 pvedaemon 和 pveproxy 产生,全部记录在 systemd 中
journalmatch = _SYSTEMD_UNIT=pvedaemon.service + _SYSTEMD_UNIT=pveproxy.service
maxretry = 3
bantime  = 12h

参数详解

  • backend = systemd:强制 Fail2Ban 调用 python3-systemd 库直接读取 journal 数据库,性能极佳,且完美解决了无 /var/log/auth.log 的问题。
  • journalmatch 中的多个值相加(用 + 连接)代表逻辑“或”的关系。这确保了无论你的系统使用的是经典的 ssh.service 还是全新的套接字激活 ssh@.service,其产生的认证失败日志都能被 Fail2Ban 捕捉到。

第三步:为 PVE 9.2 编写专属过滤器(Filter)

对于 PVE 用户而言,保护 8006 管理后台与保护 SSH 同样重要。由于 PVE 9.2 的认证失败日志格式与标准 Web 服务不同,我们需要为其量身定做过滤器。

创建并编辑 /etc/fail2ban/filter.d/proxmox.conf

sudo nano /etc/fail2ban/filter.d/proxmox.conf

填入以下正则表达式规则:

[Definition]
# 匹配 pvedaemon/pveproxy 中记录的登录失败、双因子认证失败等日志
failregex = ^(?P<__prefix_line>)(?:pvedaemon|pveproxy)\[\d+\]: (?:<authentication failure>|connection error: .*|.*authentication failure;.*)$

# 忽略白名单(如有需要可在此配置)
ignoreregex =

第四步:启动并启用 Fail2Ban 服务

完成上述两步配置后,我们就可以安全地启动 Fail2Ban,并将其设置为开机自启了:

# 启用并启动服务
sudo systemctl enable fail2ban --now

# 重新加载配置(如果服务已经在运行)
sudo systemctl restart fail2ban

4. 验证与排查指南(非常重要!)

配置完成后,千万不要觉得大功告成,我们必须通过实际命令来验证拦截机制是否生效。

🔍 验证一:检查 Fail2Ban 服务运行状态

首先检查 systemd 服务的健康状况:

systemctl status fail2ban.service

Fail2Ban 运行状态控制台截图 图 2:Fail2Ban 在 systemd 中成功运行并加载了 sshd 与 proxmox 两个 Jail

如果服务启动失败,通常会在输出的日志中给出明确的提示。最常见的错误是由于没有安装 python3-systemd 导致 backend = systemd 无法初始化。


🔍 验证二:使用 fail2ban-regex 测试日志匹配

这是最关键的排查工具。它能帮我们模拟 Fail2Ban 是否能从现有的 systemd 日志中正确提取到攻击特征。

针对 SSH 服务进行测试:

sudo fail2ban-regex systemd-journal /etc/fail2ban/filter.d/sshd.conf

针对 Proxmox 后台服务进行测试:

sudo fail2ban-regex systemd-journal /etc/fail2ban/filter.d/proxmox.conf

运行后,你应该能看到类似下方的匹配成功报告:

fail2ban-regex 匹配结果截图 图 3:使用 fail2ban-regex 成功匹配到了 PVE 日志中的爆破行为

如果在 Failregex 这一行显示有数字(如 24 matched),说明你的正则表达式和日志抓取源完全正确;如果是 0 matched,则需要检查你的服务器近期是否有登录失败记录,或者检查 journalmatch 里的服务名是否匹配。


🔍 验证三:检查 nftables 拦截规则集

既然我们放弃了 iptables,那么所有的拦截动作都会呈现在 nftables 中。我们可以通过以下命令实时查看 Fail2Ban 创建的防火墙表、链和被封禁的 IP 列表:

sudo nft list ruleset | grep -A 15 f2b

你会看到 Fail2Ban 优雅地在 nftables 中创建了一个专用的 inet f2b-table

nftables 规则集控制台截图 图 4:nftables 规则链中已成功注入 Fail2Ban 的拦截集与动态 DROP 规则

在这个输出中,elements = { ... } 括号里的 IP 就是当前处于封禁状态的恶意 IP。当拦截时间过期(即达到 bantime)后,Fail2Ban 会自动从该 nftables 集合中将 IP 移除,无需人工干预。这种基于 Set 的机制在应对大规模扫描时,比传统的 iptables 逐条遍历规则要高效得多。


5. 常见痛点与 FAQ

Q1: 为什么我改了 /etc/fail2ban/jail.local,但系统依然报错说找不到 /var/log/auth.log

A: 这是因为你在 jail.local[DEFAULT] 区间没有指定 backend = systemd,或者某些特定的 Jail(比如第三方自定义的 Jail)里强行写死了 logpath = ...。请检查你的配置文件,确保全局后端为 systemd,并将所有 Jail 里的 logpath 配置行删除。

Q2: 我使用 nftables 后,怎么手动解封一个不小心被封锁的内网 IP?

A: 可以使用 fail2ban-client 命令优雅地进行手动解封。

Q3: 为什么 fail2ban-regex 匹配成功了,但 nftables 里却一直没有新增封禁的 IP?

A: 封禁的触发条件是“在 findtime 时间内失败次数达到 maxretry”。请确认你的测试攻击次数是否已经超过了设定的阈值。另外,请检查 ignoreip 参数,确保你的测试机 IP 没有被列入白名单中。


6. 总结

在新一代 Linux 操作系统中,很多我们习以为常的传统组件(如 rsyslog、iptables)正在加速退网。这要求我们这些系统管理员必须及时更新知识库,转向更现代、更高效的 systemd-journaldnftables 架构。

通过本文的避坑与实战指引,你的 Ubuntu 26.04 与 PVE 9.2 服务器现在已经拥有了一套健壮、敏捷、完全契合现代内核的 Fail2Ban 防御体系。快去给你的爱机做一次安全体检吧!