本文要点
- fail2ban 通过分析服务日志,把失败次数超过阈值的来源
IP自动拉入防火墙黑名单,到期自动解封。 - Ubuntu 24.04 上
apt install fail2ban后,sshd守护已默认启用,后台直接读journald,不需要额外的auth.log配置。 - 核心参数三个:
maxretry(几次算攻击)、findtime(统计时间窗)、bantime(封多久),修改建议写进/etc/fail2ban/jail.local,不碰默认文件。 - 实测:连续 5 次错误密码登录即触发封禁,被封后的 SSH 连接直接
Connection refused,一条unbanip命令即可解除。 - 排障用
fail2ban-client -t测配置、fail2ban-regex验证过滤规则,日志看/var/log/fail2ban.log。
为什么需要 fail2ban
只要你的服务器有公网 IP 并且开着 SSH,就几乎每天都有人来试密码。我在一台刚装好系统的演示机上查看 SSH 日志,几分钟内就能翻到来自各个 IP 的「无效格式 banner」、未知用户、错误密码尝试——这些大多是扫描器在批量探测。
密码复杂、改用密钥登录能挡住大部分攻击,但总有一些主机出于兼容性仍开着密码认证。fail2ban 的思路很直接:让日志说话——哪个 IP 在短时间内反复登录失败,就把它拉进防火墙黑名单封一段时间。它不依赖你是 SSH、FTP 还是 Web 服务,凡是「能在日志里看到失败记录」的服务都能管,所以是 Linux 运维里通用的防暴力破解方案。
fail2ban 是什么
fail2ban 是一个用 Python 写的守护进程。它读服务的日志(支持文件日志和 systemd journal),用正则表达式从日志行中提取需要判断的 IP,统计在 findtime 时间窗内失败的次数,超过 maxretry 阈值就执行封禁动作(默认是调用系统防火墙加入黑名单);到了 bantime 设定的时长后自动解封。它只做一件事:把连续失败的可疑来源挡在外面。
工作流程可以用四步概括:
- 监听:读取
/var/log/auth.log或 journald 里的服务日志; - 匹配:用过滤规则(filter)里的正则提取「谁、何时、失败了几次」;
- 判定:
findtime窗口内同一来源失败次数 ≥maxretry,判定为攻击; - 执行:触发 action 封禁 IP(默认写防火墙规则),
bantime到期后自动删除规则。
安装与启停
Ubuntu 24.04(以及 Debian、CentOS/Rocky)的软件源里都有 fail2ban,一条命令装完:
sudo apt update && sudo apt install -y fail2ban安装后服务会自动启动并设为开机自启(我实测安装完 systemctl is-active fail2ban 已返回 active)。常用的启停命令:
sudo systemctl enable --now fail2ban # 开机自启 + 立即启动
sudo systemctl status fail2ban # 查看运行状态
sudo systemctl reload fail2ban # 重载配置(不中断,推荐)
sudo systemctl restart fail2ban # 完全重启(会清空内存计数)Ubuntu/Debian 有一个贴心的默认:装完 sshd 这一条 jail 已经是启用状态,且后端默认走 journald,即使服务器没有生成 /var/log/auth.log 也能工作。装好后直接看状态就能确认:

图中 fail2ban-client status 显示已经有一个名为 sshd 的 jail;fail2ban-client status sshd 则给出 Filter(当前失败数、累计失败数、日志匹配条件)和 Actions(当前封禁数、累计封禁数、封禁 IP 列表)两组信息。注意 Total failed: 5——那是此前模拟的攻击已经留下的痕迹,说明统计是真实、连续的。
理解默认配置
fail2ban 的主配置文件是 /etc/fail2ban/jail.conf,安装包自带的默认值足够先跑起来。几个最关键的参数:
| 参数 | 默认值 | 含义 |
|---|---|---|
bantime | 10m | 封禁时长,支持 1m/10m/1h/1d 等写法 |
findtime | 10m | 统计时间窗:在这个时间段内累计失败 |
maxretry | 5 | 达到几次失败就封禁 |
ignoreip | 127.0.0.1/8 ::1 | 永不封禁的 IP/网段 |
它们配合的含义是:在 10 分钟内同一个来源累计 5 次登录失败,就把它封禁 10 分钟。.local 后缀的配置文件优先级更高——自定义配置应该写入 /etc/fail2ban/jail.local,而不要直接改 jail.conf,这样软件升级时不会被覆盖。
第一次使用的人最常踩的坑是把自己封了:你用办公网络、家里宽带或云服务器管理台的 IP 都可能变化,一旦你的当前出口 IP 被误封,SSH 就连不上了。务必要在 ignoreip 里加上你常用的管理来源网段(比如公司出口 IP),并给管理员保留一个带外通道(云控制台 VNC/救援模式)。
模拟一次暴力破解:看 fail2ban 自动封禁
纸上谈兵不如实测。我在演示机上真实触发了 6 次错误密码登录(模拟攻击者用字典跑 SSH),来观察 fail2ban 的行为。
第 1~5 次失败时,sshd jail 的 Currently failed 计数会不断增长;当同一个来源在第 5 次失败时达到 maxretry = 5,fail2ban 立刻执行封禁。之后第 6 次及以后的连接直接失败,客户端报错:
ssh: connect to host 47.238.230.124 port 22: Connection refused注意这个报错不是「密码错」,而是 TCP 层面直接拒绝连接——防火墙规则已经在本次连接建立之前把来源 IP 丢掉了。这时再回看服务端:
fail2ban-client status sshd输出里 Actions 部分变成了 Currently banned: 1,封禁列表里正是刚才那个来源 IP;而 /var/log/fail2ban.log 里会留下一条明确记录:
2026-08-23 08:04:30 fail2ban.actions [sshd] Ban 117.182.133.208
2026-08-23 08:04:46 fail2ban.actions [sshd] Unban 117.182.133.208Ban 表示封禁动作触发,Unban 表示到期(或手动)解封。确认封禁无误后,管理员一条命令即可解除整个封锁:
fail2ban-client set sshd unbanip <你的IP>为了演示完整闭环而不影响演示机的对外连接,下面用 set sshd banip 手动封禁一个保留测试网段(203.0.113.10 属于 TEST-NET-3,不会是真的攻击来源),再立即解封,完整展示封禁→验证→解封的流程:

