背景 服务器 SSH 端口 22 一直暴露在公网,每天被扫。
lastb | wc -l 一看,一天几千次失败登录。
装了 fail2ban,但默认配置有几个问题:
只防 SSH,不防 Nginx 恶意请求
ban 时长太短(10 分钟),攻击者过会儿又来
ignoreip 没配,有次把自己 IP 封了
想做到:该封的封住,不该封的别误伤。
解决 一、基础结构 fail2ban 配置分两层:
bash
/etc/fail2ban/jail.conf ← 包管理的,升级会覆盖,别改
/etc/fail2ban/jail.d/*.conf ← 你自己加的,优先级更高
/etc/fail2ban/jail.local ← 也可以,但推荐用 jail.d/
规则:所有自定义放 /etc/fail2ban/jail.d/。
二、核心配置 创建 /etc/fail2ban/jail.d/00-local.conf:
ini
[DEFAULT]
# 封禁时长:1 小时
bantime = 1h
# 检测窗口:10 分钟
findtime = 10m
# 触发阈值:5 次失败
maxretry = 5
# 白名单:自己的 IP
ignoreip = 127.0.0.1/8 ::1 <YOUR_HOME_IP>
# 封禁动作:用 ufw 封(和你现有的防火墙配合)
banaction = ufw
[sshd]
enabled = true
port = 22
backend = systemd
maxretry = 3
bantime = 24h
关键点:
| 配置 | 作用 |
|---|---|
bantime = 1h |
封 1 小时,默认只有 10 分钟太短 |
maxretry = 5 |
10 分钟内失败 5 次就封 |
ignoreip |
必须配,否则可能把自己封了 |
banaction = ufw |
和已有的 ufw 联动,不额外装 iptables 规则 |
三、为 Nginx 加自定义规则 fail2ban 内置了 nginx-http-auth(basic auth 失败),但没有针对 404 扫描的。
新建 filter /etc/fail2ban/filter.d/nginx-404scan.conf:
ini
[Definition]
failregex = ^<HOST> -.*"(GET|POST|HEAD).*" 404
ignoreregex =
新建 jail /etc/fail2ban/jail.d/10-nginx.conf:
ini
[nginx-404scan]
enabled = true
port = http,https
filter = nginx-404scan
logpath = /var/log/nginx/access.log
maxretry = 20
findtime = 1m
bantime = 1h
含义:1 分钟内触发 20 次 404 → 封 1 小时。
为什么阈值这么高:正常用户也会遇到 404(比如浏览器请求 favicon),阈值太低会误伤。
四、验证
bash
# 看 jail 状态
sudo fail2ban-client status
sudo fail2ban-client status sshd
sudo fail2ban-client status nginx-404scan
# 看被封的 IP
sudo fail2ban-client status sshd | grep "Banned IP"
# 手动解封一个 IP
sudo fail2ban-client set sshd unbanip 1.2.3.4
# 测试 filter 能不能匹配日志
sudo fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/nginx-404scan.conf
五、日志在哪
bash
# fail2ban 自身日志
sudo journalctl -u fail2ban -n 50
# 或者
sudo tail -f /var/log/fail2ban.log
三个坑 坑 1:忘了配 ignoreip,把自己封了
ini
ignoreip = 127.0.0.1/8 ::1 <YOUR_HOME_IP>
必须包含:
本机回环
你自己的家庭/公司公网 IP
你的 CI/CD runner IP(如果它在跑部署)
怎么知道自己的公网 IP:
bash
curl -s ifconfig.me
如果真被封了怎么办:从腾讯云控制台用 VNC 登录(不走 SSH),解封。
bash
sudo fail2ban-client set sshd unbanip <你的IP>
坑 2:bantime 太短,攻击者回头再来 默认 10 分钟,攻击者过 10 分钟又能继续。
建议:
SSH:24h 以上(正常用户不会输错 3 次密码)
Nginx:1h 起步
进阶:bantime.increment = true,让反复被封的 IP 越封越久。
ini
[DEFAULT]
bantime.increment = true
bantime.factor = 2
bantime.maxtime = 1w
第一次封 1 小时,第二次 2 小时,第三次 4 小时......最多 1 周。
坑 3:filter 写错,匹配不到日志 failregex 用 Python 正则, 是内置占位符(匹配 IP)。
调试方法:用 fail2ban-regex 直接测:
bash
sudo fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/nginx-404scan.conf
会输出匹配到多少行、哪些没匹配。
常见错误:
日志格式变了(比如你换过 log_format)忘了改 filter
位置不对(必须在 IP 应该出现的地方)
转义字符漏了(" 要写 ")