一、fail2ban 是什么
fail2ban 是一个开源的入侵防护工具,通过实时监控日志文件,根据预定义的规则自动识别恶意行为,并调用防火墙(firewalld / iptables)封禁来源 IP。

核心能力:
- 实时监控日志,无需定时任务
- 支持正则匹配,灵活定义"恶意行为"
- 自动调用系统防火墙封禁 / 解封
- 支持设置封禁时长,到期自动解封
- 支持递增封禁(repeat offenders)
- 支持邮件通知(可选)
二、安装
dnf install -y epel-release
dnf install -y fail2ban
验证安装:
fail2ban-client --version
三、目录结构
/etc/fail2ban/
├── fail2ban.conf # 主配置(一般不改)
├── jail.conf # 默认规则(不要直接改,升级会覆盖)
├── jail.local # 自定义规则(写在这里)
├── jail.d/ # 额外 jail 配置目录
├── filter.d/ # 过滤器目录(定义匹配规则)
│ ├── apache-scan.conf # 你自己写的
│ └── apache-error.conf
├── action.d/ # 动作目录(定义封禁方式)
│ └── firewallcmd-rich-rules.conf # 调用 firewalld
└── action.d/
核心原则: 不要改 jail.conf 和 filter.d/ 下的默认文件,自定义内容写到 jail.local 和新建的 filter 文件中,升级不会被覆盖。
四、核心概念
4.1 Jail(监狱)
一条防护规则,定义了监控哪个日志、用什么过滤器、匹配多少次后封禁、封禁多久。
4.2 Filter(过滤器)
定义正则表达式,从日志中提取恶意行为的特征行。
4.3 Action(动作)
定义封禁方式,比如调用 firewalld、iptables、发送邮件等。
4.4 工作流程
→ 到期自动解封
4.5 关键参数
| 参数 | 含义 | 示例 |
|---|---|---|
enabled |
是否启用 | true / false |
port |
监控的端口 | http,https |
filter |
使用的过滤器名称 | apache-scan |
logpath |
监控的日志文件路径 | /Data/.../access.log |
maxretry |
触发封禁的匹配次数 | 30 |
findtime |
统计次数的时间窗口(秒) | 60 |
bantime |
封禁持续时间(秒),-1 为永久 |
86400(24小时) |
banaction |
封禁使用的动作 | firewallcmd-rich-rules |
五、实战配置
5.1 创建过滤器一:扫描行为检测(access.log)
cat > /etc/fail2ban/filter.d/apache-scan.conf << 'EOF'
[Definition]
failregex = ^<HOST> -.*"(GET|POST|HEAD).*/(wp-admin|wp-login|xmlrpc\.php|wp-json).*".*$
^<HOST> -.*"(GET|POST|HEAD).*/\.?env.*".*$
^<HOST> -.*"(GET|POST|HEAD).*/\.git(/|config).*".*$
^<HOST> -.*"(GET|POST|HEAD).*/\.gitlab-ci\.yml.*".*$
^<HOST> -.*"(GET|POST|HEAD).*/\.github/.*".*$
^<HOST> -.*"(GET|POST|HEAD).*/\.idea/.*".*$
^<HOST> -.*"(GET|POST|HEAD).*/\.vscode/.*".*$
^<HOST> -.*"(GET|POST|HEAD).*/(amplify\.yml|firebase\.json|vite\.config|nuxt\.config|next\.config)\.?.*".*$
^<HOST> -.*"(GET|POST|HEAD).*/(Jenkinsfile|panel|\.pypirc|composer\.json).*".*$
^<HOST> -.*"(GET|POST|HEAD).*/(db|database)\.sql.*".*$
^<HOST> -.*"(GET|POST|HEAD).*/(storage/logs|var/log|config)\b.*".*$
^<HOST> -.*"(GET|POST|HEAD).*/goform/.*".*$
ignoreregex =
EOF
涵盖的扫描类别:
| 类别 | 匹配的路径特征 |
|---|---|
| WordPress 扫描 | wp-admin、wp-login、xmlrpc.php、wp-json |
| 环境文件泄露 | .env、env.js、environment.ts 等 |
| Git 仓库暴露 | .git/、.git/config |
| CI/CD 配置 | .gitlab-ci.yml、.github/workflows/ |
| IDE 配置泄露 | .idea/、.vscode/ |
| 框架配置文件 | vite.config、nuxt.config、next.config、firebase.json |
| 开发工具文件 | Jenkinsfile、.pypirc、composer.json |
| 数据库文件 | db.sql、database.sql |
| 日志泄露 | storage/logs、var/log |
| 设备探测 | goform/ |
5.2 创建过滤器二:错误日志检测(error.log)
cat > /etc/fail2ban/filter.d/apache-error.conf << 'EOF'
[Definition]
failregex = ^.*$$client <HOST>$$ .* (AH01630|AH01797|AH00128):.*
^.*$$client <HOST>$$ (File does not exist|script not found|denied by server configuration).*$
^.*$$client <HOST>$$ .* (SQL injection|XSS|eval\(|base64_decode).*$
^.*$$client <HOST>$$ .* PHP (Fatal|Parse) error.*$
ignoreregex =
EOF
5.3 验证过滤器能否匹配日志
fail2ban-regex /Data/Public_Root/iewb.net/logs/access.log /etc/fail2ban/filter.d/apache-scan.conf
输出中 Failregex: 152 hits 表示匹配成功,过滤器可正常使用。
fail2ban-regex /Data/Public_Root/iewb.net/logs/error.log /etc/fail2ban/filter.d/apache-error.conf
5.4 创建 jail.local 配置
cat > /etc/fail2ban/jail.local << 'EOF'
[DEFAULT]
# 封禁动作:使用 firewalld rich rules
banaction = firewallcmd-rich-rules
# 封禁时间:24小时(秒),-1 为永久
bantime = 86400
# 统计时间窗口:60秒内
findtime = 60
# 忽略本机和指定IP(多个用空格分隔)
ignoreip = 127.0.0.1/8
# ============ 扫描行为防护 ============
[apache-scan]
enabled = true
port = http,https
filter = apache-scan
logpath = /Data/Public_Root/iewb.net/logs/access.log
maxretry = 30
findtime = 60
bantime = 86400
# ============ 错误日志防护 ============
[apache-error]
enabled = true
port = http,https
filter = apache-error
logpath = /Data/Public_Root/iewb.net/logs/error.log
maxretry = 10
findtime = 60
bantime = 86400
EOF
logpath 即可。5.5 启动与开机自启
systemctl enable --now fail2ban
六、常用管理命令
6.1 查看状态
# 查看所有 jail 列表
fail2ban-client status
# 查看某个 jail 详情(含封禁 IP 数量和列表)
fail2ban-client status apache-scan
fail2ban-client status apache-error
# 只看被封禁的 IP
fail2ban-client status apache-scan | grep "Banned IP"
6.2 手动封禁 / 解封
# 手动封禁
fail2ban-client set apache-scan banip 1.2.3.4
# 手动解封
fail2ban-client set apache-scan unbanip 1.2.3.4
6.3 查看日志
# 实时跟踪
tail -f /var/log/fail2ban.log
# 查看今天的封禁记录
grep "Ban" /var/log/fail2ban.log | grep "$(date +%Y-%m-%d)"
6.4 重载配置
# 修改 jail.local 或过滤器后重载
fail2ban-client reload
# 或重启
systemctl restart fail2ban
6.5 暂停与恢复
# 暂停(不封新 IP,已封的保留)
fail2ban-client stop apache-scan
# 恢复
fail2ban-client start apache-scan
七、进阶用法
7.1 修改封禁时间
# 查看当前封禁时间
fail2ban-client get apache-scan bantime
# 临时修改为永久封禁
fail2ban-client set apache-scan bantime -1
# 临时修改为 1 小时
fail2ban-client set apache-scan bantime 3600
7.2 忽略特定 IP
在 jail.local 的 [DEFAULT] 中:
# 多个 IP 用空格分隔,支持 CIDR
ignoreip = 127.0.0.1/8 1.2.3.4 10.0.0.0/8
7.3 查看 firewalld 中 fail2ban 添加的规则
firewall-cmd --list-rich-rules | grep fail2ban
7.4 递增封禁时间(repeat offenders)
在 jail.local 中对应 jail 下添加:
[apache-scan]
bantime = 3600
bantime.increment = true
bantime.factor = 24
bantime.maxtime = 604800
效果:第 1 次封 1 小时 → 第 2 次封 24 小时 → 第 3 次封 7 天
7.5 SSH 暴力破解防护
在 jail.local 中添加:
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/secure
maxretry = 5
findtime = 600
bantime = 3600
八、故障排查
# 测试过滤器是否能匹配日志
fail2ban-regex /Data/Public_Root/iewb.net/logs/access.log /etc/fail2ban/filter.d/apache-scan.conf
# 检查配置语法
fail2ban-client --test
# 查看详细运行日志
journalctl -u fail2ban -f
# 确认 firewalld 正常运行
systemctl status firewalld
# 查看 fail2ban 运行状态
systemctl status fail2ban
九、速查表
| 项目 | 说明 |
|---|---|
| 配置文件 | /etc/fail2ban/jail.local |
| 过滤器目录 | /etc/fail2ban/filter.d/*.conf |
| 日志文件 | /var/log/fail2ban.log |
| 启动服务 | systemctl enable --now fail2ban |
| 查看状态 | fail2ban-client status apache-scan |
| 查看封禁 IP | fail2ban-client status apache-scan | grep "Banned IP" |
| 解封 IP | fail2ban-client set apache-scan unbanip x.x.x.x |
| 重载配置 | fail2ban-client reload |
| 测试过滤器 | fail2ban-regex 日志路径 过滤器路径 |
| 查看日志 | tail -f /var/log/fail2ban.log |