1Panel 服务器用 fail2ban 自动封禁恶意扫描 IP 实战教程

1Panel 服务器用 fail2ban 自动封禁恶意扫描 IP 实战

你的网站是不是经常被各种扫描器骚扰?日志里一堆 404444?这篇文章手把手教你用 1Panel + fail2ban 实现自动防御。


背景

最近我的导航站(就是你现在看到的这个)频繁遭遇恶意扫描。攻击者通过 Azure 云服务器批量扫描网站的 PHP 文件(/x.php/shell.php/wpconf.php 等等),寻找未安装的漏洞脚本。一天的访问日志中,超过 80% 的请求都是这种扫描流量

虽然 Nginx 的 444 规则能拦截它们,但请求还是到达了服务器,占用了 PHP-FPM 进程和带宽。如果不能自动封禁 IP,攻击者换个 IP 又能继续扫。

解决方案:fail2ban。


什么是 fail2ban?

fail2ban 是一个日志监控工具。它会实时扫描日志文件,当某个 IP 在短时间内出现大量失败请求时,自动将其加入防火墙黑名单。

简单说:60 秒内扫我 5 次 → 自动 ban 24 小时,不用你动手。


前置条件

  • 服务器安装的是 1Panel 面板(本文基于 1Panel 操作)
  • Nginx/OpenResty 作为 Web 服务器
  • 有 SSH 登录权限

第一步:安装 fail2ban

在 1Panel 面板内安装,无需 SSH:

  1. 进入 1Panel 面板 → 工具箱Fail2ban
  2. 如果尚未安装,界面会提示”未安装”,点击引导链接跳转到 1Panel 脚本库
  3. 在脚本库中找到 Fail2ban 安装脚本,执行安装即可

安装完成后回到工具箱 → Fail2ban,你就可以看到管理界面了。

如果你习惯用命令行,也可以通过 SSH 安装(sudo apt-get install fail2banyum install fail2ban),但 1Panel 面板方式更省事。


第二步:在 1Panel 中添加规则

进入 工具箱 → Fail2ban,你会看到两个模式:

  • 基础配置:只有 SSH 端口的可视化配置(发邮件告警等简单选项)
  • 全部配置:手写 YAML,所有自定义规则都在这里配置

⚠️ Nginx 的扫描拦截规则没有可视化界面,需要通过「全部配置」手写 + SSH 创建 filter 文件。

点击「全部配置」,在已有内容后面追加以下规则:

# ====== 规则 1:精准拦截 PHP 探针扫描 ======
[nginx-php-scan]
enabled = true
port = http,https
filter = nginx-php-scan
logpath = /opt/1panel/www/sites/lxzt.fun/log/access.log
maxretry = 5
findtime = 60
bantime = 86400
action = iptables-allports[name=nginx-php-scan]

# ====== 规则 2:兜底拦截无头扫描器 ======
[nginx-bad-request]
enabled = true
port = http,https
filter = nginx-bad-request
logpath = /opt/1panel/www/sites/lxzt.fun/log/access.log
maxretry = 8
findtime = 60
bantime = 86400
action = iptables-allports[name=nginx-bad-request]

⚠️ 把 logpath 换成你自己网站的 Nginx 日志路径。1Panel 的典型路径是 /opt/1panel/www/sites/<站点名>/log/access.log


第三步:创建过滤规则文件(SSH 操作)

1Panel 没有过滤规则的可视化界面,需要 SSH 创建两个文件。

3.1 PHP 探针拦截规则

sudo tee /etc/fail2ban/filter.d/nginx-php-scan.conf << 'EOF'
[Definition]
failregex =
  # 访问 .php 返回 404/444/403 → 扫描器
  ^<HOST> -.*"(?:GET|POST) .+.phps+HTTP/[0-9.]+"s+(?:404|444|403)
  # 访问 wp_filemanager 返回 403/404/444 → 漏洞利用尝试
  ^<HOST> -.*"(?:GET|POST) .*/wp_filemanager.*s+HTTP/[0-9.]+"s+(?:403|404|444)
