13 10 月 2026

防火墙只能挡端口,挡不住"用合法端口反复试密码"的行为。SSH 的 22 端口你总得开,扫描器就会天天来试。

fail2ban 解决这个问题:它盯着日志,发现某个 IP 在短时间内反复失败,就自动把它加进防火墙黑名单。整个过程全自动,配好后基本不用管。

财富云计算 的云服务器支持安装 fail2ban;做内网服务、游戏服务端可选 NAT 型(无独立公网 IP,价格比独立 IP 机型省一半以上)。

一、fail2ban 能防护什么

服务防护内容
SSH反复尝试登录
Nginx/Apache反复 401 认证失败、扫后台、CC 刷接口
WordPress/Typecho后台登录爆破
FTP账号爆破
邮件(Postfix/Dovecot)账号爆破
任意服务只要日志里有失败记录,就能写规则

工作原理:

监控日志文件
   → 用正则(filter)匹配失败记录
   → 统计来源 IP 的失败次数
   → 达到阈值(maxretry)就执行动作(ban)
   → 动作通常是加一条 iptables/firewalld 规则封禁
   → 到时间(bantime)自动解封

二、安装

# Debian/Ubuntu
apt update
apt install fail2ban -y

# CentOS/Rocky
yum install epel-release -y
yum install fail2ban -y

systemctl enable --now fail2ban
fail2ban-client version

三、配置文件结构

