作为一名运维工程师,你一定遇到过这种情况:服务器日志里密密麻麻的 SSH 登录失败记录,Nginx 访问日志里某个 IP 疯狂扫描你的网站。手动封禁 IP?太累了。iptables 规则写到飞起?治标不治本。
fail2ban 就是为解决这个问题而生的——它能自动分析日志,发现恶意行为后自动封禁 IP,是你服务器安全的第一道防线。
什么是 fail2ban
fail2ban 是一款开源的入侵防护工具,工作原理很简单:
- 监控日志文件:实时读取指定日志(如 /var/log/auth.log)
- 正则匹配:用预定义的 filter 规则识别失败行为
- 计数触发:在指定时间窗口内达到阈值次数
- 执行动作:自动调用 iptables/firewalld 封禁 IP
整个过程完全自动化,你只需要配置好规则,剩下的交给它。
为什么选择 fail2ban
市面上安全工具不少,为什么 fail2ban 能成为 Linux 服务器的标配?
| 特性 | fail2ban | denyhosts | CSF |
|---|
|——|———-|———–|—–|
| 支持服务 | 任意日志 | 仅 SSH | 多种 |
|---|---|---|---|
| 自定义规则 | 灵活 | 有限 | 复杂 |
| 资源占用 | 低 | 低 | 高 |
| 社区活跃 | 活跃 | 停更 | 活跃 |
| 学习成本 | 中等 | 低 | 高 |
核心优势:fail2ban 不仅能保护 SSH,还能保护 Nginx、Apache、Postfix、Dovecot 等任何能输出日志的服务。
安装与基础配置
安装
`bash
# Ubuntu/Debian
sudo apt update
sudo apt install fail2ban -y
# CentOS/RHEL
sudo yum install epel-release -y
sudo yum install fail2ban -y
# Arch Linux
sudo pacman -S fail2ban
`
安装后启动服务:
`bash
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
`
配置文件结构
fail2ban 的配置文件位于 /etc/fail2ban/:
`
/etc/fail2ban/
├── fail2ban.conf # 主配置(日志级别、PID文件等)
├── jail.conf # 默认规则(不要修改!)
├── jail.local # 自定义规则(你改这个)
├── jail.d/ # 额外规则片段
├── filter.d/ # 过滤器规则
├── action.d/ # 动作定义
└── fail2ban.service # systemd 服务文件
`
重要:永远不要直接修改 jail.conf,升级会覆盖。所有自定义配置写在 jail.local。
基础配置示例
创建 /etc/fail2ban/jail.local:
`ini
[DEFAULT]
# 默认封禁时间(秒),1小时
bantime = 3600
# 检测时间窗口(秒),10分钟
findtime = 600
# 最大失败次数
maxretry = 5
# 使用 firewalld(CentOS 7+)或 iptables
banaction = firewallcmd-ipset
# 忽略本地回环
ignoreip = 127.0.0.1/8 ::1
# 忽略内网IP(根据你的网络调整)
ignoreip = 127.0.0.1/8 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 86400
`
这个配置的意思是:SSH 登录失败 3 次,封禁 24 小时。
核心概念详解
Jail(监狱)
Jail 是 fail2ban 的核心概念,代表一个保护规则。每个 jail 定义了:
- 监控哪个日志(logpath)
- 用什么规则匹配(filter)
- 失败几次触发(maxretry)
- 封禁多久(bantime)
- 在多长时间内计数(findtime)
Filter(过滤器)
过滤器定义了如何从日志中识别恶意行为。它们是正则表达式文件,位于 /etc/fail2ban/filter.d/。
查看 SSH 过滤器:
`bash
cat /etc/fail2ban/filter.d/sshd.conf
`
你会看到类似这样的规则:
`ini
failregex = ^.*Failed password for .* from .*$
^.*Invalid user .* from .*$
^.*Connection closed by authenticating user .* .*[preauth]$
`
是占位符,fail2ban 会自动提取匹配的 IP 地址。
Action(动作)
动作定义了封禁 IP 的方式。默认使用 iptables,常见动作包括:
- iptables-multiport:在指定端口封禁
- iptables-allports:封禁所有端口
- firewallcmd-ipset:使用 firewalld(CentOS 7+)
- route:通过路由表封禁
你也可以自定义动作,比如发送邮件通知。
SSH 安全防护
SSH 是服务器最常见的攻击目标,也是 fail2ban 最基础的保护场景。
基础 SSH 防护
`ini
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 86400
findtime = 600
`
针对暴力破解的强化配置
如果你的服务器暴露在公网,建议更严格:
`ini
[sshd-aggressive]
enabled = true
port = ssh
filter = sshd[mode=aggressive]
logpath = /var/log/auth.log
maxretry = 2
bantime = 604800
findtime = 3600
`
mode=aggressive 会匹配更多恶意行为模式,包括:
- 密码错误
- 无效用户
- Root 登录尝试
- 暴力破解特征
保护非标准 SSH 端口
如果你改了 SSH 端口(比如 2222):
`ini
[sshd-custom]
enabled = true
port = 2222
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 86400
`
Nginx 安全防护
Nginx 是 Web 服务器的主力,也是攻击者的重点目标。
防止暴力破解登录页面
创建过滤器 /etc/fail2ban/filter.d/nginx-auth.conf:
`ini
[Definition]
failregex = ^ -.*”(GET|POST).*/login.* HTTP/.*” (401|403) .*$
^ -.*”(GET|POST).*/admin.* HTTP/.*” (401|403) .*$
ignoreregex =
`
配置 jail:
`ini
[nginx-auth]
enabled = true
port = http,https
filter = nginx-auth
logpath = /var/log/nginx/access.log
maxretry = 5
bantime = 3600
findtime = 600
`
防止扫描器和爬虫
创建过滤器 /etc/fail2ban/filter.d/nginx-scan.conf:
`ini
[Definition]
failregex = ^ -.*(GET|HEAD) /(wp-admin|wp-login|xmlrpc|phpmyadmin).* HTTP/.*” (404|403) .*$
^ -.*”GET /(env|info|phpinfo|test|shell).* HTTP/.*” (404|403) .*$
ignoreregex =
`
配置 jail:
`ini
[nginx-scan]
enabled = true
port = http,https
filter = nginx-scan
logpath = /var/log/nginx/access.log
maxretry = 10
bantime = 7200
findtime = 3600
`
防止 DDoS 和 CC 攻击
创建过滤器 /etc/fail2ban/filter.d/nginx-req-limit.conf:
`ini
[Definition]
failregex = limiting requests, excess: .* by zone .*, client:
ignoreregex =
`
配合 Nginx 的 limit_req_zone 使用:
`nginx
# nginx.conf
http {
limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s;
server {
location / {
limit_req zone=req_limit burst=20 nodelay;
}
}
}
`
配置 jail:
`ini
[nginx-req-limit]
enabled = true
port = http,https
filter = nginx-req-limit
logpath = /var/log/nginx/error.log
maxretry = 5
bantime = 3600
findtime = 600
`
防止恶意 User-Agent
创建过滤器 /etc/fail2ban/filter.d/nginx-bad-agent.conf:
`ini
[Definition]
failregex = ^ -.*”.*” .* “.*(sqlmap|nikto|nmap|masscan|python-requests|Go-http-client).*”$
ignoreregex =
`
配置 jail:
`ini
[nginx-bad-agent]
enabled = true
port = http,https
filter = nginx-bad-agent
logpath = /var/log/nginx/access.log
maxretry = 1
bantime = 86400
findtime = 86400
`
Apache 安全防护
如果你用的是 Apache,配置方式类似。
防止暴力破解
`ini
[apache-auth]
enabled = true
port = http,https
filter = apache-auth
logpath = /var/log/apache2/error.log
maxretry = 5
bantime = 3600
findtime = 600
`
防止扫描
`ini
[apache-scan]
enabled = true
port = http,https
filter = apache-scan
logpath = /var/log/apache2/access.log
maxretry = 10
bantime = 7200
findtime = 3600
`
邮件服务防护
邮件服务器是垃圾邮件和暴力破解的重灾区。
Postfix 防护
`ini
[postfix]
enabled = true
port = smtp,465,submission
filter = postfix
logpath = /var/log/mail.log
maxretry = 3
bantime = 3600
findtime = 600
[postfix-sasl]
enabled = true
port = smtp,465,submission
filter = postfix-sasl
logpath = /var/log/mail.log
maxretry = 3
bantime = 86400
findtime = 600
`
Dovecot 防护
`ini
[dovecot]
enabled = true
port = pop3,pop3s,imap,imaps
filter = dovecot
logpath = /var/log/mail.log
maxretry = 3
bantime = 3600
findtime = 600
`
进阶配置
自定义过滤器
假设你有一个自定义应用,日志格式如下:
`
2024-01-15 10:30:45 [ERROR] Login failed from 192.168.1.100 – Invalid credentials
`
创建过滤器 /etc/fail2ban/filter.d/myapp.conf:
`ini
[Definition]
failregex = ^.*[ERROR] Login failed from – .*$
ignoreregex =
`
测试过滤器:
`bash
fail2ban-regex /var/log/myapp.log /etc/fail2ban/filter.d/myapp.conf
`
递增封禁时间
对于反复攻击的 IP,可以递增封禁时间:
`ini
[recidive]
enabled = true
filter = recidive
logpath = /var/log/fail2ban.log
action = iptables-allports[name=recidive]
bantime = 604800
findtime = 86400
maxretry = 3
`
这个 jail 会监控 fail2ban 自己的日志,如果一个 IP 在 24 小时内被封禁 3 次以上,就封禁 7 天。
邮件通知
配置封禁时发送邮件通知:
`ini
[DEFAULT]
# 在 jail.local 的 [DEFAULT] 部分添加
action = %(action_mwl)s
# action_mwl = ban + 发送邮件 + 包含日志
# action_mw = ban + 发送邮件(不含日志)
# action_ml = ban + 只发日志(不封禁)
`
配置邮件参数 /etc/fail2ban/action.d/mail.conf:
`ini
[Definition]
actionstart =
actionstop =
actioncheck =
actionban = printf %%b “Hi,nnThe IP has just been banned by Fail2Ban after attempts against .nnRegards,nFail2Ban” | mail -s “[Fail2Ban] : banned ” your@email.com
actionunban =
`
使用 firewalld(CentOS 7+)
CentOS 7 默认使用 firewalld,需要调整 banaction:
`ini
[DEFAULT]
banaction = firewallcmd-ipset
banaction_allports = firewallcmd-ipset
`
或者使用 rich rules:
`ini
[DEFAULT]
banaction = firewallcmd-rich-rules[actiontype=]
`
使用 nftables
如果你使用 nftables(新版 Linux 推荐):
`ini
[DEFAULT]
banaction = nftables[type=multiport]
banaction_allports = nftables[type=allports]
`
故障排除
查看 fail2ban 状态
`bash
# 查看所有 jail 状态
fail2ban-client status
# 查看特定 jail 状态
fail2ban-client status sshd
# 查看被封禁的 IP
fail2ban-client get sshd banned
# 查看 jail 配置
fail2ban-client get sshd maxretry
fail2ban-client get sshd bantime
`
手动封禁/解封 IP
`bash
# 手动封禁 IP
fail2ban-client set sshd banip 192.168.1.100
# 手动解封 IP
fail2ban-client set sshd unbanip 192.168.1.100
# 查看封禁历史
fail2ban-client get sshd banip –with-time
`
测试过滤器
`bash
# 测试过滤器是否能匹配日志
fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf
# 详细输出
fail2ban-regex -v /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf
# 测试单行
fail2ban-regex “Failed password for root from 192.168.1.100 port 22 ssh2” /etc/fail2ban/filter.d/sshd.conf
`
常见问题
问题 1:fail2ban 启动失败
`bash
# 查看错误日志
journalctl -u fail2ban -f
# 常见原因:配置文件语法错误
fail2ban-client -t
`
问题 2:IP 被封禁但还能访问
`bash
# 检查 iptables 规则
iptables -L -n | grep f2b
# 检查 firewalld 规则
firewall-cmd –list-all
# 检查日志
tail -f /var/log/fail2ban.log
`
问题 3:误封正常用户
`bash
# 立即解封
fail2ban-client set sshd unbanip 用户IP
# 添加到白名单
# 在 jail.local 的 [DEFAULT] 部分
ignoreip = 127.0.0.1/8 用户IP
`
问题 4:日志轮转后 fail2ban 不工作
`bash
# 创建 logrotate 配置
cat > /etc/logrotate.d/fail2ban << EOF
/var/log/fail2ban.log {
weekly
rotate 4
compress
delaycompress
missingok
notifempty
create 0640 root root
postrotate
fail2ban-client flushlogs > /dev/null 2>&1 || true
endscript
}
EOF
`
调试模式
`bash
# 前台运行,查看详细日志
fail2ban-client -f start
# 或者提高日志级别
fail2ban-client set loglevel 4
`
性能优化
使用 ipset 提升性能
当封禁 IP 数量很多时,iptables 性能会下降。使用 ipset 可以大幅提升:
`ini
[DEFAULT]
banaction = iptables-ipset-proto4
# 或者
banaction = iptables-ipset-proto6
`
调整监控频率
默认 fail2ban 每秒检查一次日志,可以根据服务器负载调整:
`ini
# /etc/fail2ban/fail2ban.conf
[Definition]
# 检查间隔(秒)
dbpurgeage = 86400
`
数据库优化
fail2ban 默认使用 SQLite 存储封禁记录,大量 IP 时可以优化:
`bash
# 查看数据库大小
ls -lh /var/lib/fail2ban/fail2ban.sqlite3
# 清理旧记录
fail2ban-client flushlogs
`
最佳实践
1. 合理设置阈值
- SSH:maxretry=3, bantime=86400(24小时)
- Web 登录:maxretry=5, bantime=3600(1小时)
- API 接口:maxretry=10, bantime=1800(30分钟)
2. 必须设置白名单
`ini
[DEFAULT]
# 至少包含以下 IP
ignoreip = 127.0.0.1/8 ::1 你的管理IP
`
3. 启用持久化
`ini
[DEFAULT]
# 封禁记录持久化到数据库
dbfile = /var/lib/fail2ban/fail2ban.sqlite3
dbpurgeage = 604800
`
4. 定期检查状态
`bash
# 创建监控脚本
cat > /usr/local/bin/fail2ban-status.sh << 'EOF'
#!/bin/bash
echo “=== Fail2Ban Status ===”
fail2ban-client status
echo “”
echo “=== Banned IPs ===”
for jail in $(fail2ban-client status | grep “Jail list” | sed ‘s/.*://;s/,/ /g’); do
echo “Jail: $jail”
fail2ban-client status $jail | grep “Banned IP”
done
EOF
chmod +x /usr/local/bin/fail2ban-status.sh
`
5. 配合其他工具
fail2ban 不是万能的,建议配合:
- iptables 基础规则:限制连接速率
- SSH 密钥登录:禁用密码登录
- VPN:管理端口不对外暴露
- IDS/IPS:更高级的入侵检测
实战案例
案例 1:保护 WordPress 登录
`ini
# /etc/fail2ban/filter.d/wordpress.conf
[Definition]
failregex = ^ -.*”(GET|POST) /wp-login.php.*$
^ -.*”(GET|POST) /xmlrpc.php.*$
ignoreregex =
# /etc/fail2ban/jail.local
[wordpress]
enabled = true
port = http,https
filter = wordpress
logpath = /var/log/nginx/access.log
maxretry = 5
bantime = 3600
findtime = 600
`
案例 2:保护 GitLab
`ini
# /etc/fail2ban/filter.d/gitlab.conf
[Definition]
failregex = ^ -.*”(GET|POST) /users/sign_in.* HTTP/.*” (401|422) .*$
^ -.*”(GET|POST) /users/auth/.* HTTP/.*” (401|422) .*$
ignoreregex =
[gitlab]
enabled = true
port = http,https
filter = gitlab
logpath = /var/log/gitlab/gitlab-rails/production.log
maxretry = 5
bantime = 3600
findtime = 600
`
案例 3:保护 MySQL
`ini
# /etc/fail2ban/filter.d/mysqld.conf
[Definition]
failregex = ^.*Access denied for user .* from .*$
ignoreregex =
[mysqld]
enabled = true
port = 3306
filter = mysqld
logpath = /var/log/mysql/error.log
maxretry = 3
bantime = 86400
findtime = 600
`
总结
fail2ban 是服务器安全的瑞士军刀,简单但强大。通过合理配置,它可以:
- 自动封禁恶意 IP,减少人工干预
- 保护 SSH、Web、邮件等多种服务
- 灵活的自定义规则适应各种场景
- 低资源占用,适合各种规模服务器
记住几个关键点:
- 永远设置白名单,避免把自己锁在外面
- 测试过滤器,确保规则正确匹配
- 监控 fail2ban 日志,及时发现问题
- 配合其他安全措施,多层防护
安全无小事,fail2ban 只是开始。养成良好的安全习惯,定期更新系统,使用强密码或密钥认证,才能让你的服务器固若金汤。
作者:攀岩者 | 技术总监 | 19年IT全栈实战
精通网络、安全、云计算、容器、数据库、超算,持证 PMP、ITIL、CKA、网络工程师等。主导过多个千万级政务与智慧城市项目,从售前到交付全流程打通。热衷开源,日拱一卒,每天分享技术笔记,陪你从零基础到运维达人。
发表回复