Fail2ban:暴力破解的自动防御系统
概述
Fail2ban 是一款开源的入侵防御软件,通过扫描服务日志文件,发现多次认证失败的 IP 地址,然后自动将其加入防火墙黑名单,在一段时间内阻止其继续访问。
简单来说:有人疯狂尝试 SSH 密码?Fail2ban 检测到后自动封了他的 IP。
攻击者 IP ──▶ 尝试 SSH 登录(失败 ×3)──▶ Fail2ban 检测到 ──▶ iptables/nftables 封禁
│
攻击者被挡住 ──◀──────────────────────────────┘
核心概念
| 概念 | 说明 |
|---|---|
| 监狱(jail) | 一个"监控规则",定义监控哪个服务、使用什么过滤器、封禁多久 |
| 过滤器(filter) | 从日志中匹配失败尝试的正则表达式规则 |
| 动作(action) | 检测到攻击后执行的操作(封禁 IP、发送邮件等) |
| 封禁时间(bantime) | IP 被封禁的时长(秒) |
| 发现时间(findtime) | 在这个时间窗口内统计失败次数 |
| 最大重试(maxretry) | 在 findtime 内允许的最大失败次数,超过则封禁 |
安装
Debian / Ubuntu
sudo apt update
sudo apt install fail2ban
# 安装后自动启动
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
# 查看状态
sudo systemctl status fail2ban
RHEL / Rocky / AlmaLinux
sudo dnf install epel-release
sudo dnf install fail2ban
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
# RHEL 默认使用 firewalld,需要安装 firewalld 动作插件
# fail2ban 会自动检测并使用合适的防火墙后端
验证安装
fail2ban-client --version
# Fail2Ban v1.0.2
sudo fail2ban-client status
# Status
# |- Number of jail: 0
# `- Jail list:
首次配置
Fail2ban 的核心配置位于 /etc/fail2ban/ 目录:
/etc/fail2ban/
├── fail2ban.conf # 主配置文件(日志级别、socket 路径等)
├── fail2ban.local # 主配置本地覆盖(推荐在此修改而非 fail2ban.conf)
├── jail.conf # 监狱配置(默认规则,**不要直接编辑**)
├── jail.local # 监狱本地覆盖配置(在此自定义)
├── jail.d/ # 监狱配置片段目录(推荐方式)
│ └── *.conf
├── filter.d/ # 过滤器定义(匹配各服务的日志)
│ ├── sshd.conf
│ ├── nginx-http-auth.conf
│ └── ...
├── action.d/ # 动作定义(封禁、通知等)
│ ├── iptables.conf
│ ├── nftables.conf
│ ├── ufw.conf
│ └── ...
└── fail2ban-test.conf
配置原则
永远不要直接编辑
jail.conf—— 它会被软件包更新覆盖。正确做法:在
jail.local或jail.d/local.conf中覆盖设置。
最小配置:保护 SSH
创建 /etc/fail2ban/jail.local:
[DEFAULT]
# 封禁时间:1 小时(秒)
bantime = 1h
# 时间窗口:10 分钟内
findtime = 10m
# 最大失败次数:5 次
maxretry = 5
# 默认动作:iptables 封禁(fail2ban 会自动选 nftables 或 iptables)
banaction = iptables-allports
# 封禁后发送邮件通知(可选,需配置 sendmail)
# action = %(action_mwl)s
[sshd]
# 启用 SSH 监狱
enabled = true
# SSH 日志路径(系统会自动检测)
# logpath = /var/log/auth.log # Debian/Ubuntu
# logpath = /var/log/secure # RHEL/CentOS
启动并验证
# 重新加载配置
sudo fail2ban-client reload
# 查看所有活动的监狱
sudo fail2ban-client status
# 查看 SSH 监狱状态
sudo fail2ban-client status sshd
# 输出示例:
# Status for the jail: sshd
# |- Filter
# | |- Currently failed: 3
# | |- Total failed: 42
# | `- File list: /var/log/auth.log
# `- Actions
# |- Currently banned: 2
# |- Total banned: 15
# `- Banned IP list: 203.0.113.5 198.51.100.20
常用命令
# ===== 状态查看 =====
# 查看所有监狱
sudo fail2ban-client status
# 查看特定监狱详情
sudo fail2ban-client status sshd
# 查看 fail2ban 运行状态
sudo systemctl status fail2ban
# ===== 封禁管理 =====
# 手动封禁一个 IP
sudo fail2ban-client set sshd banip 1.2.3.4
# 手动解封一个 IP
sudo fail2ban-client set sshd unbanip 1.2.3.4
# 查看所有已封禁的 IP
sudo fail2ban-client get sshd banned
# ===== 配置重载 =====
# 重新加载所有配置
sudo fail2ban-client reload
# 重新加载单个监狱
sudo fail2ban-client reload sshd
# ===== 日志查看 =====
# 实时查看 Fail2ban 日志
sudo tail -f /var/log/fail2ban.log
# 查看最近封禁记录
sudo grep "Ban" /var/log/fail2ban.log
配置详解
全局配置([DEFAULT] 段)
[DEFAULT]
# ---- 封禁策略 ----
# 封禁时长(秒),可带后缀:s/m/h/d/w/mo/y
# -1 = 永久封禁(直到手动解封)
bantime = 1h
# 时间窗口(在此时间段内统计失败次数)
findtime = 10m
# 在 findtime 内超过此次数即封禁
maxretry = 5
# ---- 防火墙后端 ----
# 自动检测防火墙工具
banaction = iptables-allports
# 如果使用 nftables
# banaction = nftables-allports
# 如果使用 ufw
# banaction = ufw
# ---- 日志与通知 ----
# 日志级别:CRITICAL, ERROR, WARNING, NOTICE, INFO, DEBUG
loglevel = INFO
# 日志文件位置
logtarget = /var/log/fail2ban.log
# 封禁时发送邮件(需配置 sendmail)
# action = %(action_mwl)s
# action_mw = 发送邮件(含日志)
# action_mwl = 发送邮件(含日志+WHOIS)
# ---- 白名单 ----
# 不封禁的 IP 列表(空格分隔)
ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24
# ---- 后端模式 ----
# 日志监控后端:auto, polling, gamin, pyinotify, systemd
backend = systemd # systemd 日志最推荐
监狱配置(各服务的 [xxx] 段)
# ===== SSH 保护 =====
[sshd]
enabled = true
port = ssh
logpath = %(sshd_log)s # 自动匹配系统 SSH 日志路径
backend = %(sshd_backend)s
# 如果你改了 SSH 端口:
# port = 2222
# 更严格的 SSH 保护
[sshd-ddos]
enabled = true
port = ssh
logpath = %(sshd_log)s
maxretry = 3
findtime = 5m
bantime = 24h
# ===== Nginx 保护 =====
# 保护 Nginx HTTP 认证
[nginx-http-auth]
enabled = true
logpath = /var/log/nginx/error.log
# 保护 Nginx 站点(404 扫描检测)
[nginx-botsearch]
enabled = true
logpath = /var/log/nginx/access.log
maxretry = 10
findtime = 60
# ===== Apache 保护 =====
[apache-auth]
enabled = true
logpath = /var/log/apache2/error.log
[apache-badbots]
enabled = true
logpath = /var/log/apache2/access.log
maxretry = 1
# ===== MySQL/MariaDB 保护 =====
[mysqld-auth]
enabled = true
logpath = /var/log/mysql/error.log
# ===== Postfix 邮件服务器保护 =====
[postfix]
enabled = true
logpath = /var/log/mail.log
# ===== vsftpd FTP 保护 =====
[vsftpd]
enabled = true
logpath = /var/log/vsftpd.log
# ===== webadmin 面板保护 =====
[wordpress]
enabled = true
logpath = /var/log/wordpress/auth.log
maxretry = 5
[php-url-fopen]
enabled = true
logpath = /var/log/apache2/access.log
实际场景配置
场景 1:生产服务器标准配置
创建 /etc/fail2ban/jail.d/server.conf:
[DEFAULT]
# 白名单:内网和公司 IP 豁免
ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24 203.0.113.0/24
# 全局封禁 24 小时
bantime = 24h
# 10 分钟内失败 5 次
findtime = 10m
maxretry = 5
# 使用 nftables(现代系统推荐)
banaction = nftables-allports
# 封禁时发邮件通知管理员
action = %(action_mwl)s
# 邮件配置(需先配置 sendmail 或 postfix)
mta = sendmail
destemail = admin@example.com
sender = fail2ban@example.com
# ---- 各服务配置 ----
[sshd]
enabled = true
[nginx-http-auth]
enabled = true
logpath = /var/log/nginx/error.log
[nginx-botsearch]
enabled = true
logpath = /var/log/nginx/access.log
maxretry = 5
[nginx-bad-request]
enabled = true
logpath = /var/log/nginx/access.log
maxretry = 3
findtime = 60
bantime = 1w
场景 2:WordPress 站点保护
# /etc/fail2ban/jail.d/wordpress.conf
# 方式一:使用 WordPress 插件将登录失败记录到日志
# 安装 "WP fail2ban" 插件后:
[wordpress]
enabled = true
logpath = /var/log/wordpress.log
maxretry = 5
findtime = 5m
bantime = 1h
# 方式二:直接通过 Nginx/Apache 日志拦截
[nginx-http-auth]
enabled = true
logpath = /var/log/nginx/error.log
# 拦截 XML-RPC 暴力破解(常用于 WordPress)
[nginx-xmlrpc]
enabled = true
logpath = /var/log/nginx/access.log
maxretry = 3
port = http,https
场景 3:Docker 容器中的 Fail2ban
# Fail2ban 推荐直接在宿主机部署,而非容器内
# 因为它需要直接操作 iptables/nftables
# 如果你一定要放容器里,需要这些特权:
docker run -d \
--name fail2ban \
--restart=always \
--cap-add=NET_ADMIN \
--cap-add=NET_RAW \
-v /var/log:/var/log:ro \
-v /etc/fail2ban:/etc/fail2ban:ro \
-v /etc/localtime:/etc/localtime:ro \
crazymax/fail2ban:latest
场景 4:配合 UFW 使用
# /etc/fail2ban/jail.d/ufw.conf
[DEFAULT]
# 将 UFW 作为 banaction
banaction = ufw
[sshd]
enabled = true
Fail2ban 会自动调用 ufw deny from <IP> 来封禁。
场景 5:邮件通知配置
# 1. 安装邮件发送工具
sudo apt install sendmail # Debian/Ubuntu
sudo dnf install sendmail # RHEL
# 或使用 postfix 作为 MTA
sudo apt install postfix mailutils
# 2. 配置 fail2ban 邮件通知
# /etc/fail2ban/jail.d/notification.conf
[DEFAULT]
action = %(action_mwl)s
mta = sendmail
destemail = admin@example.com
sender = fail2ban@example.com
action_mwl 会发送包含 WHOIS 信息的封禁通知邮件,格式类似:
Hi,
The IP 203.0.113.5 has just been banned by Fail2ban after
5 attempts against "sshd".
Here are more information about 203.0.113.5:
...
自定义过滤器
如果内置过滤器不满足需求,可以自定义。
创建 Nginx 404 扫描过滤器
# /etc/fail2ban/filter.d/nginx-404.conf
[Definition]
failregex = ^<HOST> - - \[.*\] "GET .* HTTP/.*" 404 .*$
ignoreregex =
# 使用说明:
# <HOST> 是 Fail2ban 的占位符,自动匹配 IP 地址
# 该过滤器匹配 Nginx 访问日志中返回 404 的请求
对应监狱配置:
# /etc/fail2ban/jail.d/nginx-404.conf
[nginx-404]
enabled = true
port = http,https
logpath = /var/log/nginx/access.log
maxretry = 20
findtime = 60
bantime = 1h
测试自定义过滤器
# 使用 fail2ban-regex 工具测试正则是否匹配
sudo fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/nginx-404.conf
# 输出示例:
# Results
# =======
# Failregex: 43 total
# |- Regular expression: ^<HOST> - - \[.*\] "GET .* HTTP/.*" 404 .*$
# `- 43 matches
# Ignoreregex: 0 total
日志分析
Fail2ban 自身日志位于 /var/log/fail2ban.log:
# 查看最近封禁
sudo grep "Ban" /var/log/fail2ban.log | tail -20
# 输出示例:
# 2026-01-15 10:23:45,123 fail2ban.actions [1234]: NOTICE [sshd] Ban 203.0.113.5
# 2026-01-15 10:23:45,456 fail2ban.actions [1234]: NOTICE [sshd] Ban 198.51.100.20
# 2026-01-15 11:30:00,789 fail2ban.actions [1234]: NOTICE [sshd] Unban 203.0.113.5
# 查看封禁统计
sudo grep "Ban" /var/log/fail2ban.log | wc -l
# 按 IP 统计封禁次数
sudo grep "Ban" /var/log/fail2ban.log | grep -oP '\d+\.\d+\.\d+\.\d+' | sort | uniq -c | sort -rn | head -10
# 查看实时日志
sudo tail -f /var/log/fail2ban.log
高级技巧
1. 封禁后发送 Webhook(企业微信/钉钉/Slack)
创建自定义动作 /etc/fail2ban/action.d/send_webhook.conf:
[Definition]
actionban = curl -s -X POST "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"msgtype":"text","text":{"content":"Fail2ban 封禁通知\nIP: <ip>\n服务: <name>\n时间: <time>"}}'
actionunban = curl -s -X POST "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"msgtype":"text","text":{"content":"Fail2ban 解封通知\nIP: <ip>\n服务: <name>\n时间: <time>"}}'
在监狱配置中引用:
[sshd]
enabled = true
action = send_webhook
2. 永久封禁与白名单
# 永久封禁(直到手动解封)
bantime = -1
# 解封命令
sudo fail2ban-client set sshd unbanip 1.2.3.4
# 将某些 IP 加入永不封禁名单
ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24 10.0.0.0/8
3. 分级封禁策略
对不同攻击强度实施不同惩罚:
# 需要在 jail.local 中配置多个"重复监狱"
# 但更简单的方式:用 fail2ban 的 recidive 监狱
# /etc/fail2ban/jail.d/recidive.conf
[recidive]
enabled = true
logpath = /var/log/fail2ban.log
maxretry = 3
findtime = 1d
bantime = 1w
# 功能:如果在 1 天内某 IP 被 fail2ban 封禁了 3 次(来自不同监狱),
# 则对其实施 1 周的封禁。
4. 使用 nftables 集合实现高性能封禁
# /etc/fail2ban/jail.d/nftables.conf
[DEFAULT]
banaction = nftables-allports
[sshd]
enabled = true
Fail2ban 会创建 nftables 集合来管理封禁 IP,比 iptables 链式规则性能更好。
# 查看 Fail2ban 创建的 nftables 规则
sudo nft list ruleset | grep -A 20 f2b
5. 按天统计攻击趋势
# 每天的攻击次数
sudo zgrep "Ban" /var/log/fail2ban.log.* /var/log/fail2ban.log 2>/dev/null | \
grep -oP '^\S+' | sort | uniq -c
# 最常见的攻击目标服务
sudo grep "Ban" /var/log/fail2ban.log | grep -oP '\[\K[^\]]+' | sort | uniq -c | sort -rn
性能调优
# /etc/fail2ban/fail2ban.local
[DEFAULT]
# 日志轮转时自动检测
loglvl = WARNING
# 使用 systemd 后端(比 polling 更高效)
backend = systemd
# 减少 IO 负载(大日志文件时)
maxmatches = 5
常见问题
Q:我改了配置为什么没生效?
修改配置后需要重载,且要确保修改的是正确的文件:
# 重载所有配置
sudo fail2ban-client reload
# 检查语法错误
sudo fail2ban-client -d
# 确认你修改的是 jail.local 或 jail.d/*.conf,而不是 jail.conf
Q:如何确认 Fail2ban 正在工作?
# 方法 1:查看监狱状态
sudo fail2ban-client status sshd
# 方法 2:自己尝试模拟登录失败(不要在生产环境做!)
# ssh wronguser@localhost
# 方法 3:查看封禁日志
sudo tail -f /var/log/fail2ban.log
# 方法 4:查看防火墙规则
sudo iptables -L f2b-sshd -n -v
# 或
sudo nft list ruleset | grep f2b
Q:Fail2ban 和 UFW 一起用怎么配置?
[DEFAULT]
banaction = ufw
[sshd]
enabled = true
这样 Fail2ban 封禁 IP 时会执行 ufw deny from <IP>。也可以用 ufw route deny 来处理转发流量。
Q:我改了 SSH 端口,Fail2ban 还能工作吗?
能,但需要告诉 Fail2ban:
[sshd]
enabled = true
port = 2222 # 与 /etc/ssh/sshd_config 的端口一致
Q:Fail2ban 资源占用高吗?
极低。通常占用 10-30MB 内存 和几乎可以忽略的 CPU,监控几个监狱非常轻量。
但如果监控超大日志文件(几百 MB 以上),建议使用 backend = systemd 或 backend = pyinotify,避免轮询 IO 消耗。
Q:误封怎么办?
# 1. 立即解封
sudo fail2ban-client set sshd unbanip 1.2.3.4
# 2. 将该 IP 加入白名单
# 在 jail.local 中:
[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 1.2.3.4
# 然后重载
sudo fail2ban-client reload
Q:Docker 环境下 Fail2ban 需要注意什么?
Docker 网络默认走 NAT,宿主机看到的是 Docker 网关 IP(如 172.17.0.1),而非真正的客户端 IP。解决方案:
- 在宿主机部署 Fail2ban(推荐)
- 如果部署在宿主机但服务在容器里,确保容器日志被映射到宿主机
- 使用
--network host模式启动容器(让容器直接使用宿主机网络)
Q:如何查看所有历史封禁统计?
# 总封禁次数
grep -c "Ban" /var/log/fail2ban.log
# 各服务封禁统计
for jail in $(sudo fail2ban-client status | grep "Jail list" | cut -d: -f2); do
count=$(sudo fail2ban-client get $jail ban 2>/dev/null || echo 0)
echo "$jail: $count"
done
# 各 IP 封禁次数
grep "Ban" /var/log/fail2ban.log | grep -oP '\d+\.\d+\.\d+\.\d+' | sort | uniq -c | sort -rn
同类工具对比
| 特性 | Fail2ban | Crowdsec | DenyHosts | sshguard |
|---|---|---|---|---|
| 配置复杂度 | 中(需配置正则) | 低(自动) | 低 | 低 |
| 支持协议 | SSH, HTTP, FTP, Mail, 自定义 | SSH, HTTP, 自定义 | 仅 SSH | SSH |
| IP 黑名单共享 | ❌ 需自行配置 | ✅ 全球社区共享 | ❌ | ❌ |
| Web UI | ❌ | ✅ 有仪表盘 | ❌ | ❌ |
| 自定义正则 | ✅ 灵活 | ✅ 场景化配置 | ❌ | ❌ |
| 资源占用 | 极低(10-30MB) | 中等(50-100MB) | 极低 | 极低 |
| 安装方式 | apt/dnf 直接安装 | 需添加仓库 | apt/dnf 直接安装 | apt/dnf 直接安装 |
| 社区活跃度 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐(增长快) | ⭐⭐(维护模式) | ⭐⭐ |
选型建议:
- 简单场景(只保护 SSH)→ Fail2ban 或 sshguard
- 复杂的 Web 服务保护 → Fail2ban(丰富的过滤器支持)
- 想要社区联动的 IP 黑名单 → Crowdsec
安全最佳实践
- 先配置白名单 — 别把自己的办公室 IP 封了
- 搭配 SSH 密钥登录 — Fail2ban 是辅助,SSH 密钥才是正解
- 修改默认 SSH 端口 — 减少 99% 的扫描攻击
- 设置合理的 bantime — 永久封禁(
-1)可能导致 IP 池耗尽 - 监控日志 — 定期检查
fail2ban.log了解攻击态势 - 定期更新 — Fail2ban 的过滤器和动作定义在不断改进
- 与通知系统集成 — 封禁时发送企业微信/钉钉/Slack 通知
- 启用 recidive 监狱 — 对反复攻击者实施更长时间封禁
总结
| 操作 | 命令 |
|---|---|
| 查看所有监狱 | sudo fail2ban-client status |
| 查看 SSH 监狱 | sudo fail2ban-client status sshd |
| 手动封禁 IP | sudo fail2ban-client set sshd banip 1.2.3.4 |
| 手动解封 IP | sudo fail2ban-client set sshd unbanip 1.2.3.4 |
| 重载配置 | sudo fail2ban-client reload |
| 查看日志 | sudo tail -f /var/log/fail2ban.log |
| 测试过滤器 | sudo fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf |
| 查看封禁统计 | grep "Ban" /var/log/fail2ban.log | wc -l |
一句话总结:互联网上每时每刻都有扫描器在试探你的服务器 —— Fail2ban 就是那个全天候站在门口帮你挡人的保安。它不该是你唯一的安全措施,但它是成本最低、效果最明显的防线之一。