nginx可通过limit_conn按客户端ip限制websocket并发连接数,配合set_real_ip_from和map提取真实ip,并用limit_req限制握手请求频率,实现轻量高效防护。

Nginx 本身不感知 WebSocket 协议,但每个 WebSocket 连接对应一个长生命周期的 TCP 连接,因此可直接用 limit_conn 模块限制并发连接数——这是最轻量、最有效的前置防护手段。
按客户端 IP 限制并发连接数
这是最常用且防攻击效果最好的方式。需在 http 块中定义共享内存区域,并在 WebSocket 路径的 location 块中启用:
-
在
http块顶部添加:limit_conn_zone $binary_remote_addr zone=ws_perip:10m;
$binary_remote_addr比$remote_addr更省内存;10m可支持约 16 万个独立 IP 的状态记录。 -
在
location /ws/(或你实际的 WebSocket 路径)中加入:limit_conn ws_perip 10;
表示单个客户端 IP 最多维持 10 个并发 WebSocket 连接。
处理代理后的真实 IP(如经 Cloudflare 或负载均衡器)
若用户流量经过 CDN 或反向代理,需先提取真实 IP 再限流:
-
配置可信代理段和头字段:
set_real_ip_from 103.21.244.0/22; set_real_ip_from 173.245.48.0/20; # ……其他 Cloudflare IP 段 real_ip_header CF-Connecting-IP; # 或 X-Forwarded-For
-
用
map提取真实 IP 并定义 zone:map $http_x_forwarded_for $client_real_ip { ~^(?<ip>\d+\.\d+\.\d+\.\d+)$ $ip; default $remote_addr; } limit_conn_zone $client_real_ip zone=ws_realip:10m;</ip> -
然后在 location 中使用:
limit_conn ws_realip 5;
配合握手请求限频,防重连风暴
高频建连(如断网后疯狂重试)会压垮握手阶段,可用 limit_req 控制每分钟握手请求数:
-
定义限速区域(按 IP):
limit_req_zone $binary_remote_addr zone=ws_handshake:10m rate=3r/m;
-
在同一 location 中启用:
limit_req zone=ws_handshake burst=2 nodelay;
注意:limit_req 作用于 HTTP 握手请求(即带 Upgrade: websocket 的 GET),不是已建立的长连接。
关键提醒
-
limit_conn统计的是当前 ESTABLISHED 状态的连接数,连接关闭后自动释放,无需手动清理 - 不要与
limit_req混用同一 zone;二者逻辑不同,应分开定义 - 所有限流指令必须放在最终
proxy_pass所在的location块内,不能写在upstream或外层server中 - 若后端有鉴权(如 token 校验),建议在 Nginx 层做连接限流,避免无效请求穿透到应用
不复杂但容易忽略