ignoreregex =
  # 放行 wp-admin 的正常后台请求
  ^<HOST> -.*"(?:GET|POST) .*/wp-admin/.*s+HTTP/[0-9.]+"s+200
  ^<HOST> -.*"(?:GET|POST) .*/wp-admin/admin-ajax.phps+HTTP/[0-9.]+"s+200
  ^<HOST> -.*"(?:GET|POST) .*/wp-cron.phps+HTTP/[0-9.]+"s+200
EOF

匹配规则解读

部分 含义
^<HOST> 日志开头的 IP 地址
.* IP 后面的任意字符(日期、请求行等)
(?:GET|POST) 匹配 GET 或 POST 请求
.+.php 请求路径以 .php 结尾
s+(?:404|444|403) 状态码为 404/444/403
.*/wp-admin/.*s+200 豁免:wp-admin 下状态码 200 的请求不计入失败

3.2 无头扫描器兜底规则

sudo tee /etc/fail2ban/filter.d/nginx-bad-request.conf << 'EOF'
[Definition]
failregex =
  # 状态码 403/404/444 + Referer 和 UA 都是空 → 脚本扫描器
  ^<HOST> -.*s+(?:403|404|444)s+d+s+"-"s+"-"s+"
ignoreregex =
EOF

它的原理:正常浏览器访问网站一定带有 User-Agent(比如 Mozilla/5.0 ... Chrome/xxx),而脚本扫描器的 User-Agent 和 Referer 都是空的(日志中显示为 "-")。两个字段同时为空,说明不是人类访问,封它没商量。


第四步:用 fail2ban-regex 测试规则

在执行任何配置之前,强烈建议先用 fail2ban-regex 测试一下规则是否能正确匹配你的日志

# 测试 PHP 探针规则
sudo fail2ban-regex /opt/1panel/www/sites/lxzt.fun/log/access.log /etc/fail2ban/filter.d/nginx-php-scan.conf

# 测试无头扫描规则
sudo fail2ban-regex /opt/1panel/www/sites/lxzt.fun/log/access.log /etc/fail2ban/filter.d/nginx-bad-request.conf

你会看到类似这样的输出:

Results
=======
Failregex: 300 total
Lines: 482 lines, 0 ignored, 300 matched, 182 missed
  • matched:命中的日志条数(这些就是攻击请求 ✅)
  • missed:未命中的日志条数(正常请求,不会被误封 ✅)

我测试时 nginx-php-scan 命中了 300 条nginx-bad-request 命中了 364 条,两条规则有部分重叠但不冲突,分工明确。


第五步:重启生效

sudo systemctl restart fail2ban

检查规则运行状态:

# 列出所有规则
sudo fail2ban-client status

# 查看 PHP 探针规则的封禁情况
sudo fail2ban-client status nginx-php-scan

# 查看无头扫描规则的封禁情况
sudo fail2ban-client status nginx-bad-request

如果看到类似以下输出,说明配置成功:

