必须用ngx_http_limit_conn_module,且limit_conn_zone和limit_conn缺一不可;前者定义共享内存区(须在http块),后者启用限制规则,单独写limit_conn无效。

直接限制单个 IP 并发连接数,必须用 ngx_http_limit_conn_module,且 limit_conn_zone 和 limit_conn 缺一不可;漏掉任意一个,配置就完全不生效。
为什么 limit_conn 单独写在 location 里没用
因为 limit_conn 是“执行指令”,它只负责启用某条限制规则;真正存储连接计数、识别客户端 IP 的逻辑,全靠 limit_conn_zone 提供。这个 zone 必须定义在 http 块里,否则 Nginx 启动时会报错:unknown limit_conn_zone "xxx"。
-
limit_conn_zone $binary_remote_addr zone=perip:10m—— 这行必须放在http{}最外层,perip是 zone 名,后面limit_conn要引用它 -
$binary_remote_addr比$remote_addr更省内存,推荐始终使用前者 -
10m不是随便写的:1M 约存 16000 个 IP 记录,10M 可存约 16 万 IP;如果业务有几十万活跃用户且要长期限流,建议调到20m或更高 - 如果用了 CDN 或反向代理(比如 Cloudflare),
$binary_remote_addr拿到的是 CDN 节点 IP,不是真实用户 IP;此时得配合real_ip_header X-Forwarded-For和set_real_ip_from修正
limit_conn perip 5 到底限制什么
这行写在 server 或 location 块里,表示“对当前作用域内所有请求,每个客户端 IP 最多维持 5 个并发 TCP 连接”。注意几个关键点:
- 它限制的是“已建立但尚未关闭的连接”,不是请求数;HTTP/1.1 keepalive、WebSocket、长轮询都会被计入
- 如果用户开了 6 个浏览器标签页同时访问 /api,第 6 个连接会被直接拒绝,Nginx 返回
503 Service Temporarily Unavailable - 它不区分 URL 路径;哪怕你只在
location /download里写这行,也只对该路径生效;想全局限制,就得写在server块顶层 - 和
limit_req不同,limit_conn没有burst或nodelay参数——超了就是超了,不排队也不缓冲
HTTP/2 下 limit_conn 容易失效的原因
HTTP/2 允许单个 TCP 连接复用多个请求流(stream)。这时候 limit_conn perip 5 只限制了 5 个 TCP 连接,但每个连接里可能跑上百个并发请求,实际压力远超预期。
- 验证是否启用 HTTP/2:检查
listen 443 ssl http2是否存在,或用curl -I --http2 https://yoursite.com看响应头是否有HTTP/2 200 - 补救办法:加一层
limit_req配合使用,例如limit_req zone=perip_rate burst=20 nodelay,从请求速率维度兜底 - 更彻底的方案:在
limit_conn_zone里换 key,比如用$binary_remote_addr$host区分不同域名,或结合$request_uri做路径级限制(需注意内存占用翻倍) - 别依赖
limit_conn防 CC 攻击:它对短连接洪水效果有限,真要防攻击,得上iptables或云厂商的 WAF 限连功能
真正难处理的不是配置写法,而是如何判断该限制多少——设太低伤正常用户,设太高起不到防护作用;建议先开 log_format 记录 $connections 和 $connection_requests,跑几天真实流量再定阈值。











