为什么你的VPS需要Fail2ban
任何一台暴露在公网的Linux VPS,从开机那一刻起就在被扫描和爆破。无论你用的是阿里云、腾讯云还是海外VPS,SSH端口、Web面板、数据库端口无一例外都会成为攻击者的目标。根据我的实际观察,一台配置了默认SSH端口(22)的全新VPS,在接入互联网后的24小时内,平均会遭受2000到5000次登录尝试。这些尝试来自全球各地的僵尸网络、扫描器以及自动化攻击脚本。
传统的防护手段——修改SSH端口、使用强密码、禁用root登录——虽然有效,但远远不够。攻击者同样会扫描其他端口(如2222、22222等常见替代端口),而密码再强也架不住撞库和字典攻击的持续轰炸。更关键的是,这些方法都是被动防御,无法在攻击发生时实时响应并阻断攻击源。
这就是Fail2ban发挥作用的地方。Fail2ban是一个基于Python的入侵防御框架,它通过扫描系统日志文件(如
1 | /var/log/auth.log |
、
1 | /var/log/nginx/error.log |
),识别出反复失败的登录尝试、恶意请求模式或扫描行为,然后动态地修改防火墙规则(iptables/nftables),在指定时间内临时封禁攻击源的IP地址。简单来说,Fail2ban让你的服务器拥有了”自动反击”的能力。
本文将带你从零开始,全面掌握Fail2ban的安装、配置、调优,并深入讲解如何保护SSH、Nginx、WordPress、Postfix邮件服务等常见应用,最终打造一个自动化的VPS防御体系。

