直接用 limit_req 模块拦截高频非法请求需配对使用:先在 http 块定义 zone=badreq:10m rate=10r/s 规则,再在 server 或 location 中用 limit_req zone=badreq burst=20 nodelay 启用;键推荐 $binary_remote_addr,CDN 场景需改用 $http_x_forwarded_for 并校验;须压测验证,日志查 limiting requests 或 zone is full;进阶可换键、改状态码为 429、调低日志级别。

直接用 limit_req 模块就能拦住高频非法请求,但必须配对使用两个指令:先定义规则,再启用限制。单独写其中任何一个都没用。
第一步:在 http 块里定义限流规则
这是硬性要求,只能写在 http{...} 里,写到 server 或 location 会启动失败。
- 推荐用
$binary_remote_addr作键——比$remote_addr更省内存、哈希更稳,尤其对 IPv6 友好 -
zone=badreq:10m表示建一个叫badreq的共享内存区,10MB 大小;按经验,1MB 约存 1.6 万个 IP 状态,高并发场景建议调大 -
rate=10r/s是固定值,不能带变量(比如rate=$rate_var是非法的),支持r/s或r/m单位
第二步:在 server 或 location 中启用限制
只定义不启用,等于没配。启用位置决定作用范围:整个站点写在 server 块,某接口写在 location /api/ 里。
-
limit_req zone=badreq burst=20 nodelay;是常用组合:允许最多积压 20 个请求,超了立刻返回 503 - 去掉
nodelay时,Nginx 会把burst内的请求匀速放出,可能造成客户端卡顿 - 如果前端有 CDN 或代理(如 Cloudflare),
$binary_remote_addr拿到的是代理 IP,得改用$http_x_forwarded_for并做可信头校验
验证是否真生效,不能只看 reload 成功
配置重载后必须动手测,否则容易误判。
- 用
ab -n 50 -c 10 http://your.site/快速压测,观察是否出现大量 503 响应 - 实时盯日志:
tail -f /var/log/nginx/error.log,触发限流时会出现limiting requests, excess: X.XXX by zone "badreq"或rejected字样 - 注意:共享内存区满(比如 10MB 不够存所有活跃 IP)会导致新请求绕过限制,错误日志里会有
zone is full提示
进阶建议:区分合法与非法流量
单纯按 IP 限流容易误伤,可叠加判断提升精准度。
- 对已登录用户,可用
$cookie_session_id或$arg_token替代 IP 作为限流键,避免同一出口多个用户被连坐 - 配合
limit_req_status 429把默认 503 改成标准的 “Too Many Requests”,方便前端识别处理 - 加
limit_req_log_level warn把限流日志降到 warn 级别,减少 error 日志噪音


















