直接在承载 WebSocket 升级请求的 location 块中配置 limit_conn 即可限制单 IP 并发连接数,因其本质是 HTTP Upgrade 后的长连接,Nginx 将每个活跃 WebSocket TCP 连接计入统计;必须作用于最终处理升级逻辑的 location(如 /ws/),不可置于 server 或 upstream 中,并需配合 real_ip_module 还原真实 IP、limit_req 防高频重连及 limit_conn_status 429 显式反馈。

直接在承载 WebSocket 升级请求的 location 块中配置 limit_conn,就能限制单个 IP 的并发 WebSocket 连接数。关键不是“WebSocket 特殊”,而是它本质是 HTTP Upgrade 后维持的长连接——Nginx 把每个活跃的 WebSocket TCP 连接计入 limit_conn 的统计。
必须作用于正确的 location 块
WebSocket 连接建立始于一个普通 HTTP 请求(带 Upgrade: websocket 头),Nginx 必须在该请求被路由到后端前就完成限流判断。所以限制只能加在最终处理升级逻辑的 location 里,不能放在 upstream 或顶层 server 中无效位置。
- 正确写法(假设路径为
/ws/):
location /ws/ {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
limit_conn perip 3;
}
- 如果把
limit_conn perip 3写在location /或server级别,可能对静态资源、API 等也生效,误伤正常流量; - 若后端是多个 WebSocket 服务(如
/chat/ws和/notify/ws),建议分别为它们定义独立 zone,避免共用计数器。
代理环境要识别真实客户端 IP
如果 Nginx 前有 CDN、WAF 或 SLB,$binary_remote_addr 拿到的是中间节点 IP。此时需启用 http_realip_module 并配置可信上游:
- 确认 Nginx 编译时含
--with-http_realip_module; - 在
http块中添加:
set_real_ip_from 192.0.2.0/24;
real_ip_header X-Forwarded-For;
limit_conn_zone $realip_remote_addr zone=ws_perip:1m; - 然后在
location /ws/中用limit_conn ws_perip 3; - 不推荐手动解析
$http_x_forwarded_for—— 头可伪造,且需额外做空格截取和合法性校验。
配合其他策略提升防护效果
单纯靠 limit_conn 在 HTTP/2 或 NAT 场景下可能不够准:一个 TCP 连接可承载上百个 WebSocket stream,而 limit_conn 只计连接数。建议组合使用:
-
加
limit_req控速率:防止单 IP 频繁发起新连接(比如反复断连重连),例如:
limit_req zone=ws_rate burst=5 nodelay; -
加
limit_rate控单连接带宽:避免某个 WebSocket 连接持续发送大消息拖垮带宽,例如:
limit_rate 100k; -
显式设置拒绝行为:加
limit_conn_status 429返回标准限流状态码,加limit_conn_log_level error让超限日志可查。
注意内存与 zone 规划
limit_conn_zone 必须定义在 http 块顶层,大小要预估够用:
- 1MB zone 约存 1.6 万个独立 IP 的连接状态;
- 若业务预期最多 5000 个活跃 WebSocket 客户端,设
zone=ws_perip:1m足够; - 内存不足时 Nginx 不报错,但会静默丢弃新连接计数,导致限流失效 —— 查
error.log是否出现limit_conn: cannot add connection是重要排查点。


















