limit_conn_zone 通过在 http 块定义 $binary_remote_addr 为 key 的共享内存区(如 zone=perip:10m),再于 server 或 location 中用 limit_conn perip n 限制单 ip 并发连接数,适用于 websocket/http/2/keep-alive 场景;代理环境需配合 realip_module 将 key 改为 $realip_remote_addr。

用 limit_conn_zone 控制单用户最大并发连接数,核心是两步:先在 http 块里定义共享内存区域,再在 server 或 location 中启用限制规则。它不是限制请求数,而是统计每个 IP 当前已建立、尚未关闭的 TCP 连接数——这对 WebSocket、HTTP/2、Keep-Alive 场景特别关键。
必须在 http 块定义 zone,且 key 要用 $binary_remote_addr
这是整个机制的前提,写错位置或选错变量都会失效:
- 只能放在
http{}最外层,不能嵌套进server或upstream,否则启动报错:unknown limit_conn_zone - 必须用
$binary_remote_addr作 key:IPv4 固定 4 字节,IPv6 固定 16 字节,省内存、不崩溃;$remote_addr是点分十进制字符串,长度不固定,会导致统计异常甚至 worker 进程退出 - zone 大小按真实 IP 数预估:10m ≈ 支持约 16 万个独立 IP;若后端有几十万活跃用户,建议设为 20m 或更高
- 示例配置:
limit_conn_zone $binary_remote_addr zone=perip:10m;
在 server 或 location 中启用 limit_conn
定义 zone 只是建好“计数本”,真正起作用靠这一步:
- 放在
server块开头(紧贴listen和server_name后),则全站生效;放在某个location /api/内,则只限制该路径 -
limit_conn perip 8;表示每个 IP 最多维持 8 个并发连接;数值要结合业务定:普通网站 8–16,AJAX 密集页可到 32,纯 API 接口建议搭配limit_req一起用 - 注意:它统计的是连接数,不是请求数。一个 HTTP/1.1 Keep-Alive 连接发 10 次请求,只算 1 个连接;一个 WebSocket 连接始终占 1 个名额
代理环境下必须还原真实 IP
如果前面有 CDN、WAF 或 SLB,$binary_remote_addr 拿到的是代理节点 IP,所有用户会被当成同一个 IP 限流:
- 确认 Nginx 已启用
http_realip_module(编译时加--with-http-realip-module) - 用
set_real_ip_from明确声明可信上游网段(如 Cloudflare 的 IP 段) - 设置
real_ip_header X-Forwarded-For;或X-Real-IP(依上游实际传的头而定) - 把 zone 的 key 改为
$realip_remote_addr:limit_conn_zone $realip_remote_addr zone=perip:10m;
增强防护与可观测性
单靠 limit_conn 不够,建议组合使用提升效果:
- 加
limit_conn_log_level error;:只在真超限时记日志,避免刷屏 - 设
limit_conn_status 429;:返回标准 429 状态码,方便前端识别并退避重试 - 搭配
limit_req防短连接攻击:比如limit_req zone=perip_rate burst=10 nodelay; - 必要时加
limit_rate 512k;防止单连接吃满带宽,尤其对下载或大响应体路径











