概述

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.localjail.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 = systemdbackend = 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。解决方案:

  1. 在宿主机部署 Fail2ban(推荐)
  2. 如果部署在宿主机但服务在容器里,确保容器日志被映射到宿主机
  3. 使用 --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)→ Fail2bansshguard
  • 复杂的 Web 服务保护 → Fail2ban(丰富的过滤器支持)
  • 想要社区联动的 IP 黑名单 → Crowdsec

安全最佳实践

  1. 先配置白名单 — 别把自己的办公室 IP 封了
  2. 搭配 SSH 密钥登录 — Fail2ban 是辅助,SSH 密钥才是正解
  3. 修改默认 SSH 端口 — 减少 99% 的扫描攻击
  4. 设置合理的 bantime — 永久封禁(-1)可能导致 IP 池耗尽
  5. 监控日志 — 定期检查 fail2ban.log 了解攻击态势
  6. 定期更新 — Fail2ban 的过滤器和动作定义在不断改进
  7. 与通知系统集成 — 封禁时发送企业微信/钉钉/Slack 通知
  8. 启用 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 就是那个全天候站在门口帮你挡人的保安。它不该是你唯一的安全措施,但它是成本最低、效果最明显的防线之一。


参考链接