/etc/fail2ban/
├── fail2ban.conf        # 主配置(一般不动)
├── jail.conf            # 默认规则(不要直接改,会被升级覆盖)
├── jail.local           # ← 你的自定义配置写这里
├── jail.d/*.conf        # 额外的规则文件
├── filter.d/            # 过滤器(匹配日志的正则)
│   ├── sshd.conf
│   ├── nginx-http-auth.conf
│   └── ...
└── action.d/            # 动作(封禁方式)
    ├── iptables.conf
    ├── firewallcmd.conf
    └── ...

关键原则:永远改 jail.local 或 jail.d/ 下的文件,不要改 jail.conf。

cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
nano /etc/fail2ban/jail.local

四、核心参数

[DEFAULT]
# 不封禁的 IP(白名单),务必加上自己的 IP 和内网
ignoreip = 127.0.0.1/8 ::1 192.168.0.0/16 10.0.0.0/8 你的公网IP

# 封禁时长(秒),-1 表示永久
bantime  = 86400

# 统计窗口(秒):在这个时间内的失败次数
findtime = 600

# 允许的失败次数
maxretry = 3

# 封禁方式(自动检测)
banaction = iptables-multiport
# CentOS 7+ 用:banaction = firewallcmd-ipset

# 后端(自动检测 systemd 或文件)
backend = auto

# 邮件通知(可选)
destemail = you@example.com
sender = fail2ban@example.com
mta = sendmail
action = %(action_)s        # 只封禁
# action = %(action_mw)s    # 封禁 + 发邮件
# action = %(action_mwl)s   # 封禁 + 发邮件 + 附日志

参数怎么理解:

findtime=600 + maxretry=3 = "10 分钟内失败 3 次就封"。


五、配置 SSH 防护

[sshd]
enabled  = true
port     = ssh              # 或改成你的实际端口,如 2299
filter   = sshd
logpath  = /var/log/auth.log        # CentOS 是 /var/log/secure
maxretry = 3
findtime = 600
bantime  = 86400
systemctl restart fail2ban

验证

fail2ban-client status
fail2ban-client status sshd

输出:

Status for the jail: sshd
|- Filter
|  |- Currently failed: 2
|  |- Total failed: 47
|  `- File list: /var/log/auth.log
`- Actions
   |- Currently banned: 3
   |- Total banned: 12
   `- Banned IP list: 45.13.xx.xx 103.xx.xx.xx 185.xx.xx.xx

手动测试(从另一台机器故意输错密码 3 次),然后看是否被封:

fail2ban-client status sshd
iptables -L -n | grep f2b-sshd

六、Nginx 防护

1)HTTP 认证失败

[nginx-http-auth]
enabled  = true
filter   = nginx-http-auth
port     = http,https
logpath  = /var/log/nginx/error.log
maxretry = 5
findtime = 600
bantime  = 3600

2)封禁扫描后台的 IP(如 /admin、/wp-login.php、/.env)

先看日志格式,常见的是访问日志里出现大量 404。

创建自定义 filter:

nano /etc/fail2ban/filter.d/nginx-scan.conf
[Definition]
failregex = ^<HOST> -.*"(GET|POST|HEAD).*(/\.env|/\.git|/wp-login\.php|/xmlrpc\.php|/admin|/phpmyadmin|/shell\.php).*" (404|403|301|200)
ignoreregex =

创建 jail:

nano /etc/fail2ban/jail.d/nginx-scan.conf
[nginx-scan]
enabled  = true
filter   = nginx-scan
port     = http,https
logpath  = /var/log/nginx/access.log
maxretry = 5
findtime = 300
bantime  = 86400

3)防 CC(请求频率过高)

nano /etc/fail2ban/filter.d/nginx-cc.conf
[Definition]
failregex = ^<HOST> -.*"(GET|POST).*" 200
ignoreregex =
[nginx-cc]
enabled  = true
filter   = nginx-cc
port     = http,https
logpath  = /var/log/nginx/access.log
maxretry = 200          # 阈值放宽,别误伤正常用户
findtime = 60
bantime  = 3600
防 CC 更推荐用 Nginx 自带的 limit_req(性能更好,不依赖日志分析)。fail2ban 的 CC 防护适合日志量不大的小站。

4)封禁恶意爬虫

[Definition]
failregex = ^<HOST> -.*"(GET|POST).*" (4\d\d) .*"(scrapy|python-requests|curl|wget|AhrefsBot|SemrushBot)"

七、自定义 filter:给任意服务加防护

步骤:

1)先找到日志里的失败记录

tail -100 /path/to/app.log | grep -i "fail\|error\|invalid"

假设有:

2026-10-12 14:23:01 [WARN] Login failed for user admin from 45.13.22.11

2)写 filter

nano /etc/fail2ban/filter.d/myapp.conf
[Definition]
failregex = Login failed for user .* from <HOST>
ignoreregex =

<HOST> 是固定占位符,会被替换成 IP 匹配正则。

3)测试正则(很重要)

fail2ban-regex /path/to/app.log /etc/fail2ban/filter.d/myapp.conf

输出会显示匹配到多少条、匹配了哪些行。一定要测,正则写错等于没防护。

4)写 jail

nano /etc/fail2ban/jail.d/myapp.conf
[myapp]
enabled  = true
filter   = myapp
port     = 8080
logpath  = /path/to/app.log
maxretry = 5
findtime = 600
bantime  = 7200

5)重启验证

systemctl restart fail2ban
fail2ban-client status myapp

八、常用命令

# 状态
fail2ban-client status                    # 所有 jail
fail2ban-client status sshd               # 单个 jail

# 手动封禁/解封
fail2ban-client set sshd banip 1.2.3.4
fail2ban-client set sshd unbanip 1.2.3.4
fail2ban-client set sshd unbanip --all    # 解封所有

# 加白名单(永久)
fail2ban-client set sshd addignoreip 1.2.3.4

# 重载配置
fail2ban-client reload
fail2ban-client reload sshd

# 停止/启动某个 jail
fail2ban-client stop sshd
fail2ban-client start sshd

# 测试 filter 正则
fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf

# 查看日志
tail -f /var/log/fail2ban.log

九、动作(action):封禁之外还能做什么

默认动作是封 IP,也可以配置发邮件、调用 API 等。

内置动作:

动作行为
%(action_)s只封禁
%(action_mw)s封禁 + 发邮件
%(action_mwl)s封禁 + 发邮件 + 附日志片段
%(action_abuseipdb)s上报到 AbuseIPDB(需 API key)

配置邮件通知:

apt install sendmail mailutils -y    # 或配 ssmtp/msmtp
[DEFAULT]
destemail = you@example.com
sender = fail2ban@example.com
mta = sendmail

[sshd]
action = %(action_mwl)s

调用钉钉/企业微信机器人(更实用):

nano /etc/fail2ban/action.d/dingtalk.conf
[Definition]
actionstart =
actionstop =
actioncheck =
actionban = curl -s -X POST 'https://oapi.dingtalk.com/robot/send?access_token=xxx' \
            -H 'Content-Type: application/json' \
            -d '{"msgtype":"text","text":{"content":"fail2ban 封禁 IP: <ip> (jail: <name>)"}}'
actionunban =
[sshd]
action = iptables-multiport
         dingtalk

十、持久化与开机自启

systemctl enable fail2ban

fail2ban 有 SQLite 数据库(/var/lib/fail2ban/fail2ban.sqlite3)记录封禁历史,重启后不会丢失已封 IP 的计时。

清空数据库(规则太多想重置):

systemctl stop fail2ban
rm /var/lib/fail2ban/fail2ban.sqlite3
systemctl start fail2ban

十一、调优与注意事项

1)别把自己封在外面

ignoreip = 127.0.0.1/8 ::1 你的常用IP 内网网段

万一被封:走云控制台 VNC 登录,执行:

fail2ban-client set sshd unbanip 你的IP
# 或
systemctl stop fail2ban
iptables -L -n --line-numbers | grep f2b
iptables -D f2b-sshd 1

2)bantime 递增(重复犯事的封更久)

[DEFAULT]
bantime  = 3600
bantime.increment = true
bantime.factor = 2
bantime.maxtime = 604800      # 最多封 7 天

第一次 1 小时,第二次 2 小时,第三次 4 小时……

3)日志量太大影响性能

fail2ban 要实时读日志,日志量极大的站点会有开销。可以:

  • 只启用必要的 jail
  • 增大 findtime,减少匹配频率
  • 用 journal 后端(systemd)代替文件轮询:
[sshd]
backend = systemd

4)Docker 容器里的服务

Docker 日志默认不写文件,fail2ban 读不到。解决:

  • 让容器把日志写到宿主机某个目录
  • 或用 docker logs 配合脚本
  • 或容器应用本身就是反代后,用 Nginx 的日志来封

5)IPv6

确保 iptables 规则也覆盖 ip6tables:

banaction = iptables-multiport
banaction_allports = iptables-allports

现代版本会自动处理。

6)误封正常用户

  • 把公司/家庭固定 IP 加白名单
  • 防 CC 的 maxretry 别设太低(建议 100+/分钟)
  • 定期看 Banned IP list,发现误封及时调整

十二、完整配置示例(可直接用)

nano /etc/fail2ban/jail.local
[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 192.168.0.0/16 10.0.0.0/8
bantime  = 86400
bantime.increment = true
bantime.factor = 2
bantime.maxtime = 604800
findtime = 600
maxretry = 3
backend  = auto
banaction = iptables-multiport

destemail = you@example.com
sender = fail2ban@localhost
action = %(action_)s

[sshd]
enabled  = true
port     = 2299
filter   = sshd
logpath  = /var/log/auth.log
maxretry = 3
findtime = 600
bantime  = 86400

[nginx-http-auth]
enabled  = true
port     = http,https
filter   = nginx-http-auth
logpath  = /var/log/nginx/error.log
maxretry = 5
bantime  = 3600

[nginx-noscript]
enabled  = true
port     = http,https
filter   = nginx-noscript
logpath  = /var/log/nginx/access.log
maxretry = 6
bantime  = 86400

[nginx-badbots]
enabled  = true
port     = http,https
filter   = nginx-badbots
logpath  = /var/log/nginx/access.log
maxretry = 2
bantime  = 86400

[nginx-noproxy]
enabled  = true
port     = http,https
filter   = nginx-noproxy
logpath  = /var/log/nginx/access.log
maxretry = 2
bantime  = 86400
nginx-noscript / nginx-badbots / nginx-noproxy 是 fail2ban 自带的 filter,一般安装后就有,用 ls /etc/fail2ban/filter.d/ | grep nginx 确认。
systemctl restart fail2ban
fail2ban-client status

十三、fail2ban 不是万能的

它能挡:

  • ✅ 密码爆破
  • ✅ 明显的扫描行为
  • ✅ 高频 CC(辅助)

它挡不住:

  • ❌ 分布式 CC(IP 太多,封不过来)→ 用 Nginx limit_req + CDN
  • ❌ 应用层漏洞(SQL 注入等)→ 靠程序安全
  • ❌ 已经拿到密码的攻击者 → 靠密钥登录 + 强密码
  • ❌ 慢速攻击(低频但持续)→ 靠 WAF

正确的安全是分层的:防火墙 + fail2ban + 密钥登录 + 及时打补丁 + 最小权限 + 备份,缺一不可。


服务器上线就该装 fail2ban。财富云计算 的云服务器支持完整管理员权限,可自由安装配置;做内网服务、游戏服务端可选 NAT 型(无独立公网 IP,价格比带独立 IP 机型省一半以上),配合端口映射按需开放,暴露面更小更安全。

相关阅读:

  • 《SSH 密钥登录与账号安全配置》
  • 《Linux 防火墙配置:ufw / firewalld / iptables》
  • 《服务器被入侵应急排查与处置》
  • 《网站常见漏洞与基础防护》
延伸阅读
  1. 网站环境怎么选:LNMP 手动 / 宝塔面板 / Docker / 云开发
  2. 问卷表单系统搭建:SurveyKing / Formbricks,数据自己收
  3. 图床搭建:Lsky Pro / Lychee,自托管图片托管方案
  4. 邮件列表搭建:listmonk 自托管 Newsletter,把读者握在自己手里
  5. 文档站点搭建:MkDocs / VuePress / Docsify,产品文档与技术手册方案
  6. RSS 阅读器搭建:FreshRSS 自托管,把信息流拿回自己手里
  7. 短链接服务搭建:Shlink 自托管,链接数据自己掌握
  8. 网站状态监控页搭建:Uptime Kuma,服务器挂了第一时间知道
更多阅读
  1. 上一篇:Linux 防火墙配置实战:ufw / firewalld / iptables 该怎么选
  2. 下一篇:服务器被入侵应急排查与处置:发现异常后该做什么
发表评论 9

取消回复