只要你的服务器有一个公网 IP,并且开着 SSH 的 22 端口,用不了多久登录日志里就会开始出现来自世界各地的失败登录记录。这些记录绝大多数来自自动化脚本,它们拿着常见的用户名和密码字典,一天二十四小时不停地尝试,靠概率碰运气。手动去看日志再手动去封 IP,面对动辄每天几万次的尝试量根本不现实,这时候就需要一个能自动盯日志、自动封禁的工具,Fail2ban 就是这类工具里最经典的一个。
这篇文章从防御和运维的角度,讲清楚 Fail2ban 到底在做什么、它的配置结构是什么样的、如何针对 SSH 配一套既有效又不会把自己锁在门外的规则。读完你应该能做到:装好它、自定义封禁策略、随时查看谁被封了、出问题时把封禁解掉,以及在上线前做好防误伤的准备。文中的所有命令都区分了 RHEL/CentOS/Rocky 与 Debian/Ubuntu 两套发行版,你可以直接照着执行。
需要先明确一点:Fail2ban 是一个"降低噪声、抬高攻击成本"的工具,它不能替代密钥登录、不能替代防火墙最小化开放端口、也不能替代及时打补丁。把它当成多层防御里的一环,而不是万能钥匙,心态就对了。
一、Fail2ban 是怎么工作的
Fail2ban 的设计非常朴素:它本身不做网络拦截,而是扮演一个"日志监视器 + 规则执行器"的角色。它定期读取指定的日志文件,用正则表达式去匹配日志里的失败记录,当某个来源 IP 在给定时间窗口内的失败次数超过阈值,它就调用底层的防火墙(iptables、nftables 或 firewalld)把该 IP 加入拒绝列表一段时间;时间一到,再自动移除。整个过程不需要人工介入。
理解这个模型,就能明白它的三个关键参数为什么长这样。第一个是 findtime,也就是"时间窗口",它决定了多久以内的失败算作同一批;第二个是 maxretry,也就是"容忍次数",窗口内失败几次才触发封禁;第三个是 bantime,也就是"封禁时长"。这三个参数共同定义了一条策略:在 findtime 秒内失败超过 maxretry 次,就封禁 bantime 秒。任何一个参数调整,都会改变温和或激进的程度。
Fail2ban 的核心概念有三个词必须记住。filter 是过滤器,负责定义"什么样的日志行算一次失败",本质是一组正则;jail 是牢房,把过滤器、动作和具体服务绑定在一起,例如一个叫 sshd 的 jail 就负责守护 SSH 服务;action 是动作,定义命中之后具体做什么,最常见的就是调用防火墙封禁,也可以只发邮件通知。你在配置里改来改去的,基本就是这三样东西。
有一点容易被忽略:Fail2ban 只能看到"日志里写下来的失败"。如果一个服务根本不记录失败尝试,或者日志级别设得太低,Fail2ban 就无从下手。所以它和服务的日志配置是绑定的,不是装完就一定能生效,后面排障时会用到这个知识点。
二、安装与开机自启
绝大多数发行版的官方仓库里都带了 Fail2ban,直接装即可,不需要额外加源。
# RHEL / CentOS / Rocky / AlmaLinux(RHEL 8 及以上默认有 dnf)
sudo dnf install -y fail2ban
# 如果系统较老只有 yum
sudo yum install -y fail2ban
# Debian / Ubuntu
sudo apt update
sudo apt install -y fail2ban
装完之后不要急着启动,因为默认配置通常只启用了一个很宽松的策略,而且 Debian 系默认不启用 sshd 的 jail,需要先做配置。正确的顺序是:先建好自定义配置,再启动并设为开机自启。
# 设置开机自启并立即启动
sudo systemctl enable --now fail2ban
# 查看运行状态
sudo systemctl status fail2ban
# RHEL 系如果需要用 firewalld 作为后端,确认其正在运行
sudo systemctl status firewalld
# Debian/Ubuntu 如果用的是 nftables 或 iptables,确认相应服务可用
sudo systemctl status nftables 2>/dev/null || true
一个常见的坑是:Fail2ban 的服务名叫 fail2ban,但它的客户端命令是 fail2ban-client,两者容易混淆。查看状态用前者(systemctl),操作封禁用后者(fail2ban-client),记住这个区别能省下不少查文档的时间。
三、用 jail.local 覆盖默认配置
Fail2ban 的配置分两层。/etc/fail2ban/jail.conf 是软件自带的默认配置,升级时可能被覆盖,官方明确不建议直接改它。你应该新建 /etc/fail2ban/jail.local,在里面只写需要覆盖或新增的项,Fail2ban 启动时会自动读取它并覆盖默认值。这是一个非常重要的工程习惯:把"软件自带"和"我的定制"分开,升级才不会把你的策略冲掉。
jail.local 的配置可以分两段来看:[DEFAULT] 段是全局默认值,对所有 jail 生效;各个 [服务名] 段是具体 jail,可以单独覆盖全局值。
# /etc/fail2ban/jail.local
[DEFAULT]
# 白名单:这些地址永远不封,多个用空格分隔,支持网段
# 重要:务必把你的管理机 IP、办公出口 IP、跳板机 IP 加进来
ignoreip = 127.0.0.1/8 ::1 203.0.113.10 198.51.100.0/24
# 封禁时长(秒),-1 表示永久封禁
bantime = 3600
# 时间窗口(秒):在这个窗口内累计失败才计数
findtime = 600
# 容忍次数:窗口内失败达到这个次数就封
maxretry = 5
# 封禁后是否允许重新解析主机名(关掉更快,也更少依赖 DNS)
# 一般保持默认即可
[sshd]
enabled = true
# 指定要监听的日志(不同发行版路径不同,见下方说明)
# Debian/Ubuntu 默认读 /var/log/auth.log,一般无需显式指定
# RHEL/CentOS/Rocky 建议显式指定 journal 或 secure 文件
backend = systemd
port = ssh
# 继承全局的 bantime/findtime/maxretry,也可在此单独覆盖
# bantime = 86400
# maxretry = 3
mode = normal
这里有一个发行版差异必须点出来。Debian/Ubuntu 把认证日志写在 /var/log/auth.log,Fail2ban 默认就能找到;而 RHEL/CentOS/Rocky 系把认证日志写进 systemd journal,同时也会落在 /var/log/secure。新版本的 Fail2ban 在这两个系上会自动选择合适的后端,但如果你的服务不封人,先怀疑"它到底有没有读到日志",这时候显式写 backend = systemd 往往能解决问题。
ignoreip 那一行是整份配置里最值钱的一行。很多人配完 Fail2ban 就不管了,结果某天自己反复输错密码,把自己办公室出口 IP 封了,只能灰溜溜地去控制台处理。提前把可信来源加进白名单,成本几乎为零,收益却是"永远不用担心自己被锁"。
四、参数怎么调:温和、标准、严格
三个参数没有放之四海皆准的值,取决于你的业务场景和你能承受的误伤程度。下面给出一组经验区间,不是硬性规定,你可以按实际情况取舍。
| 场景 | findtime | maxretry | bantime | 说明 |
|---|---|---|---|---|
| 宽松(怕误伤) | 600 秒 | 8 | 600 秒 | 适合多人共用、动态 IP 频繁变动的环境 |
| 标准(推荐起点) | 600 秒 | 5 | 3600 秒 | 大多数公网服务器的均衡选择 |
| 严格(对抗暴力破解) | 300 秒 | 3 | 86400 秒 | 持续被爆破的机器可短窗口、长封禁 |
| 极严(研究/诱捕) | 180 秒 | 2 | -1(永久) | 仅限明确只给自己用的机器,慎用永久封禁 |
调整时的一个实用技巧是"先观察再收紧"。你可以先把 bantime 设得短一些(比如 600 秒),运行几天看看封禁频率和是否误伤,确认策略健康之后,再把时间逐步拉长。反过来,一上来就设永久封禁,一旦误封了自己或者误封了某个正常用户,麻烦就大了。
还有一点:maxretry 并不是越小越好。如果你的 findtime 很短而 maxretry 也很小,正常用户偶尔手滑输错几次密码就可能触发封禁;而如果 findtime 很长,攻击者可以刻意放慢速度,每几分钟试一次,就永远凑不满阈值。工程上的折中是上面表格里的"标准"那组,作为绝大多数场景的起点是合理的。
五、查看封禁、解封与开机行为
配好并重启服务之后,最常用的就是下面这几条命令。
# 重启使配置生效
sudo systemctl restart fail2ban
# 查看所有 jail 的总体状态
sudo fail2ban-client status
# 查看 sshd 这个 jail 的详细状态:当前封了几个、封了谁
sudo fail2ban-client status sshd
# 手动解封某个 IP
sudo fail2ban-client set sshd unbanip 203.0.113.99
# 手动封禁某个 IP(临时处理时有用)
sudo fail2ban-client set sshd banip 203.0.113.99
# 查看封禁列表(以 firewalld 为例,看富规则)
sudo firewall-cmd --list-rich-rules
# 如果后端是 iptables,直接看规则链
sudo iptables -L -n --line-numbers | grep -i f2b
fail2ban-client status sshd 的输出里有两行最关键:Currently banned 是当前封禁数量,Banned IP list 是具体名单。每天扫一眼这两个值,就能对服务器的受关注程度有个直观判断。如果某个 IP 反复出现在解封又被封的循环里,说明它是个执着的自动化脚本,这种情况下把 bantime 调长比反复解封更省事。
关于开机行为也要留意:iptables 和 nftables 的规则默认不持久化,重启后可能丢失,而 Fail2ban 自身设为开机自启后会在启动时重新下发规则。所以真正需要保证的是 fail2ban 服务处于 enabled 状态,而不是手动去备份防火墙规则。反过来,如果你手动改过防火墙,又没让 Fail2ban 托管,就可能出现"重启后封禁失效"的错觉。
六、千万别把自己锁在门外
这是本文最想强调的一节。Fail2ban 这类自动封禁工具最大的风险不是"封不准攻击者",而是"把管理员自己封了"。下面几条是血泪经验。
第一,先加白名单再启用。在任何情况下,把当前你登录用的来源 IP 写进 ignoreip,把跳板机、办公网段、VPN 出口段一并加上。宁可白名单宽一点,也不要出现自己被封的情况。
第二,保留一条不依赖 SSH 的通道。主流云厂商都提供网页版 VNC 或串口控制台,能在 SSH 被切断时直接登进系统。开工前先确认这个入口可用,并且你有它的登录凭据。这是最后的救命绳。
第三,改配置时不要立刻断开当前连接。改完 sshd_config 或 Fail2ban 配置后,先重载而不是重启,并且新开一个终端窗口测试新连接能不能进;确认新会话正常之后,才关掉旧连接。更稳妥的做法是先在另一台机器上用 ssh 测一次,确认无误再收工。
第四,给封禁留一条恢复路径。如果真被锁了,除了控制台,也记住解封命令。能通过控制台执行 fail2ban-client set sshd unbanip <你的IP>,或者临时 systemctl stop fail2ban 让规则全部撤销,基本都能救回来。
# 万不得已时的兜底:临时停掉 fail2ban,撤销它下发的所有封禁
sudo systemctl stop fail2ban
# 之后冷静处理:把白名单补好,再启动
sudo systemctl start fail2ban
需要提醒的是,systemctl stop fail2ban 会让所有由它下发的封禁规则失效,等于短暂关闭了这层防护,只能作为应急手段,处理完要尽快恢复。生产环境上,处理这类事情最好两人协作,一个人操作,另一个人盯着控制台随时准备接手。
七、进阶:守护更多服务
只要某个服务会把失败记录写进日志,理论上都可以交给 Fail2ban 守护。常见的还有 Web 服务的认证失败、邮件服务的登录失败等。做法是复制官方 jail 段,把 logpath 和 filter 指到对应服务。
# 以保护 Web 登录接口为例(需要对应的 filter 文件或自定义正则)
[nginx-http-auth]
enabled = true
port = http,https
logpath = /var/log/nginx/error.log
maxretry = 5
bantime = 3600
需要说明的是,这类针对 Web 的 jail 依赖服务本身的日志格式,不同配置下正则可能匹配不到。遇到"明明有失败却没封"的情况,先用 fail2ban-regex 手动验证过滤器能否匹配日志行,再决定要不要改正则。
# 用真实日志测试某个过滤器是否有效
sudo fail2ban-regex /var/log/nginx/error.log /etc/fail2ban/filter.d/nginx-http-auth.conf
这条命令会打印匹配到多少行、是否命中,非常直观。与其凭感觉猜"为什么没封",不如让工具直接告诉你。
常见问题
Q:装好 Fail2ban 后,为什么攻击 IP 还是没被封?
大概率是它没读到日志,或者过滤器没匹配上。先确认服务在运行(systemctl status fail2ban),再看它有没有真的在处理日志:Debian/Ubuntu 检查是否启用了 [sshd],RHEL 系可以显式设 backend = systemd。用 fail2ban-regex 验证过滤器是最快的排查手段。
Q:白名单支持网段吗?动态 IP 怎么办?
支持,ignoreip 里可以直接写 CIDR,例如 198.51.100.0/24。如果你的出口 IP 是动态漂移的,可以白名单整个运营商大段的可能过于宽松,更稳妥的做法是用 VPN 固定出口,再把 VPN 地址加白。动态 IP 场景下也别完全依赖白名单,务必保留控制台入口。
Q:把 bantime 设成 -1 永久封禁好不好?
不建议作为默认策略。永久封禁会越积越多,某天误封了正常用户会很被动,而且攻击者的 IP 也会变化,永久封禁一条 IP 的长期收益有限。真有持续爆破,用几天到一周的封禁通常就够把它劝退。
Q:Fail2ban 能防住 CC 攻击吗?
不能。Fail2ban 擅长的是"针对登录认证失败的反复尝试",它基于认证失败日志工作;而 CC 攻击打的是正常请求,日志里看不到"失败",需要的是连接数和请求速率限制,那是另一套机制。
Q:封禁规则重启后会丢吗?
Fail2ban 自身设为开机自启后会在启动时重新加载规则,所以只要服务是 enabled 状态就没问题。但手动添加的、未经 Fail2ban 托管的防火墙规则重启后会丢,这两者要分开看待。
总结
Fail2ban 是公网服务器上性价比极高的第一道自动防线,它用最小的配置成本,把海量的自动化破解尝试挡在门外,让日志重新变得可读。
它的核心只有三个参数:findtime 是窗口、maxretry 是容忍、bantime 是惩罚,三者配合决定策略的强弱。标准场景从"600 秒窗口、5 次容忍、3600 秒封禁"起步,再按实际情况微调。
配置一律写进 /etc/fail2ban/jail.local,不要改软件自带的 jail.conf,这样升级才不会被冲掉。注意发行版差异:Debian/Ubuntu 读 auth.log,RHEL 系可显式用 backend = systemd。
上线之前先做三件事:把你的管理 IP 加进 ignoreip、确认云控制台可用、记住解封和临时停服的命令。这三件事决定了你出事时是"从容处理"还是"被锁在门外"。
最后,守好边界:Fail2ban 是防御工具,用来降低自己的暴露和噪声。真正的安全来自密钥登录、端口最小化、及时补丁这些基础工作,自动封禁只是锦上添花的一层。
企业QQ咨询




