在Linux VPS上安装和配置Fail2Ban

3 分钟阅读·Matthieu·ubuntudebianufwnftablesnginxsshsecurityfail2ban|

配置Fail2Ban阻止SSH和Nginx上的暴力破解攻击。涵盖UFW和nftables封禁操作、自定义jail、recidive升级封禁以及在Ubuntu 24.04和Debian 12上的过滤器测试。

Fail2Ban监控日志文件中的重复认证失败记录,并通过防火墙封禁违规IP地址。它能在暴力破解攻击成功之前将其阻止。新部署的VPS通常在上线几分钟内就会收到SSH登录尝试。Fail2Ban是标准的防御手段。

本指南涵盖在Ubuntu 24.04和Debian 12上的安装、SSH和Nginx jail配置、UFW和nftables两种封禁操作后端、针对惯犯的recidive jail,以及使用fail2ban-regex进行过滤器测试。每次配置更改都包含验证步骤。

**前提条件:**一台运行Ubuntu 24.04或Debian 12的VPS,具有root或sudo权限。防火墙应已启用,SSH应已加固。本指南是Linux VPS安全系列的一部分。

如何在Ubuntu 24.04和Debian 12上安装Fail2Ban?

使用apt安装Fail2Ban。两个发行版的默认软件源都包含该软件包。Ubuntu 24.04提供1.0.2版本,Debian 12同样如此。在Debian 12上,还需要安装python3-systemd,以便Fail2Ban能够读取systemd journal。

sudo apt update && sudo apt install -y fail2ban

在Debian 12上,安装systemd的Python绑定:

sudo apt install -y python3-systemd

启用并启动服务:

sudo systemctl enable --now fail2ban

enable标志使Fail2Ban在开机时自动启动。--now标志立即启动它。验证是否正在运行:

sudo systemctl status fail2ban

输出中应该看到Active: active (running)。如果状态显示failed,查看journal:

journalctl -u fail2ban -n 20 --no-pager

jail.conf、jail.local和jail.d/有什么区别?

jail.conf是软件包附带的默认配置文件。软件包更新会覆盖它。不要直接编辑jail.conf。下次apt upgrade时你的更改会丢失。

jail.local是传统的覆盖文件。Fail2Ban先读取jail.conf,然后将jail.local中的设置覆盖上去。这种方式可行,但文件会膨胀为难以维护的庞然大物。

jail.d/目录是更好的方法。每个jail放一个.conf文件。Fail2Ban在读取jail.confjail.local之后,按字母顺序加载这些文件。每个服务保持隔离,添加或删除jail不会影响其他配置。

本指南使用jail.d/中的drop-in文件。检查目录是否存在:

ls /etc/fail2ban/jail.d/

它应该已经存在。如果看到类似defaults-debian.conf的文件,这是正常的。在Ubuntu 24.04上,该文件启用sshd jail并设置banaction = nftables作为默认封禁操作。在Debian 12上,它启用sshd jail。由于Fail2Ban按字母顺序加载jail.d/中的文件,任何自定义默认配置文件必须排在defaults-debian.conf之后才能覆盖其设置。本指南因此使用zz-defaults.conf

如何在Fail2Ban中配置SSH jail?

SSH jail监控认证日志,封禁登录失败次数过多的IP。在Ubuntu 24.04和Debian 12上,sshd jail通过/etc/fail2ban/jail.d/defaults-debian.conf默认启用。但默认值较宽松(5次重试,10分钟封禁)。需要收紧。

创建drop-in配置文件:

sudo tee /etc/fail2ban/jail.d/sshd.conf > /dev/null << 'EOF'
[sshd]
enabled = true
mode = aggressive
port = ssh
backend = systemd
maxretry = 3
findtime = 600
bantime = 3600
EOF

各参数含义:

参数 含义
enabled true 激活此jail
mode aggressive 匹配更多SSH失败模式,包括密钥认证失败
port ssh 监控SSH端口(解析为22,或你的自定义端口)
backend systemd 从systemd journal读取,而非日志文件
maxretry 3 3次失败后封禁
findtime 600 在10分钟窗口内计数失败次数
bantime 3600 封禁1小时(3600秒)

如果你更改了SSH端口(建议这样做),将ssh替换为你的端口号:

port = 2222

重启Fail2Ban以应用更改:

sudo systemctl restart fail2ban

验证jail是否激活:

sudo fail2ban-client status sshd

预期输出:

Status for the jail: sshd
|- Filter
|  |- Currently failed:	0
|  |- Total failed:	0
|  `- Journal matches:	_SYSTEMD_UNIT=sshd.service + _COMM=sshd
`- Actions
   |- Currently banned:	0
   |- Total banned:	0
   `- Banned IP list:

注意观察:Journal matches行确认Fail2Ban从systemd journal读取,而非日志文件。这对Ubuntu 24.04和Debian 12是正确的。

如何配置Fail2Ban使用UFW作为封禁操作?

如果你使用UFW作为防火墙,配置Fail2Ban通过UFW插入封禁规则。这是较简单的方式,适合大多数场景。

创建一个将UFW设为封禁操作的默认配置文件。文件名zz-defaults.conf是特意选择的:在Ubuntu 24.04上,软件包附带的defaults-debian.conf设置了banaction = nftables。你的文件必须在字母排序上排在它后面才能覆盖该默认值。

sudo tee /etc/fail2ban/jail.d/zz-defaults.conf > /dev/null << 'EOF'
[DEFAULT]
banaction = ufw
banaction_allports = ufw
backend = systemd
EOF

重启并检查:

sudo systemctl restart fail2ban
sudo fail2ban-client status sshd

当Fail2Ban封禁一个IP时,它执行ufw insert 1 deny from <IP> to any。封禁后检查UFW规则:

sudo ufw status numbered

你会看到Fail2Ban的deny规则在列表顶部。

如何配置Fail2Ban使用nftables替代iptables?

对于直接使用nftables的生产服务器(不使用UFW),使用nftables-multiport封禁操作。Fail2Ban创建自己的nftables表,在其中管理封禁规则,不会干扰你现有的规则集。

创建默认配置文件。在Ubuntu 24.04上,defaults-debian.conf已设置banaction = nftables,因此这一步在技术上是可选的。但明确指定是好习惯。在Debian 12上,此文件是必需的。

sudo tee /etc/fail2ban/jail.d/zz-defaults.conf > /dev/null << 'EOF'
[DEFAULT]
banaction = nftables-multiport
banaction_allports = nftables[type=allports]
chain = input
backend = systemd
EOF

重启并检查:

sudo systemctl restart fail2ban
sudo fail2ban-client status sshd

要确认nftables集成,列出Fail2Ban的表:

sudo nft list tables

应该看到一个名为inet f2b-table的表。封禁后,检查其内容:

sudo nft list table inet f2b-table

UFW与nftables封禁操作对比

方面 UFW(banaction = ufw nftables(banaction = nftables-multiport
封禁命令 ufw insert 1 deny from <IP> 将IP添加到nftables集合
规则位置 ufw status numbered nft list table inet f2b-table
IPv6支持 支持(UFW处理) 支持(inet族)
持久化 UFW规则在重启后保留 Fail2Ban在启动时重新应用
性能 线性规则匹配 基于集合的查找(大规模时更快)
适用于 简单配置,单一服务 生产环境,多个jail,大量封禁

选择一种方式。不要在同一台服务器上混用UFW和nftables封禁操作。

如何在Fail2Ban中将我的IP加入白名单?

将你的IP添加到ignoreip以防止封禁自己。这很重要。如果你输错密码三次,Fail2Ban会封禁你自己的IP。你将失去SSH访问权限。

将你的IP添加到默认配置:

sudo tee /etc/fail2ban/jail.d/01-whitelist.conf > /dev/null << 'EOF'
[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 YOUR_IP_HERE
EOF

YOUR_IP_HERE替换为你的实际公网IP。在本地机器上运行curl -4 ifconfig.me可以查到。多个IP用空格分隔。

重启并验证白名单已加载:

sudo systemctl restart fail2ban
sudo fail2ban-client get sshd ignoreip

输出列出所有白名单IP和范围。确认你的IP在列表中。

**警告:**如果你从动态IP连接,将其加入白名单的保护有限。保留备用访问方式(通过主机商控制面板的控制台访问)作为被封禁时的后备方案。

如何使用自定义Fail2Ban jail保护Nginx?

Fail2Ban附带多个Nginx过滤器。最有用的是nginx-http-auth(用于HTTP基本认证暴力破解)和nginx-botsearch(用于探测不存在路径的扫描器)。你也可以为应用特定的模式编写自定义过滤器。

nginx-http-auth jail

此jail封禁反复在HTTP基本认证中失败的IP。它读取Nginx错误日志。

sudo tee /etc/fail2ban/jail.d/nginx-http-auth.conf > /dev/null << 'EOF'
[nginx-http-auth]
enabled = true
port = http,https
logpath = /var/log/nginx/error.log
maxretry = 3
findtime = 600
bantime = 3600
EOF

nginx-botsearch jail

此jail捕获扫描漏洞路径的机器人(/wp-admin/phpmyadmin/.env)。它从Nginx访问日志中读取404响应。

sudo tee /etc/fail2ban/jail.d/nginx-botsearch.conf > /dev/null << 'EOF'
[nginx-botsearch]
enabled = true
port = http,https
logpath = /var/log/nginx/access.log
maxretry = 5
findtime = 600
bantime = 7200
EOF

自定义过滤器:封禁过多的4xx错误

对于Nginx后面的应用,你可能想封禁产生过多4xx错误的IP。这能捕获撞库攻击(credential stuffing)、API滥用和路径枚举。内置过滤器不涵盖此场景,需要创建自定义过滤器。

创建过滤器文件:

sudo tee /etc/fail2ban/filter.d/nginx-4xx.conf > /dev/null << 'EOF'
[Definition]
failregex = ^<HOST> - \S+ \[.*\] "[A-Z]+ .+" (400|401|403|404|405) \d+
ignoreregex = ^<HOST> - \S+ \[.*\] "[A-Z]+ /favicon\.ico
              ^<HOST> - \S+ \[.*\] "[A-Z]+ /robots\.txt
EOF

failregex匹配Nginx访问日志中响应为4xx状态码的行。ignoreregex排除常见的误报,如favicon.icorobots.txt请求。

创建jail:

sudo tee /etc/fail2ban/jail.d/nginx-4xx.conf > /dev/null << 'EOF'
[nginx-4xx]
enabled = true
port = http,https
filter = nginx-4xx
logpath = /var/log/nginx/access.log
maxretry = 20
findtime = 600
bantime = 3600
EOF

较高的maxretry值20避免封禁正常浏览中遇到几个404的合法用户。

重启Fail2Ban并检查所有jail是否已加载:

sudo systemctl restart fail2ban
sudo fail2ban-client status

预期输出显示所有活跃的jail:

Status
|- Number of jail:      4
`- Jail list:   nginx-4xx, nginx-botsearch, nginx-http-auth, sshd

