必须用ngx_http_limit_conn_module,且limit_conn_zone和limit_conn缺一不可:前者定义共享内存区记录ip连接状态,后者启用规则;zone须在http块定义,$binary_remote_addr更省内存,10m约存16万ip,限制的是已建立未关闭的tcp连接数,不支持burst/nodelay,超限默认返回503。

直接限制单个 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更省内存(4 字节 vs 字符串),推荐始终使用前者 -
10m不是随便写的:1M 约存 16000 个 IP 记录,10M 可存约 16 万 IP;若业务有几十万活跃用户,建议调到20m或更高
真实场景下 limit_conn perip 3 到底限制什么
它限制的是“已建立但尚未关闭”的 TCP 连接数,不是请求数,也不是每秒多少次。具体来说,只统计满足以下三个条件的连接:
- 已完成三次握手
- 已完整读取 HTTP 请求头(能解析出 method、path、host)
- 响应尚未返回完毕(或正在发送中)
这意味着:
- HTTP/1.1 keepalive、WebSocket、长轮询都会被计入
- 静态文件下载(尤其是大文件)容易触发限制,因为连接长期处于“未关闭”状态
- 用户开 4 个标签页同时访问
/api,第 4 个连接可能被直接拒绝,Nginx 返回503 Service Temporarily Unavailable - 它不区分路径——如果你只在
location /download里写这行,就只对该路径生效;想全局限制,得写在server块顶层
CDN、HTTP/2 和绕过风险怎么处理
如果用了 CDN(如 Cloudflare)或反向代理,$binary_remote_addr 拿到的是节点 IP,不是真实用户 IP。此时必须配合 real_ip_header X-Forwarded-For 和 set_real_ip_from 修正,否则限流完全失效。
- HTTP/2 下
limit_conn容易形同虚设:单个 TCP 连接可复用上百个请求流(stream),limit_conn perip 5只挡 5 个连接,实际并发压力远超预期 - 验证是否启用 HTTP/2:
curl -I --http2 https://yoursite.com看响应头是否有HTTP/2 200,或检查配置中是否有listen 443 ssl http2 - 补救办法:加一层
limit_req配合使用,例如limit_req zone=perip_rate burst=20 nodelay,从请求速率维度兜底 -
limit_conn没有burst或nodelay参数——超了就是超了,不排队也不缓冲,这点和limit_req本质不同
最容易被忽略的是:限流本身不记录日志,除非显式配置 limit_conn_log_level warn,否则你根本不知道谁被拦了;另外,limit_conn_status 429 虽然语义更清晰,但它只对 limit_req 生效,limit_conn 超限默认返回 503,无法修改为 429 ——这点常被误配。











