Fail2ban 实战:SSH 防暴力破解、防火墙联动与常见排错


<!DOCTYPE html>

Fail2ban 实战:SSH 防暴力破解、防火墙联动与常见排错

任何暴露在公网上的 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 的封禁数字不断上涨,你的服务器才算真正"披上了铠甲"。


手机扫码阅读

微信或手机浏览器扫一扫,随时随地随心阅读与分享

Linux 网络故障排查实战:ping、traceroute、mtr、dig 与 tcpdump 全链路定位指南

Nginx 强制 HTTPS 跳转实战:301/302 选型、HSTS 配置与常见排错

评 论
更换验证码