关于在应用层保护Nginx的更多信息,请参阅Nginx限流与DDoS防护指南。

如何使用fail2ban-regex测试Fail2Ban过滤器?

在启用jail之前,用真实日志测试其过滤器。fail2ban-regex工具对日志文件运行过滤器并报告匹配情况。这可以避免部署一个什么都不匹配的过滤器(无用)或匹配一切的过滤器(封禁合法用户)。

测试自定义nginx-4xx过滤器:

sudo fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/nginx-4xx.conf

示例输出:

Running tests
=============

Use   failregex filter file : nginx-4xx, basedir: /etc/fail2ban
Use         log file : /var/log/nginx/access.log
Use         encoding : utf-8

Results
=======

Failregex: 42 total
|-  #) [# of hits] regular expression
|   1) [42] ^<HOST> - \S+ \[.*\] "[A-Z]+ .+" (400|401|403|404|405) \d+
`-

Ignoreregex: 3 total

Date template hits:
...

Lines: 1842 lines, 0 ignored, 42 matched, 1800 missed

注意观察:输出显示1842行中有42行匹配。这是合理的比例。如果过滤器匹配了90%的行,说明正则表达式太宽泛。如果匹配0行,要么正则表达式有误,要么日志中还没有4xx错误。

查看匹配的行:

sudo fail2ban-regex --print-all-matched /var/log/nginx/access.log /etc/fail2ban/filter.d/nginx-4xx.conf

查看未匹配的行(用于调优):

sudo fail2ban-regex --print-all-missed /var/log/nginx/access.log /etc/fail2ban/filter.d/nginx-4xx.conf

用systemd journal测试内置的sshd过滤器:

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

如何配置recidive jail处理惯犯?

recidive jail监控Fail2Ban自身的日志。当一个IP在任何jail中被多次封禁时,recidive jail会施加更长的封禁。这是一种升级:首次违规=1小时,惯犯=1周。

在繁忙的生产服务器上,recidive jail才是真正能挡住顽固攻击者的手段。

sudo tee /etc/fail2ban/jail.d/recidive.conf > /dev/null << 'EOF'
[recidive]
enabled = true
logpath = /var/log/fail2ban.log
banaction = %(banaction_allports)s
maxretry = 3
findtime = 86400
bantime = 604800
EOF
参数 含义
logpath /var/log/fail2ban.log 备用日志路径。使用backend = systemd时,Fail2Ban改为读取自身的journal条目(recidive过滤器有内置的journalmatch指令)
maxretry 3 被其他jail封禁3次后触发
findtime 86400 回溯24小时(86400秒)
bantime 604800 封禁1周(604800秒)
banaction %(banaction_allports)s 封锁所有端口,不仅是触发封禁的端口

recidive过滤器随Fail2Ban一起提供,位于/etc/fail2ban/filter.d/recidive.conf。无需创建。

重启并检查:

sudo systemctl restart fail2ban
sudo fail2ban-client status recidive

如何监控封禁和解封IP地址?

Fail2Ban提供fail2ban-client用于所有监控和管理任务。这些命令不受封禁操作后端的影响。

检查整体状态

sudo fail2ban-client status

列出所有活跃的jail及其封禁计数。

检查特定jail

sudo fail2ban-client status sshd

显示当前被封禁的IP、总封禁数和当前失败次数。

手动封禁IP

sudo fail2ban-client set sshd banip 203.0.113.50

解封IP

sudo fail2ban-client set sshd unbanip 203.0.113.50

如果IP被recidive jail封禁,也需要在那里解封:

sudo fail2ban-client set recidive unbanip 203.0.113.50

检查jail使用的封禁操作

sudo fail2ban-client get sshd actions

不重启重新加载配置

sudo fail2ban-client reload

查看Fail2Ban日志

journalctl -u fail2ban -f

实时跟踪Fail2Ban服务日志。你会看到封禁和解封事件。

Fail2Ban应用日志,包含封禁详情:

sudo tail -f /var/log/fail2ban.log

fail2ban-client命令参考

命令 用途
fail2ban-client status 列出所有jail
fail2ban-client status <jail> 显示jail详情和被封禁的IP
fail2ban-client set <jail> banip <IP> 手动封禁IP
fail2ban-client set <jail> unbanip <IP> 解封IP
fail2ban-client reload 重新加载所有配置
fail2ban-client reload <jail> 重新加载单个jail
fail2ban-client get <jail> bantime 显示封禁时长
fail2ban-client get <jail> findtime 显示失败计数窗口
fail2ban-client get <jail> maxretry 显示重试阈值
fail2ban-client get <jail> ignoreip 显示白名单IP
fail2ban-client get <jail> actions 显示使用的封禁操作

端到端检查:触发封禁并确认生效

不要假设你的配置有效。测试它。触发一次真实封禁,验证整个链条:日志检测、封禁操作、防火墙规则和解封。

**步骤1:**从另一台机器(不是你的白名单IP),尝试用错误密码进行SSH登录。3次失败后(匹配maxretry),连接应被拒绝。

如果没有第二台机器,使用fail2ban-client模拟封禁:

sudo fail2ban-client set sshd banip 198.51.100.25

**步骤2:**验证封禁已记录:

sudo fail2ban-client status sshd

被封禁的IP应出现在Banned IP list中。

**步骤3:**验证防火墙规则存在。

对于UFW:

sudo ufw status numbered | grep 198.51.100.25

对于nftables:

sudo nft list table inet f2b-table

IP应出现在表内的一个集合中。

**步骤4:**解封并验证移除:

sudo fail2ban-client set sshd unbanip 198.51.100.25
sudo fail2ban-client status sshd

IP应不再出现在封禁列表中。再次检查防火墙确认规则已移除。

Fail2Ban配置参数参考

参数 默认值 推荐值 说明
bantime 10m 1h3600 封禁持续时间
findtime 10m 10m600 失败计数窗口
maxretry 5 SSH用3,Web用5-20 封禁前的失败次数
ignoreip 127.0.0.1/8 ::1 添加你的IP 永不封禁的IP
banaction nftables(Ubuntu 24.04),iptables-multiport(上游) ufwnftables-multiport 执行的防火墙命令
backend auto systemd 日志来源(现代发行版用systemd journal)
destemail root@localhost 你的邮箱 告警接收者
action %(action_)s %(action_mwl)s用于邮件告警 封禁时执行的操作

出了问题?

**Fail2Ban无法启动:**检查jail文件的语法错误。缺少括号或无效的值会阻止启动。

sudo fail2ban-client -t

这会测试配置而不启动服务。修复报告的错误。

Jail显示0匹配但攻击正在发生:backend可能不正确。在Ubuntu 24.04和Debian 12上,使用backend = systemd。如果使用backend = auto且系统没有/var/log/auth.log,Fail2Ban什么都读不到。

**被封禁的IP仍然能连接:**封禁操作与你的防火墙不匹配。如果使用UFW,设置banaction = ufw。如果直接使用nftables,设置banaction = nftables-multiport。检查封禁后防火墙规则是否确实存在。

**你封禁了自己:**通过主机商的Web控制台(VNC/KVM)访问服务器。从那里:

sudo fail2ban-client set sshd unbanip YOUR_IP

或者完全停止Fail2Ban:

sudo systemctl stop fail2ban

然后修复ignoreip配置并重启。

**Fail2Ban内存占用过高:**在日志文件较大的服务器上,Fail2Ban可能消耗较多内存。设置dbpurgeage限制数据库大小:

sudo tee /etc/fail2ban/jail.d/99-performance.conf > /dev/null << 'EOF'
[DEFAULT]
dbpurgeage = 7d
EOF

版权所有 2026 Virtua.Cloud。保留所有权利。 本内容为 Virtua.Cloud 团队原创作品。 未经书面许可,禁止复制、转载或再分发。

准备好亲自尝试了吗?

用Fail2Ban保护您的Linux VPS。

查看 VPS 方案