1Panel 服务器用 fail2ban 自动封禁恶意扫描 IP 实战
你的网站是不是经常被各种扫描器骚扰?日志里一堆
404、444?这篇文章手把手教你用 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:
- 进入 1Panel 面板 → 工具箱 → Fail2ban
- 如果尚未安装,界面会提示”未安装”,点击引导链接跳转到 1Panel 脚本库
- 在脚本库中找到 Fail2ban 安装脚本,执行安装即可
安装完成后回到工具箱 → Fail2ban,你就可以看到管理界面了。
如果你习惯用命令行,也可以通过 SSH 安装(
sudo apt-get install fail2ban或yum 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 的封禁列表是否在增长。如果正常有用户反映无法访问,随时可以解封。
希望这篇文章对你的服务器安全有所帮助!