
你有没有遇到过这种怪事:服务器CPU突然飙到100%,带宽没跑满,但网站打不开了。你查了日志,发现同一秒内有几百个请求刷同一个页面。不是DDoS(那种会把你带宽打爆),而是CC攻击——用大量看似正常的请求,耗尽你的应用资源。你的CPU被PHP占满,数据库连接数爆了,但防火墙没报警,因为每个请求看起来都像真人。
这就是CC攻击的狡猾之处。它不拼流量,拼的是你服务器的处理能力。而对付它最直接的手段,就是在Nginx层面做限流。今天教你配置。
先看一个场景
一个做在线教育的朋友,有天下午网站突然挂了。上去一看,CPU 100%,全是PHP-FPM进程。
查访问日志,发现同一个IP每秒请求200多次同一个搜索接口。这个接口本身消耗就大,每秒200次直接打爆。他没装任何限流措施,攻击者用一台小破电脑就把他整站搞瘫痪了。
后来他在Nginx里加了两行限流配置,类似的攻击再来时,服务器稳如泰山,只是攻击者的请求被直接拒绝了。
限流是什么?——给每个IP设定“访问速度上限”
Nginx限流的核心是限制每个IP在单位时间内的请求次数。比如,限制每个IP每秒最多只能发10个请求。超过的部分,你可以选择拒绝(返回503),或者排队慢慢处理。
Nginx实现限流主要靠两个模块:
limit_req_zone:限制请求频率(每秒/每分钟多少个请求)limit_conn_zone:限制并发连接数(同一时刻多少个连接)
CC攻击通常用高频请求打你,所以limit_req更对症。
配置实战
第一步:定义限流规则
在nginx.conf的http块里添加:
nginx
http {
# 定义限流规则
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
}
参数说明:
$binary_remote_addr:按客户端IP限流zone=mylimit:10m:分配10MB共享内存,用于存储IP状态rate=10r/s:限制每个IP每秒最多10个请求
第二步:应用限流
在需要保护的location块里加上:
nginx
location / {
limit_req zone=mylimit burst=20 nodelay;
# 其他配置...
}
参数说明:
zone=mylimit:引用上面定义的规则burst=20:允许突发20个请求排队,超过的部分直接拒绝nodelay:排队中的请求不延迟处理,立即处理但计入burst限额
效果:正常情况下,用户一秒发10个请求(比如疯狂点按钮),前10个正常处理,后10个排队(如果加了burst),再多的直接返回503。
反常识点:burst不是越大越好。给攻击者留了更多空间。建议默认10-20,特殊情况单独调整。
第三步:返回友好提示
被限流的请求默认返回503。可以自定义错误页面:
nginx
limit_req zone=mylimit burst=20 nodelay; limit_req_status 429;
429 Too Many Requests是比503更符合语义的状态码。然后在server块里定义错误页:
nginx
error_page 429 /429.html;
location = /429.html {
root /usr/share/nginx/html;
}
限流策略分级
不同接口的限流阈值应该不同:
| 接口类型 | 示例 | 建议限流 | 原因 |
|---|---|---|---|
| 静态文件(CSS/JS/图片) | /static/* | 不限流或高阈值(100r/s) | 消耗小,对服务器压力低 |
| 普通页面 | /article/* | 30-50r/s | 有缓存,相对轻量 |
| 搜索接口 | /search | 5-10r/s | 查询数据库,消耗大 |
| 登录接口 | /login | 3-5r/s | 防暴力破解,低阈值 |
| API接口 | /api/* | 根据业务定 | 需评估正常峰值 |
配置示例:
nginx
# 搜索接口严格限流
location /search {
limit_req zone=mylimit burst=10 nodelay;
limit_req_status 429;
proxy_pass http://backend;
}
# 静态文件不限流
location ~* \.(css|js|jpg|png)$ {
expires 30d;
# 不应用限流
}
进阶:白名单与黑名单
白名单:给搜索引擎、合作伙伴的IP放行
nginx
geo $limit {
default 1;
192.168.1.0/24 0; # 内网不限流
1.2.3.4 0; # 合作方IP不限流
}
map $limit $limit_key {
1 $binary_remote_addr;
0 "";
}
limit_req_zone $limit_key zone=mylimit:10m rate=10r/s;
黑名单:手动封掉恶意IP
直接在server块里用deny:
nginx
location / {
deny 123.45.67.89;
deny 98.76.54.32;
}
或者用include引用黑名单文件:include /etc/nginx/blacklist.conf;
限流效果测试
配置完成后,用ab(Apache Bench)测试一下:
bash
# 模拟100个请求,并发10个 ab -n 100 -c 10 http://你的域名/
观察返回结果。如果有限流,会看到一部分请求返回429。再查看Nginx日志,确认限流生效。
一个真实案例
一个WordPress新闻站,被CC攻击打搜索接口。攻击者用肉鸡轮换IP,每个IP频率不高但总量大,IP分散很难封。他们在Nginx里对/search接口设置了rate=5r/s。攻击流量一来,大部分请求直接在Nginx层被挡掉,后端PHP-FPM压力骤降。服务器从CPU 100%恢复到正常水平,网站恢复正常访问。
攻击持续了几天,但网站再也没挂过。运维说:“Nginx挡了99%的恶意请求,我们只需要偶尔看一眼日志。”
最后一句
CC攻击不是大网站的专利。小网站更容易被打,因为攻击成本低,你的服务器扛不住。Nginx限流是性价比最高的防御手段。不需要装额外软件,不需要改代码,几行配置就能让你的服务器在攻击中活下来。
限流不是让你永远不怕打,而是让你被打的时候,还有机会喘口气,还有时间去看日志、封IP、调策略。
去检查一下你的Nginx配置,该加限流的地方加上。真要被打的时候,你会感谢今天这几行配置。




