nginx 的 limit_conn 模块可直接实现基于每个 ip 当前活跃 tcp 连接数的限流,需在 http 块顶层定义共享内存区(如 zone=perip:10m),用 $binary_remote_addr 或代理环境下的 $realip_remote_addr 作键,再在 server 或 location 中引用并设定每 ip 最大并发连接数(建议 3~10),超限返回 503 或 429,并配合 realip 模块、日志级别、限速及 keepalive 优化提升实用性与可观测性。

直接用 Nginx 的 limit_conn 模块就能实现,不依赖额外组件,生效快、开销低,核心是控制每个 IP 当前活跃的 TCP 连接数(含 keepalive、HTTP/2 流),不是请求数。
在 http 块中定义共享内存区
必须放在 http{} 最外层,不能写在 server 或 location 内:
- 用
$binary_remote_addr作键:IPv4 固定占 4 字节,IPv6 固定 16 字节,比$remote_addr更省内存、抗哈希冲突 -
zone=perip:10m表示分配 10MB 共享内存,约可存 16 万~32 万个独立 IP 的连接状态 - 如果日志出现
limit_conn: cannot add connection,说明内存不足,可调大为20m或50m
在 server 或 location 中启用限制
引用上面定义的 zone 名,并设每个 IP 最大并发连接数:
- 放在
server块里:作用于整个虚拟主机,适合全站防护 - 放在
location /api/下:只限制该路径,不影响静态资源或轻量接口 - 数值建议设 3~10:设 1 容易误伤多标签页用户;设 50 就基本失去防护意义
- 超出立即返回 503,可加
limit_conn_status 429改为标准限流状态码
代理环境下要还原真实客户端 IP
如果 Nginx 前有 CDN、WAF 或负载均衡,$binary_remote_addr 默认是代理地址,会导致限流失效或误伤:
- 确保已加载
http_realip_module(编译默认包含) - 配置可信上游网段:
set_real_ip_from 10.0.0.0/8;、set_real_ip_from 192.168.0.0/16; - 指定头字段:
real_ip_header X-Forwarded-For;,并开启递归解析:real_ip_recursive on; - 之后改用
$realip_remote_addr定义 zone,例如:limit_conn_zone $realip_remote_addr zone=perip:10m;
增强实用性与可观测性
让防护更可控、问题更容易排查:
-
limit_conn_log_level error;:超限时只记 error 级别日志,避免刷屏 -
limit_rate 200k;:对已放行的连接限速,防止单连接耗尽带宽 -
keepalive_timeout 15;:及时释放空闲长连接,避免无效占用配额 - 搭配
limit_req使用:连接层 + 请求层双保险,比如防爬虫时同时控并发和 QPS