图中第一次 fail2ban-client status sshd 后 Banned IP list: 203.0.113.10,执行 unbanip 后再查就清空了。set <jail> banip / unbanip 适合临时手动干预;日常的自动封禁与解封由日志驱动完成。
配置自己的封禁策略
默认 5 次/10 分钟/封 10 分钟太温和,生产上通常更严格。创建 /etc/fail2ban/jail.local 覆盖参数即可:
[sshd]
enabled = true
maxretry = 3
bantime = 1h
findtime = 10m
ignoreip = 127.0.0.1/8 ::1含义改成:10 分钟内失败 3 次就封 1 小时。改完后先测配置再热重载:
sudo fail2ban-client -t # 语法自检,输出 OK 才放行
sudo systemctl reload fail2ban # 热重载,不需要重启进程
fail2ban-client status sshd # 确认重载后仍正常实测效果如下:

图中 fail2ban-client -t 返回 OK: configuration test is successful,reload 后 status sshd 依然正常(已统计的 Total failed 计数会被保留,不用大惊小怪)。
用 filter 规则实现匹配
jail.local 里的 [sshd] 只是 OOTB 最常用的一例。fail2ban 的模块化结构是三层:jail 定义「管哪个服务 + 策略」、filter 定义「认哪几行日志」、action 定义「怎么封」。每个 jail 可用 filter 和 action 字段指认:
[myapp] # 自定义服务名
enabled = true
port = 8080
logpath = /var/log/myapp/error.log # file 后端
filter = myapp # 用 filter.d/myapp.conf
maxretry = 3
bantime = 1h对应的过滤器写在 /etc/fail2ban/filter.d/myapp.conf,核心是正则 failregex。例如匹配「密码错误」:
[Definition]
failregex = ^.*authentication failed from <HOST>
ignoreregex =<HOST> 是 fail2ban 预留占位符,会自动换成正则去提取 IP。写成 failure from 1.2.3.4 这样的日志就能被命中。
用 fail2ban-regex 预先验证正则
正则写错会导致「该封的没封」。动手写日志场景做一次离线验证,不依赖真实流量:
echo 'Aug 23 08:04:30 demo sshd: Failed password for root from 203.0.113.9 port 50000 ssh2' > /tmp/sample.log
fail2ban-regex /tmp/sample.log /etc/fail2ban/filter.d/sshd.conf输出关键行 Lines: 1 lines, 0 ignored, 1 matched, 0 missed 表示这条失败日志被成功识别。新增自定义 filter 前先用 fail2ban-regex 跑样本,能省去大量排障时间。
加大攻击者代价的几个技巧
- 结合密钥认证:配合
PermitRootLogin prohibit-password与仅密钥登录,就算密码认证关闭前被爆破,也没有密码可爆。ssh 的失败日志本身仍会被 fail2ban 计数。 - 缩短窗口、加长封禁:SSH 字典攻击会在几分钟内打几千次,
maxretry = 3, bantime = 1h只是入门;对重要主机可以bantime = 1d或配合recidivejail(封禁过的 IP 再次出现直接拉黑更长)。 - 多服务共管:nginx、postfix、dovecot、vsftpd 等有日志的认证服务,都可以仿照 sshd 写自己的 jail;GitHub 上各发行版
filter.d/里一般自带现成模板,改参数即可。 - 关注 fail2ban.log:
/var/log/fail2ban.log记录了每次Ban/Unban及其原因,是判断「到底有没有被攻击、有没有误封」的第一手证据。
常见坑与提醒
- 别把 ignoreip 写成全局开放:
ignoreip如果你图省事写上0.0.0.0/0等于关闭了所有封禁。 - reload 与 restart 语义不同:
reload保留内存中的失败统计,restart全部清零;排障时二者都可以用,别再误删统计贡献排查难度。 - journald 后端不需要 auth.log:Ubuntu 24.04 默认
backend = systemd,没有/var/log/auth.log也照样工作;若你手动改回file后端,务必确认logpath路径真实存在且 fail2ban 用户可读。 - 时间与抗绕过:攻击者会随机化端口/间隔以绕过 findtime 窗口,误报与漏报之间要权衡;建议从先「防自己、信日志」起步,再逐步加严。
fail2ban 是 Linux 运维里投入产出比极高的一个工具:安装成本十几秒,换来的是公网 SSH 端口的持续降噪。装好之后,把上面几条自检命令跑一遍(status、-t、fail2ban-regex),再配上 jail.local 里的严格策略,服务器就可以安心挂到公网了。
评论 (0)
暂无评论,快来抢沙发吧!