在Linux VPS上安装和配置Fail2Ban
配置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.conf和jail.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.ico和robots.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 |
1h或3600 |
封禁持续时间 |
findtime |
10m |
10m或600 |
失败计数窗口 |
maxretry |
5 |
SSH用3,Web用5-20 |
封禁前的失败次数 |
ignoreip |
127.0.0.1/8 ::1 |
添加你的IP | 永不封禁的IP |
banaction |
nftables(Ubuntu 24.04),iptables-multiport(上游) |
ufw或nftables-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 团队原创作品。 未经书面许可,禁止复制、转载或再分发。