针对 Debian 系统,以及 Imperva CDN 环境,使用“Fail2Ban + Nginx Deny” 的方案。
获取真实IP
使用Imperva时,nginx日志中只有CDN的IP地址,所以首先要获取真实IP。 配置文件在/etc/nginx/conf.d中加入配置文件:
# Imperva (Incapsula) IP Ranges
set_real_ip_from 199.83.128.0/21;
set_real_ip_from 198.143.32.0/19;
set_real_ip_from 149.126.72.0/21;
set_real_ip_from 103.28.248.0/22;
set_real_ip_from 45.64.64.0/22;
set_real_ip_from 185.11.124.0/22;
set_real_ip_from 192.230.64.0/18;
set_real_ip_from 107.154.0.0/16;
set_real_ip_from 45.60.0.0/16;
set_real_ip_from 45.223.0.0/16;
set_real_ip_from 2a02:26f0::/32;
# 告诉 Nginx 真实 IP 藏在哪个 Header 里
# Imperva 官方推荐 Incap-Client-IP,但也支持标准 X-Forwarded-For
# 我们先尝试标准方式,并开启递归搜索
#real_ip_header X-Forwarded-For;
real_ip_header Incap-Client-IP;
real_ip_recursive on;
官方建议使用real_ip_header Incap-Client-IP; 而不是X-Forwared-For。因为后者可能被伪造。
第一步:安装 Fail2Ban
sudo apt update
sudo apt install fail2ban -y
sudo systemctl status fail2ban
第二步:配置 Nginx 黑名单文件
创建一个文件专门存放被封禁的 IP,并让 Nginx 读取它。
创建黑名单文件:
sudo touch /etc/nginx/conf.d/ip_blacklist.conf # 设置权限,确保 Nginx 可读 sudo chmod 644 /etc/nginx/conf.d/ip_blacklist.conf修改 Nginx 主配置引入该文件: 编辑
/etc/nginx/nginx.conf:sudo nano /etc/nginx/nginx.conf在
http { ... }代码块内部,添加一行include指令:http { # ... 其他原有配置 ... # 引入 Fail2Ban 自动生成的黑名单 include /etc/nginx/conf.d/ip_blacklist.conf; # ... }测试并重载 Nginx:
sudo nginx -t # 如果显示 successful,则重载 sudo systemctl reload nginx
第三步:配置 Fail2Ban 的“动作” (Action)
告诉 Fail2Ban:“封禁 IP 时,不要去动防火墙,而是把 deny IP; 写入刚才那个文件里。”
创建自定义动作文件:
sudo nano /etc/fail2ban/action.d/nginx-deny.conf粘贴以下内容:
[Definition]
# 封禁时:追加 deny 规则到文件,并重载 Nginx
actionban = printf "deny <ip>;\n" >> /etc/nginx/conf.d/ip_blacklist.conf && systemctl reload nginx
# 解封时:使用 sed 删除对应行,并重载 Nginx
actionunban = sed -i "/deny <ip>;/d" /etc/nginx/conf.d/ip_blacklist.conf && systemctl reload nginx
按 Ctrl+O 保存,Ctrl+X 退出。
第四步:配置 Fail2Ban 的“过滤规则” (Filter)
需要告诉 Fail2Ban 如何从日志里识别那些扫描 WordPress 后门的攻击。
创建过滤规则文件:
sudo nano /etc/fail2ban/filter.d/nginx-php-scan.conf粘贴以下内容(可能需要修改,匹配你的日志格式):
[Definition]
# 匹配 "Primary script unknown" 错误,Nginx 会自动把 <HOST> 替换为真实 IP
failregex = ^\s*\[error\] \d+#\d+: \*\d+ FastCGI sent in stderr: "Primary script unknown" while reading response header from upstream, client: <HOST>
ignoreregex =
第五步:启用监控 (Jail)
最后,将规则和动作组合起来,启用监控。
创建/编辑本地配置文件(永远不要直接修改 jail.conf):
sudo nano /etc/fail2ban/jail.local在文件中添加以下内容:
[DEFAULT]
# 忽略你自己的 IP(如果有固定 IP,建议填入,防止误封自己)
ignoreip = 127.0.0.1/8 ::1
[nginx-php-scan]
enabled = true
# 使用我们刚才定义的 filter
filter = nginx-php-scan
# 指定 Nginx 错误日志路径(请确认你的路径是否正确)
logpath = /var/log/nginx/error.log
# 使用我们刚才定义的 action (nginx-deny)
banaction = nginx-deny
# 600秒(10分钟)内失败 3 次即封禁
maxretry = 3
findtime = 600
# 封禁时间:86400秒 (1天)
bantime = 86400
第六步:重启并验证
重启 Fail2Ban:
sudo systemctl restart fail2ban验证状态: 查看 jail 是否启动成功:
sudo fail2ban-client status nginx-php-scan下面应该看到
Currently failed和Currently banned的统计数据。如何手动测试? 可以手动往日志里写入一条模拟攻击记录(小心不要填自己的 IP,填一个假 IP,比如
1.2.3.4):# 模拟写入日志 sudo sh -c 'echo "2026/01/12 16:13:04 [error] 123#123: *1 FastCGI sent in stderr: \"Primary script unknown\" while reading response header from upstream, client: 1.2.3.4, server: test" >> /var/log/nginx/error.log'重复执行该命令 3 次。
检查是否生效:
- 检查 Fail2Ban 状态:
应该看到sudo fail2ban-client status nginx-php-scanBanned IP list: 1.2.3.4。 - 检查 Nginx 黑名单文件:
应该能看到cat /etc/nginx/conf.d/ip_blacklist.confdeny 1.2.3.4;。
- 检查 Fail2Ban 状态:
手动解封(测试用):
sudo fail2ban-client set nginx-php-scan unbanip 1.2.3.4
关键提示
由于你使用了 Imperva,请务必确认 Nginx 的 set_real_ip_from 和 real_ip_header 配置已经生效。如果 Nginx 日志里记录的还是 CDN 的 IP,Fail2Ban 就会误封 CDN 节点,导致所有用户无法访问!
