Nginx的limit_req模块通过limit_req_zone定义限流规则、limit_req启用策略,结合burst和nodelay实现动态频率控制,可有效防御CC攻击;需记录状态、自定义429错误码,并避免在if中使用。

用 Nginx 的 limit_req 模块做动态频率控制,是防御 CC 攻击最直接、低开销的方式。它不依赖外部组件,所有逻辑在接入层完成,既能快速拦截高频恶意请求,又不会明显影响真实用户访问。
核心配置必须分两步走
limit_req 不能单独生效,必须配合 limit_req_zone 使用:
-
limit_req_zone 写在
http块里,定义“按什么限、存多久、多快放行”。例如:limit_req_zone $binary_remote_addr zone=ip_limit:10m rate=5r/s;
表示按客户端 IP 限流,分配 10MB 共享内存(约支持 16 万个 IP),平均每秒只放行 5 个请求。 -
limit_req 写在
server或location块里,启用规则并控制突发行为。例如:limit_req zone=ip_limit burst=10 nodelay;
表示允许最多 10 个请求排队,超量立即拒绝(不延迟处理)。
不同场景推荐的限流粒度
单一维度容易被绕过,应结合业务敏感度选择匹配的 key:
-
按 IP 限流:适合防护登录、注册、短信发送等入口,防止暴力尝试。
配置示例:limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s; -
按 URI 限流:保护高负载接口,比如搜索、导出、数据聚合类路径。
配置示例:limit_req_zone $uri zone=api_limit:10m rate=3r/s; -
IP+URI 组合限流:精准打击“同一 IP 刷多个接口”的行为,内存占用略高但更抗绕过。
配置示例:limit_req_zone "$binary_remote_addr$uri" zone=ipuri:10m rate=2r/s;
burst 和 nodelay 的真实作用
这两个参数常被误解,直接影响防护效果和用户体验:
-
burst 不是并发数上限,而是漏桶能临时容纳的“额外请求数”。设为 0 时,所有超速请求立刻返回 503;设为 20 并配
nodelay,等于允许瞬时 20 个请求打进来,但后续仍受 rate 约束。 - nodelay 决定是否排队:不加时,Nginx 尝试匀速放出 burst 内的请求(可能造成延迟);加上后,burst 内请求全在当前秒内处理,超量则直接拒绝。对防 CC 更实用。
- 建议组合使用:
burst=15 nodelay,既容许合理波动,又避免攻击者利用排队机制耗尽资源。
必须配套的关键动作
光配限流不够,还需可观测、可响应:
-
记录限流状态:在 log_format 中加入
$limit_req_status,值为passed/rejected/delayed,方便识别攻击源或误伤。 -
自定义错误码:用
limit_req_status 429;替代默认的 503,更符合语义,也便于前端做友好提示。 -
避免写在 if 块中:Nginx 官方明确不支持
limit_req出现在if内,会导致配置加载失败或策略失效。 - 配合其它手段:limit_req 对伪造 IP 效果有限,建议叠加 geoip 过滤已知代理段、或前置 CDN/WAF 做初步清洗。











