
上周二凌晨三点,我手机的服务器报警群突然炸了。爬起来一看,一台闲置的测试机 CPU 占用率直接飙到了 98%,Load Average 甚至超过了 CPU 核心数的 5 倍。这就是典型的 CC 攻击(HTTP Flood)。
很多新手站长遇到这种情况,第一反应是去装防火墙软件。其实,在 Linux 环境下,攻击的特征都写在日志里。今天我不讲空洞的理论,直接还原我当时是如何通过 Nginx 原生模块配合 Fail2Ban 把这波攻击挡回去的。
第一步:现场取证,分析日志特征
防御的前提是知道敌人在哪。我们直接进入服务器日志目录(通常在 /www/wwwlogs/ 或 /var/log/nginx/),使用 tail 命令实时查看:
tail -f access.log | grep -v "Googlebot"
当时的日志大概是这样的(这里为了演示我精简了一下):
183.192.xx.xx - - [14/Jan/2026:03:15:01] "GET /?s=123 HTTP/1.1" 200 562 "-" "Mozilla/5.0..." 183.192.xx.xx - - [14/Jan/2026:03:15:01] "GET /?s=123 HTTP/1.1" 200 562 "-" "Mozilla/5.0..." 183.192.xx.xx - - [14/Jan/2026:03:15:02] "GET /?s=123 HTTP/1.1" 200 562 "-" "Mozilla/5.0..."
特征非常明显: 同一个 IP,在短短一秒内对 /?s=123 这个搜索接口发起了几十次请求。这显然不是人类的手速,而是脚本工具。
第二步:Nginx 漏桶算法限流
既然知道了对方是高频请求,我们首先要做的就是在 Nginx 层面“降速”。这里有一个很多教程没讲透的细节:为什么要用 binary_remote_addr?
打开 nginx.conf,在 http 块中添加:
# 开辟一块10M的内存区域,命名为 limit_cc # $binary_remote_addr 比 $remote_addr (字符串) 更省内存,IPv4仅占4字节 limit_req_zone $binary_remote_addr zone=limit_cc:10m rate=5r/s;
这里我设置了 rate=5r/s,意味着同一个 IP 每秒只能请求 5 次。对于绝大多数内容站来说,这完全够用了。
接着,在具体的 server 块中应用它:
location / {
# burst=10 允许突发10个请求排队,nodelay 表示超过队列直接返回503
limit_req zone=limit_cc burst=10 nodelay;
}第三步:Fail2Ban 编写正则主动封禁
Nginx 限流虽然能减轻数据库压力,但 Nginx 本身还得处理握手,返回 503 也是消耗资源的。最彻底的方法是:既然你超速了,我就让防火墙把你拉黑。
我们安装 Fail2Ban 后,需要新建一个规则文件 /etc/fail2ban/filter.d/nginx-cc.conf。这里需要用到正则表达式来匹配 Nginx 的错误日志:
[Definition] # 匹配 Nginx error.log 中由 limit_req 模块产生的日志 # 日志示例:limiting requests, excess: 10.xxx by zone "limit_cc", client: 1.2.3.4 failregex = limiting requests, excess:.* by zone.*client:ignoreregex =
然后编辑 jail.local 启用这个监狱:
[nginx-cc] enabled = true filter = nginx-cc port = http,https logpath = /www/wwwlogs/www.lunvps.com.error.log maxretry = 5 bantime = 86400 # 甚至可以设置得更狠一点,封他24小时 action = iptables-allports
重启 Fail2Ban 后,我们可以通过命令 fail2ban-client status nginx-cc 查看战果。你会看着被 Ban 的 IP 列表在不断增加,而服务器的负载会肉眼可见地降下来。
总结
技术防御没有银弹。对于小规模的 CC 攻击(几十到几百个 IP),这套 "Nginx限流 + Fail2Ban封禁" 的组合拳成本最低、效果最好。如果攻击流量实在太大(比如打满了你的带宽),那这就属于 DDoS 的范畴了,这时候请毫不犹豫地套上 Cloudflare。