Status for the jail: nginx-php-scan
|- Filter
|  |- Currently failed: 0
|  |- Total failed:     12
|  `- File list:        /opt/1panel/www/sites/lxzt.fun/log/access.log
`- Actions
   |- Currently banned: 3
   |- Total banned:     5
   `- Banned IP list:   20.104.203.253, 20.151.116.187, 45.8.19.56

第六步:手动加入已知恶意 IP(可选)

重启 fail2ban 后,旧的攻击记录不会触发封禁。建议手动把之前发现的可疑 IP 加入黑名单:

sudo fail2ban-client set nginx-php-scan banip 20.226.116.19
sudo fail2ban-client set nginx-php-scan banip 20.104.203.253
sudo fail2ban-client set nginx-php-scan banip 20.151.116.187
sudo fail2ban-client set nginx-php-scan banip 45.8.19.56
sudo fail2ban-client set nginx-php-scan banip 45.8.19.46
sudo fail2ban-client set nginx-php-scan banip 216.73.160.117
sudo fail2ban-client set nginx-php-scan banip 216.73.161.248

也可以在 1Panel 面板的 工具箱 → Fail2ban → IP 黑名单 中手动添加。


效率对比:手动 vs 自动

方式 响应速度 是否需要人工 漏网之鱼
手动封 IP 数小时甚至数天 ✅ 需要 很多(发现时已被扫很久)
Nginx 444 拦截 即时 ❌ 不需要 请求仍到服务器,占用资源
fail2ban 自动封禁 60 秒内 不需要 极少(换 IP 后 60s 再封)

常见问题

Q:会误封正常用户吗?

基本不会。 两条规则的触发条件是:
1. 访问 不存在的 .php 文件 返回 404/444/403
2. User-Agent 和 Referer 都为空

正常用户不会在 60 秒内访问 5 个不存在的 .php 文件,而且正常浏览器一定有 User-Agent。

Q:会影响搜索引擎收录吗?

不会。 搜索引擎爬虫(Googlebot、Bingbot 等)都有合法的 User-Agent,不会被 nginx-bad-request 拦截。而 nginx-php-scan 规则只匹配 .php 文件的 404/444/403,搜索引擎不会大量请求不存在的 .php 文件。

Q:封禁时间到了会自动解封吗?

会。 24 小时后自动解封。如果同一个 IP 再次触发规则,会重新封禁。如果需要永久封禁,把 bantime 设为 -1

Q:怎么手动解封一个 IP?

sudo fail2ban-client set nginx-php-scan unbanip 20.104.203.253

完整配置一览

方便你直接复制使用。把下面内容粘贴到 1Panel → 工具箱 → Fail2ban → 全部配置 中:

[DEFAULT]
bantime = 600
findtime = 300
maxretry = 5
banaction = firewallcmd-ipset
action = %(action_mwl)s

[sshd]
ignoreip = 127.0.0.1/8
enabled = true
filter = sshd
port = 22
maxretry = 2
findtime = 300
bantime = 600
action = %(action_mwl)s
banaction = iptables-multiport
logpath = /var/log/auth.log

[nginx-php-scan]
enabled = true
port = http,https
filter = nginx-php-scan
logpath = /opt/1panel/www/sites/lxzt.fun/log/access.log
maxretry = 5
findtime = 60
bantime = 86400
action = iptables-allports[name=nginx-php-scan]

[nginx-bad-request]
enabled = true
port = http,https
filter = nginx-bad-request
logpath = /opt/1panel/www/sites/lxzt.fun/log/access.log
maxretry = 8
findtime = 60
bantime = 86400
action = iptables-allports[name=nginx-bad-request]

两个 filter 文件的内容也在下面,SSH 直接执行即可:

# PHP 探针规则
sudo tee /etc/fail2ban/filter.d/nginx-php-scan.conf << 'EOF'
[Definition]
failregex =
  ^<HOST> -.*"(?:GET|POST) .+.phps+HTTP/[0-9.]+"s+(?:404|444|403)
  ^<HOST> -.*"(?:GET|POST) .*/wp_filemanager.*s+HTTP/[0-9.]+"s+(?:403|404|444)
ignoreregex =
  ^<HOST> -.*"(?:GET|POST) .*/wp-admin/.*s+HTTP/[0-9.]+"s+200
  ^<HOST> -.*"(?:GET|POST) .*/wp-admin/admin-ajax.phps+HTTP/[0-9.]+"s+200
  ^<HOST> -.*"(?:GET|POST) .*/wp-cron.phps+HTTP/[0-9.]+"s+200
EOF

# 无头扫描器规则
sudo tee /etc/fail2ban/filter.d/nginx-bad-request.conf << 'EOF'
[Definition]
failregex =
  ^<HOST> -.*s+(?:403|404|444)s+d+s+"-"s+"-"s+"
ignoreregex =
EOF

配置完成后重启即可:

sudo systemctl restart fail2ban

设置好之后,你可以观察几天的日志,看 fail2ban 的封禁列表是否在增长。如果正常有用户反映无法访问,随时可以解封。

希望这篇文章对你的服务器安全有所帮助!

© 版权声明

相关文章

暂无评论

none
暂无评论...