Fail2ban安装与基础配置
安装Fail2ban
主流的Linux发行版都内置了Fail2ban包,安装非常简单:
1
2
3
4
5
6
7
8
9
10 # Debian/Ubuntu
apt update && apt install -y fail2ban
# CentOS/RHEL 7/8
yum install epel-release -y
yum install fail2ban -y
# Rocky Linux / AlmaLinux 9
dnf install epel-release -y
dnf install fail2ban -y
安装完成后,先不要急着启动服务。我们需要先理解它的配置文件结构,然后根据自己的需求进行定制。
配置文件结构
Fail2ban的配置文件遵循”本地覆盖”原则,这一点非常重要:
| 文件路径 | 作用 | 注意事项 | ||||
|---|---|---|---|---|---|---|
|
Fail2ban守护进程本身的配置(日志级别、socket路径等) | 一般不需要修改 | ||||
|
默认的监狱配置(包含所有内置规则) | 不要直接编辑,会被更新覆盖 | ||||
|
用户自定义的监狱配置(覆盖jail.conf中的值) | 你真正需要编辑的文件 | ||||
|
各种服务的日志匹配规则(正则表达式) | 可以自定义
覆盖 |
||||
|
封禁动作的定义(iptables、firewallcmd、cloudflare等) | 一般不需要修改 |
核心原则是:永远不要修改
1 | <em>.conf |
文件,而是在同目录下创建同名的
1 | </em>.local |
文件来覆盖配置。这样在升级Fail2ban时,你的自定义配置不会丢失。
创建本地配置文件
现在我们创建
1 | jail.local |
,这是整个Fail2ban配置的核心:
1
2
3 cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
# 或者直接新建一个空文件从头写
vim /etc/fail2ban/jail.local
一个最基本的
1 | jail.local |
配置示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 [DEFAULT]
# 封禁时间:3600秒(1小时)。设置为 -1 表示永久封禁
bantime = 3600
# 在findtime秒内,如果失败maxretry次,则封禁
findtime = 600
maxretry = 5
# 忽略的IP列表(白名单),永远不要封禁这些IP
# 建议把你自己公司的公网IP或VPN的IP加进来
ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24
# 默认的防火墙封禁动作
# iptables-allports 会封禁所有端口;iptables 只封禁目标端口
banaction = iptables-allports
# 封禁通知邮箱(可选)
# destemail = admin@example.com
# sender = fail2ban@example.com
# action = %(action_mw)s
# 日志编码
logencoding = utf-8
[sshd]
enabled = true
port = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s
这里有几个关键参数需要理解:
- bantime:封禁持续时间。默认3600秒(1小时)。对于SSH爆破,建议至少设置86400秒(24小时)。对于某些特别顽固的攻击者,可以考虑永久封禁。
- findtime:检测窗口。Fail2ban会统计在findtime秒内某个IP的失败次数。
- maxretry:触发封禁的失败次数阈值。在findtime内达到maxretry次失败,即触发封禁。
- ignoreip:白名单IP列表。这个非常重要,一定要把自己的IP加进去,否则把自己封了就尴尬了。
深入配置:保护SSH服务
SSH是VPS管理的最基本入口,也是被攻击最多的服务。针对SSH的Fail2ban配置虽然看起来简单,但有很多调优空间。
基础SSH监狱配置
1
2
3
4
5
6
7
8
9 [sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
findtime = 300
bantime = 86400
ignoreip = 127.0.0.1/8 ::1 你的公网IP
这个配置意味着:在5分钟内,如果有3次失败的SSH登录尝试,该IP将被封禁24小时。对于大多数场景,这已经足够有效。
SSH监狱调优技巧
如果你发现自己的SSH登录偶尔也会被误封(比如输错了一两次密码),可以适当调高
1 | maxretry |
或调大
1 | findtime |
。但更好的做法是使用
1 | recidive |
监狱——它实现了一种”累进惩罚”机制:
1
2
3
4
5
6
7
8 [recidive]
enabled = true
logpath = /var/log/fail2ban.log
filter = fail2ban
maxretry = 3
findtime = 86400
bantime = 604800 # 1周
banaction = iptables-allports
这个监狱监控的是Fail2ban自己的日志。如果一个IP在过去24小时内被Fail2ban封禁过3次以上,说明这是”惯犯”,那就直接封一周。这种策略非常有效,因为大多数攻击者不会持续一周攻击同一台机器。
自定义SSH filter
有时默认的SSH filter可能无法匹配某些特殊场景。你可以创建自定义filter:
1
2
3
4
5
6 # /etc/fail2ban/filter.d/sshd-custom.local
[Definition]
failregex = ^%(__prefix_line)sFailed \w+ for .* from <HOST> port \d+ ssh2$
^%(__prefix_line)sConnection closed by authenticating user .* <HOST> port \d+ \[preauth\]$
^%(__prefix_line)sDisconnected from invalid user .* <HOST> port \d+ \[preauth\]$
ignoreregex =
然后修改
1 | jail.local |
中的 filter 指向自定义文件:
1
2
3
4 [sshd]
enabled = true
filter = sshd-custom
...
保护Web服务:Nginx和Apache
Web服务是VPS的另一大攻击面。常见的攻击包括:目录扫描、SQL注入尝试、暴力破解登录页面、CC攻击等。我们可以为Nginx配置多个监狱来应对不同场景。
Nginx基础防护
1
2
3
4
5
6
7
8 [nginx-botsearch]
enabled = true
port = http,https
filter = nginx-botsearch
logpath = /var/log/nginx/access.log
maxretry = 2
findtime = 600
bantime = 3600
这个监狱会检测访问不存在的URL(404错误)的请求,如果某个IP在短时间内触发大量404,说明它在扫描你的网站结构或寻找漏洞,应当封禁。
防止WordPress登录爆破
WordPress的
1 | /wp-login.php |
和
1 | /xmlrpc.php |
是暴力破解的重灾区。我们可以创建专门的Nginx filter来检测:
1
2
3
4
5 # /etc/fail2ban/filter.d/nginx-wordpress-login.local
[Definition]
failregex = ^<HOST> - - \[.*\] "POST /wp-login\.php HTTP/.*" 200
^<HOST> - - \[.*\] "POST /xmlrpc\.php HTTP/.*" 200
ignoreregex =
然后在
1 | jail.local |
中添加:
1
2
3
4
5
6
7
8 [nginx-wordpress-login]
enabled = true
port = http,https
filter = nginx-wordpress-login
logpath = /var/log/nginx/access.log
maxretry = 5
findtime = 300
bantime = 86400
CC攻击防护
CC攻击(Challenge Collapsar)是一种应用层DDoS攻击,通过大量看似正常的请求耗尽服务器资源。Fail2ban可以通过检测单个IP的请求频率来应对:
1
2
3
4 # /etc/fail2ban/filter.d/nginx-cc.local
[Definition]
failregex = ^<HOST> -.*"(GET|POST).*" \d+ \d+ ".*" ".*"$
ignoreregex =
1
2
3
4
5
6
7
8 [nginx-cc]
enabled = true
port = http,https
filter = nginx-cc
logpath = /var/log/nginx/access.log
maxretry = 300
findtime = 60
bantime = 600
这个配置的意思是:在1分钟内,如果某个IP发送了超过300个请求,就封禁10分钟。这里的阈值需要根据你的网站实际流量调整。如果网站正常访问量就很大,可以把
1 | maxretry |
调高到500或1000。
高级配置:Cloudflare联动与邮件通知
Cloudflare API联动封禁
如果你的网站使用了Cloudflare CDN,那么所有真实的访问IP都是Cloudflare的IP,而不是用户的实际IP。在这种情况下,Fail2ban的iptables封禁无法直接作用于真实用户。解决方法是通过Cloudflare API自动添加防火墙规则来封禁IP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 # 安装Cloudflare action
cp /etc/fail2ban/action.d/cloudflare.conf /etc/fail2ban/action.d/cloudflare.local
# 编辑 action 文件,添加你的Cloudflare API凭证
# /etc/fail2ban/action.d/cloudflare.local
[Definition]
actionstart =
actionstop =
actioncheck =
actionban = curl -s -X POST "https://api.cloudflare.com/client/v4/zones/<cfzone>/firewall/access_rules/rules" \
-H "X-Auth-Email: <cfuser>" \
-H "X-Auth-Key: <cftoken>" \
-H "Content-Type: application/json" \
--data '{"mode":"block","configuration":{"target":"ip","value":"<ip>"},"notes":"Fail2ban <name>"}'
actionunban = curl -s -X DELETE "https://api.cloudflare.com/client/v4/zones/<cfzone>/firewall/access_rules/rules/<id>" \
-H "X-Auth-Email: <cfuser>" \
-H "X-Auth-Key: <cftoken>" \
-H "Content-Type: application/json"
然后在监狱配置中指定使用Cloudflare action:
1
2
3
4
5
6
7
8
9
10 [nginx-wordpress-login]
enabled = true
port = http,https
filter = nginx-wordpress-login
logpath = /var/log/nginx/access.log
maxretry = 5
findtime = 300
bantime = 86400
banaction = cloudflare
action = %(action_mw)s
邮件通知配置
如果你想在每次封禁时收到邮件通知:
1
2
3
4
5
6 [DEFAULT]
destemail = admin@yourdomain.com
sender = fail2ban@yourdomain.com
# action_mw = 发送邮件通知 + 封禁(带whois信息)
# action_mwl = 发送邮件通知 + 封禁(带whois信息和日志行)
action = %(action_mwl)s
这需要你配置好服务器的邮件发送能力(如Postfix或SendGrid),否则邮件发送会失败。
Fail2ban运维与调试
常用命令
掌握以下命令,日常运维会非常顺手:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 # 查看所有监狱的状态
fail2ban-client status
# 查看特定监狱的状态(包括当前被封禁的IP列表)
fail2ban-client status sshd
# 手动解封一个IP
fail2ban-client set sshd unbanip 1.2.3.4
# 手动封禁一个IP
fail2ban-client set sshd banip 1.2.3.4
# 重新加载配置
fail2ban-client reload
# 重启服务
systemctl restart fail2ban
# 查看Fail2ban运行日志
tail -f /var/log/fail2ban.log
测试正则表达式
Fail2ban的配置是否正确,关键在于filter中的正则表达式能否正确匹配日志。Fail2ban提供了测试工具:
1
2
3
4
5
6
7
8 # 测试filter是否匹配日志
fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf
# 测试自定义filter
fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/nginx-wordpress-login.local
# 实时测试模式
fail2ban-regex --print-all-missed /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf
输出结果会显示匹配了多少行、失败了多少行,以及每行是否匹配。如果匹配率很低,说明正则表达式可能需要调整。
性能调优
对于流量较大的VPS,Fail2ban的日志扫描可能成为性能瓶颈。以下是一些优化建议:
- 使用
:在支持systemd的系统中,使用systemd journal作为后端比轮询日志文件更高效。配置方法:1backend = systemd1backend = systemd
(默认已自动检测)。
- 减少不必要的监狱:只启用你真正需要的监狱。每个监狱都会消耗CPU资源来扫描日志。
- 合理设置
:findtime越长,Fail2ban需要维护的状态表越大。对于高流量服务器,保持findtime在合理范围内。1findtime
- 使用
1ignoreip
过滤掉已知的爬虫IP
:Googlebot、Bingbot等搜索引擎的IP可以被添加到全局ignoreip中,避免它们被误封。
实战案例:搭建完整防御体系
下面是一个适用于大多数VPS场景的完整配置模板,涵盖了SSH、Nginx、WordPress和邮件服务的防护:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66 [DEFAULT]
bantime = 3600
findtime = 600
maxretry = 5
ignoreip = 127.0.0.1/8 ::1 你的公司IP
banaction = iptables-allports
logencoding = utf-8
[sshd]
enabled = true
port = ssh
logpath = %(sshd_log)s
maxretry = 3
findtime = 300
bantime = 86400
[sshd-ddos]
enabled = true
port = ssh
logpath = %(sshd_log)s
maxretry = 6
findtime = 30
bantime = 86400
[recidive]
enabled = true
logpath = /var/log/fail2ban.log
maxretry = 3
findtime = 86400
bantime = 604800
[nginx-botsearch]
enabled = true
port = http,https
filter = nginx-botsearch
logpath = /var/log/nginx/access.log
maxretry = 2
findtime = 600
bantime = 3600
[nginx-http-auth]
enabled = true
port = http,https
filter = nginx-http-auth
logpath = /var/log/nginx/error.log
maxretry = 5
findtime = 300
bantime = 3600
[nginx-wordpress-login]
enabled = true
port = http,https
filter = nginx-wordpress-login
logpath = /var/log/nginx/access.log
maxretry = 5
findtime = 300
bantime = 86400
[postfix]
enabled = true
port = smtp,ssmtp,submission
filter = postfix
logpath = /var/log/mail.log
maxretry = 3
findtime = 300
bantime = 86400
应用配置后,记得重启Fail2ban:
1
2 systemctl restart fail2ban
fail2ban-client status
你应该看到类似这样的输出,列出了所有已启用的监狱:
1
2
3 Status
|- Number of jail: 6
`- Jail list: sshd, sshd-ddos, recidive, nginx-botsearch, nginx-http-auth, postfix
进阶技巧与注意事项
误封处理
Fail2ban最让人头疼的问题就是误封。以下是一些减少误封的策略:
- 先使用
1banaction = iptables
(只封目标端口)而不是
(封所有端口)。这样即使误封,也只是封了特定服务端口,用户的其他服务不受影响。1iptables-allports - 使用
1findtime
和
1maxretry的黄金比例
:对于SSH,1findtime=300s, maxretry=3基本不会误封正常用户,因为正常用户不会在5分钟内输错3次密码。
- 配置白名单:在
1ignoreip
中添加自己常用的IP和VPN出口IP。
- 设置合理的bantime:除非攻击非常猛烈,否则不建议永久封禁。24小时到1周的封禁时间已经足够让大多数攻击者放弃。
与CSF(ConfigServer Security & Firewall)配合使用
如果你同时使用CSF防火墙,需要注意两者的关系。CSF和Fail2ban可以共存,但需要避免冲突:
- CSF负责端口级别的防护(阻止特定国家的IP、限制新连接数等)
- Fail2ban负责应用级别的防护(基于日志分析触发封禁)
- 建议将CSF的
1LF_PERMBLOCK
设置为0,将永久封禁交给Fail2ban的recidive监狱处理
数据库服务的防护
MySQL/MariaDB和Redis也是常见的攻击目标。虽然数据库通常不直接暴露在公网上,但如果有管理后台或通过Web应用间接访问,依然需要防护:
1
2
3
4
5
6
7
8 [mysqld-auth]
enabled = true
port = 3306
filter = mysqld-auth
logpath = /var/log/mysql/error.log
maxretry = 5
findtime = 600
bantime = 86400
总结
Fail2ban是VPS安全体系中不可或缺的一环。它轻量、高效、配置灵活,能够将服务器安全从”被动防守”升级为”主动反击”。通过本文的配置,你可以实现:
- 自动封禁SSH爆破IP(24小时至1周)
- 检测并封禁WordPress登录暴力破解
- 抑制目录扫描和CC攻击
- 通过Cloudflare联动封禁真实用户IP
- 累进惩罚机制自动处理惯犯
最后,牢记安全最佳实践:Fail2ban只是防御体系的一部分,还应配合SSH密钥认证、禁用root直接登录、定期更新系统补丁、使用防火墙(UFW/CSF)等策略,构建纵深防御体系。安全没有银弹,但Fail2ban绝对是你工具箱里最趁手的那把武器。
汤不热吧