nginx限流需分两步:先在http块用limit_req_zone定义规则(如按ip或uri+ip),再在location块用limit_req精准启用并配置burst、nodelay、reject等参数实现刚性拦截,同时避开缓冲、burst滥用、忽略ua等常见陷阱。

直接在 location 块里加 limit_req 指令就能生效,但关键不是“加了”,而是加得准、判得清、拦得硬——尤其针对恶意高频刷接口的场景。
先在 http 块定义限流规则
限流必须分两步:先定义“怎么记”,再说明“在哪用”。limit_req_zone 必须放在 http{} 块里,不能写在 location 内:
-
按 IP 限流最常用:
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=2r/s;(每秒最多 2 个请求) -
按 URI + IP 组合更精细:
limit_req_zone "$binary_remote_addr$request_uri" zone=uri_ip:10m rate=1r/s;(比如专防/login被爆破) - 内存大小要够用:10m 约存 15–30 万个 IP 状态;若日均攻击 IP 超 5 万,建议调到 20m
在 location 中精准启用并刚性拦截
只对高危路径启用,避免误伤静态资源或首页。同时确保返回明确拒绝,不给爬虫试探机会:
-
绑定到具体接口路径:例如
location ^~ /api/v1/order/ { ... }或location ~ ^/login$ { ... } -
显式拒绝,不排队:用
limit_req zone=api_limit burst=1 nodelay;—— burst=1 表示最多放行 1 个突发请求,其余立即 503 -
强制返回 503(Nginx ≥1.23):
limit_req zone=api_limit reject=503;,旧版本改用limit_req_status 503; -
禁用默认延迟行为:去掉
nodelay就会排队等待,爬虫可能趁机重试;加上它才真正“秒拒”
避开常见配置陷阱
很多限流没效果,其实是踩了这几个坑:
-
没配 proxy_buffering off(反向代理时):后端响应慢会导致 Nginx 缓存请求,让限流失效;建议加
proxy_buffering off; -
全局滥用 burst:设
burst=50等于开了后门;高频刷接口建议burst=0或burst=1 -
忽略真实攻击特征:单纯限 IP 不够,可结合变量强化识别,例如:
map $http_user_agent $is_bad {<br> ~*python-requests 1;<br> ~*curl 1;<br> default 0;<br> }<br> limit_req_zone $is_bad zone=bad_ua:1m rate=0r/s;
再在 location 中叠加limit_req zone=bad_ua;,直接封死已知工具
加白名单避免误伤运维和可信来源
内部 IP、监控探针、CDN 回源等不该被限,用 geo + map 动态绕过:
- 定义信任网段:
geo $whitelist { default 0; 10.0.0.0/8 1; 172.16.0.0/12 1; } - 构造空 key:
map $whitelist $limit_key { 1 ""; 0 $binary_remote_addr; } - 限流区基于该 key:
limit_req_zone $limit_key zone=smart_limit:10m rate=3r/s; - location 中直接引用:
limit_req zone=smart_limit burst=2 nodelay;











