<!DOCTYPE html>
任何暴露在公网上的 Linux 服务器,只要开启了 SSH,几乎每时每刻都在被扫描器与暴力破解脚本轮番问候。查看 /var/log/auth.log,你往往会发现大量来自境外 IP 的 Failed password 记录。要挡住这些攻击,除了关闭密码登录、改用密钥认证之外,Fail2ban 是最经典的一道自动化防线:它监控日志文件,用正则匹配失败行为,达到阈值后自动调用防火墙封禁对方 IP。本文从原理到实战,完整讲解 Fail2ban 的安装、配置、防火墙联动与高频排错。
一、Fail2ban 的工作原理与核心概念
Fail2ban 本身并不直接拦截流量,它是一个"日志扫描 + 动作触发"框架,完整链路如下:
系统日志(auth.log) --> filter 正则匹配 --> 失败计数 --> 超过 maxretry --> 触发 action --> 防火墙封禁 IP
它的三个核心部件分别是:
- filter:定义"什么样的日志算一次失败",本质是一个正则表达式文件,位于
/etc/fail2ban/filter.d/。 - jail:把日志源、filter、动作和参数(次数、时间窗、封禁时长)组合成一条规则。
- action:封禁的具体手段,默认使用 iptables,也可以换成 ufw、firewalld、nftables 等,配置位于
/etc/fail2ban/action.d/。
三个最重要的参数必须理解清楚:
maxretry:时间窗内允许的最大失败次数。findtime:时间窗长度(秒),统计"最近多少秒内的失败"。bantime:封禁时长(秒),设为-1表示永久封禁。
例如 findtime=600、maxretry=5、bantime=3600 表示:10 分钟内失败超过 5 次,封禁 1 小时。
二、安装 Fail2ban(Ubuntu / CentOS)
# Debian / Ubuntu
apt update
apt install -y fail2ban
# CentOS / RHEL(需要 EPEL 源)
yum install -y epel-release
yum install -y fail2ban
# 开机自启并立即启动
systemctl enable --now fail2ban
systemctl status fail2ban
安装完成后先验证服务正常:systemctl status fail2ban 应显示 Active: active (running)。Debian/Ubuntu 上系统可能自动创建了 jail.local,先确认一下再继续。
三、配置文件的优先级与正确改法
Fail2ban 的配置全部遵循".conf 为基础、.local 为覆盖"的原则:同名文件下,.local 中的键值会覆盖 .conf。因此我们永远不要去修改 /etc/fail2ban/jail.conf,而是新建 /etc/fail2ban/jail.local:
/etc/fail2ban/fail2ban.conf # 主配置:日志级别、socket 路径等
/etc/fail2ban/jail.conf # 默认规则(勿直接改)
/etc/fail2ban/jail.local # 自定义覆盖(重点)
/etc/fail2ban/filter.d/*.conf # 日志匹配正则
/etc/fail2ban/action.d/*.conf # 封禁动作实现
四、SSH 防护配置示例(jail.local)
下面是一份开箱即用的 SSH 防护配置:
[DEFAULT]
# 封禁时长:1 小时
bantime = 1h
# 时间窗:10 分钟
findtime = 10m
# 时间窗内失败 5 次触发封禁
maxretry = 5
# 永不封禁的 IP(本机、公司出口、监控机)
ignoreip = 127.0.0.1/8 ::1 203.0.113.10
# 触发封禁时发邮件通知(需要配置 sendmail 或 msmtp)
destemail = admin@example.com
sendername = fail2ban
action = %(action_mwl)s
[sshd]
enabled = true
# 若 SSH 端口非 22,这里必须同步修改,否则封禁的端口不对
port = ssh
# 日志路径:Ubuntu 默认 /var/log/auth.log,CentOS 为 /var/log/secure
logpath = /var/log/auth.log
# 日志来源:systemd 表示从 journalctl 读,路径类直接写文件
backend = systemd
修改后必须重启服务并验证:
systemctl restart fail2ban
fail2ban-client status sshd
fail2ban-client status sshd 输出中,Currently banned 为当前封禁 IP 数,Total banned 为累计封禁数,看到这两个字段就说明 jail 已生效。
五、自定义端口、日志路径与后端
很多服务器把 SSH 端口改成了自定义端口(例如 22222),此时需要同步修改 jail 与端口:
[sshd]
enabled = true
port = 22222
logpath = /var/log/auth.log
backend = systemd
关于 backend 参数,需要注意:
systemd:从 journal 读取日志,适合日志已交给 systemd 管理的系统,CentOS 7+ / Ubuntu 16.04+ 推荐。auto:自动探测,能找到日志文件就用文件方式,找不到就退回 systemd。pyinotify/polling:文件监听方式,文件被 logrotate 切割后依赖重载,配置较繁琐。
六、与 ufw / firewalld / iptables 联动
Fail2ban 默认的 action 是 iptables,会在 INPUT 链上插入规则。但如果你使用 ufw 管理防火墙,iptables 规则可能被 ufw 重置逻辑干扰,因此推荐显式切换 action:
[DEFAULT]
# 使用 ufw 作为封禁手段
banaction = ufw
# 使用 firewalld(CentOS/RHEL 8+)
banaction = firewalld-cmd
切换后重启并确认动作执行:
systemctl restart fail2ban
iptables -L -n | grep f2b # 查看 f2b 链
ufw status numbered # ufw 模式下查看规则
一个小坑:如果同时启用了 ufw 和 iptables 两套封禁,会出现"卸载 fail2ban 后仍有残留规则"的问题,所以在 fail2ban 里明确指定一种 banaction 即可,避免混用。
七、日常管理命令速查
# 查看所有 jail 及封禁统计
fail2ban-client status
# 查看 sshd jail 详情
fail2ban-client status sshd
# 手动解封某个 IP
fail2ban-client set sshd unbanip 203.0.113.66
# 手动封禁 IP(应急使用)
fail2ban-client set sshd banip 203.0.113.66
# 实时查看封禁日志
journalctl -u fail2ban -f
tail -f /var/log/fail2ban.log
注意:手动解封只是把 IP 从 iptables 中移除并清空计数,如果对方继续爆破,会再次触发封禁,这是正常行为。
八、常见排错:Fail2ban 为什么"不工作"?
1. 配置没生效,没有封禁任何 IP
先确认 jail 是否加载:fail2ban-client status 里有没有 sshd。若没有,多半是 jail.local 语法错误,查看错误:
fail2ban-client -t # 校验所有配置语法
tail -n 50 /var/log/fail2ban.log # 查看真实报错
2. 日志路径不对 / 读不到日志
Ubuntu 用 /var/log/auth.log,CentOS 用 /var/log/secure,写错路径会导致 jail 报 Unable to read the log file。先确认日志确实存在:
ls -l /var/log/auth.log /var/log/secure
grep "Failed password" /var/log/auth.log | tail
3. 封禁了仍然能登录?
优先检查三件事:
- SSH 是否走了自定义端口而 jail 里
port未同步修改。 - 攻击 IP 是否落在
ignoreip白名单里。 - 服务器是否同时监听 IPv6——Fail2ban 的 IPv6 封禁依赖 ip6tables,若
ip6tables不可用,IPv6 地址不会被拦截。可检查:ip6tables -L -n | grep f2b。
4. 正则匹配不到日志(自定义 filter 时)
写自定义 filter 时务必先用 fail2ban-regex 离线验证,不要在服务里反复试错:
fail2ban-regex /var/log/auth.log "Failed password for.* from <HOST>"
输出中的 Successfully matched 数量大于 0 才说明正则有效。
5. systemd backend 拿不到日志
journal 会持久化与否取决于 /etc/systemd/journald.conf 的 Storage 选项。若日志是易失的,建议显式指定 backend = auto 并确保日志文件存在。
6. bantime 永久封禁的副作用
把 bantime 设为 -1 永久封禁要慎重:一旦误封(比如把自家 IP 写进规则),只能手动 unbanip。生产环境建议先短封(如 30 分钟),确认规则无误后再逐步调大。
九、进阶:保护 Web 应用与 Nginx 登录接口
Fail2ban 不仅能保护 SSH,也能保护 Nginx 等 Web 服务。以 WordPress 后台登录爆破为例,先写 filter:
# /etc/fail2ban/filter.d/wp-login.conf
[Definition]
failregex = ^<HOST> .* "(GET|POST) /wp-login\.php.*" 401
ignoreregex =
再在 jail.local 中启用:
[wp-login]
enabled = true
port = http,https
logpath = /var/log/nginx/access.log
maxretry = 3
findtime = 300
bantime = 1h
同理,Nginx 对 401 状态、PHP 探测、目录扫描等都可以用 failregex 组合出对应的 filter,把 Fail2ban 从"SSH 保镖"升级成"全站门卫"。
十、小结
Fail2ban 的部署成本极低、收益立竿见影:一套 jail.local 即可挡住绝大多数暴力破解。最后给出三条生产建议:第一,防御核心仍是 SSH 密钥认证,Fail2ban 是补充而非替代;第二,规则上线前用 fail2ban-client -t 校验语法、用 fail2ban-regex 验证正则;第三,封禁动作与系统防火墙保持单一(iptables / ufw / firewalld 三选一),避免规则混乱。按本文步骤配置完成后,查看 fail2ban-client status sshd 的封禁数字不断上涨,你的服务器才算真正"披上了铠甲"。




