nginx的limit_conn_zone限流需三步:一是在http块用$binary_remote_addr定义共享内存区(如zone=perip:10m);二在server或location中用limit_conn perip n启用,以嵌套层级中最内层的最小值为准;三在代理环境下改用$realip_remote_addr并配置real_ip_module。

直接在 http 块里定义 limit_conn_zone,再在 server 或 location 里用 limit_conn 引用它,就能生效。不加 realip 配置时,默认用的是代理节点 IP,不是真实用户 IP——这点最容易出错。
必须在 http 块中定义 zone,不能写在 server 里
limit_conn_zone 只能在 http 上下文中使用,写在 server 或 location 里会报错:unknown directive "limit_conn_zone"。
-
$binary_remote_addr是推荐的 key:比$remote_addr更省内存(IPv4 固定 4 字节),且不受X-Forwarded-For伪造影响 -
zone=perip:10m表示分配 10MB 共享内存,约支持 16 万~32 万个独立 IP 的连接计数;如果日志出现limit_conn: cannot add connection,说明内存溢出,需增大 size(如改20m) - zone 名称(如
perip)必须全局唯一,后续limit_conn指令靠它匹配
正确写法:
http {
limit_conn_zone $binary_remote_addr zone=perip:10m;
}
在 location 中启用 limit_conn 时,注意作用域和覆盖规则
limit_conn 可出现在 http、server、location 任意一级,但实际生效值取**嵌套层级中最内层的最小数值**。
- 若
server设了limit_conn perip 10,而location /api/v1/download/里又设了limit_conn perip 3,则该路径实际生效的是 3 - 只对高能耗路径启用(如
/download/、/ws/、/login),别放在location /下,否则静态资源也受限制,反而增加 CPU 开销 - HTTP/2 下一个 TCP 连接可承载多个 stream,
limit_conn仍按连接计,不是按 stream 计——这点和直觉相反,但符合设计本意
示例(仅限下载接口):
location ^~ /api/v1/download/ {
limit_conn perip 3;
limit_conn_status 429;
limit_conn_log_level error;
proxy_pass http://backend;
}
有 CDN、SLB 或 Nginx 前置代理时,必须还原真实 IP
否则所有请求的 $binary_remote_addr 都是上一跳代理的地址(比如 10.0.0.1),导致所有用户被当成同一个 IP 限流,或完全失效。
- 确认已编译或加载
http_realip_module(常见发行版默认包含) - 在
http或server块中配置可信上游:set_real_ip_from 192.168.1.0/24;(填你实际的代理网段) - 指定 header:
real_ip_header X-Forwarded-For;,并开启递归解析:real_ip_recursive on; - 之后应改用
$realip_remote_addr作为 zone key,而不是$binary_remote_addr;或者保持用$binary_remote_addr,但确保realip已生效(此时$remote_addr已为真实 IP)
验证方式:在 log_format 中加入 $remote_addr 和 $http_x_forwarded_for,对比日志输出是否一致。
limit_conn 不是 limit_req,别混淆连接与请求
limit_conn 控制的是当前活跃的 TCP 连接数,不是每秒请求数。这对大文件下载、WebSocket、长轮询等场景更合理;但对防暴力登录、爬虫刷小接口,单靠它不够。
- 一个浏览器标签页可能复用一个 keepalive 连接发多个请求,
limit_conn perip 3不会拦它 - 恶意脚本开 10 个并发连接持续下载,
limit_conn能立刻堵住;但它发 100 个短连接请求,就得靠limit_req配合burst来控频 - 建议组合使用:
limit_conn perip 5;+limit_req zone=perip_req burst=10 nodelay;,二者正交,互不替代 -
limit_rate 200k;可以补位——放行的连接也别让它吃光带宽
真正容易被忽略的是:Nginx 默认拒绝返回 503 Service Temporarily Unavailable,但很多前端监控只认 429;加上 limit_conn_status 429; 才能被自动识别为限流事件。











