Nginx代理WebSocket时需配置透传真实IP并启用realip模块校验。需在location中设置X-Real-IP、X-Forwarded-For及WebSocket升级头;后端在握手阶段读取请求头;生产环境应配置set_real_ip_from和real_ip_header增强可信性。

在 Nginx 代理 WebSocket 时,客户端真实 IP 默认无法直接通过 $remote_addr 获取,因为连接经过了代理层,后端服务看到的是 Nginx 的 IP。要正确传递并提取真实 IP,需同时配置 Nginx 的请求头转发与后端服务的解析逻辑。
一、Nginx 配置:透传真实 IP 到后端
在对应 WebSocket 的 location 块中,必须设置以下关键头部,并启用 WebSocket 协议支持:
-
proxy_set_header X-Real-IP $remote_addr;—— 将直连客户端(即真实用户)IP 写入X-Real-IP头 -
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;—— 追加到原有X-Forwarded-For(若上游已设),保持多级代理链路可追溯 -
proxy_http_version 1.1;和proxy_set_header Upgrade $http_upgrade;—— 必须启用,否则 WebSocket 握手失败 -
proxy_set_header Connection "upgrade";—— 显式声明升级连接类型
示例配置片段:
location /ws/ {
proxy_pass http://backend_ws;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}二、后端服务:从 WebSocket 握手请求中读取 IP
WebSocket 连接建立时,浏览器发起的是一个 HTTP Upgrade 请求,此时所有 proxy_set_header 设置的自定义头都可用。后端需在 握手阶段(onOpen 或 upgrade handler) 解析请求头,而非连接建立后的消息帧中。
- Java(Spring WebSocket):用
HandshakeInterceptor获取request.getHeader("X-Real-IP") - Node.js(ws 库):在
verifyClient或upgrade事件中读取req.headers['x-real-ip'] - Python(FastAPI + websockets):通过
scope["headers"]提取x-real-ip字节 key
注意:X-Forwarded-For 可被伪造,若仅作日志或限流用途,建议优先信任 X-Real-IP;若需兼容多级代理,应结合 set_real_ip_from + real_ip_header 模块做可信源校验(见下一点)。
三、增强可信性:启用 realip 模块校验(推荐生产环境)
仅靠 proxy_set_header 不足以防范伪造。Nginx 自带 ngx_http_realip_module 可将可信代理的 X-Real-IP 或 X-Forwarded-For 自动覆盖 $remote_addr,使后端直接使用 $remote_addr 更安全。
- 在
http或server块中添加:
set_real_ip_from 192.168.0.0/16; # 替换为你的可信代理网段(如 SLB、WAF、前置 Nginx) set_real_ip_from 10.0.0.0/8; real_ip_header X-Real-IP; real_ip_recursive on;
启用后,Nginx 会把来自可信源的 X-Real-IP 值赋给 $remote_addr,后端可统一用该变量,无需再手动解析 header。
四、验证是否生效
最简单方式:在后端打印日志,同时输出 X-Real-IP 头和 $remote_addr(若启用了 realip 模块);也可临时在 Nginx access log 中加入:
log_format ws_log '$http_x_real_ip - $remote_addr [$time_local] "$request" $status'; access_log /var/log/nginx/ws_access.log ws_log;
触发一次 WebSocket 连接,检查日志中是否出现客户端真实 IP(如 203.123.45.67)而非 Nginx 本机地址。











