答案:通过Nginx配置传递真实IP并在Swoole中读取X-Real-IP头部可获取客户端真实IP。具体步骤为:1. Nginx配置proxy_set_header X-Real-IP $remote_addr,正确转发WebSocket请求;2. Swoole在on('open')中通过$request->header['x-real-ip']获取IP;3. 为防伪造,应限制Swoole仅监听内网并确保Nginx处于可信环境。

在使用 Swoole 配合 Nginx 做 WebSocket 服务时,直接通过 Swoole 获取客户端 IP 会得到 Nginx 的 IP(比如 127.0.0.1),而不是真实用户 IP。这是因为 Nginx 作为反向代理转发了连接。要获取真实客户端 IP,需要 Nginx 正确传递来源地址,并在 Swoole 中读取对应信息。
1. 配置 Nginx 传递真实 IP
Nginx 必须设置 proxy_set_header 将客户端真实 IP 写入请求头,常用的是 X-Real-IP 或 X-Forwarded-For。同时,在代理 WebSocket 时要正确升级协议。
示例 Nginx 配置:
location /ws/ {
proxy_pass http://127.0.0.1:9501; # 转发到 Swoole 服务
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
}
其中 $remote_addr 是 Nginx 拿到的真实客户端 IP,X-Real-IP 是最干净的字段,推荐使用。
2. 在 Swoole 中获取真实 IP
Swoole 接收到 WebSocket 握手请求时,可以通过 request()->header 获取 Nginx 传来的头部信息。不能直接用 $server->connection_info() 的 remote_ip,因为那是与 Nginx 的连接 IP。
PHP 示例代码:
$server = new Swoole\WebSocket\Server("0.0.0.0", 9501);
$server->on('open', function ($server, $req) {
$realIp = $req->header['x-real-ip'] ?? $req->server['remote_addr'];
echo "Client connected from real IP: {$realIp}\n";
});
$server->on('message', function ($server, $frame) {
$server->push($frame->fd, "Hello, {$frame->data}");
});
$server->start();
这里优先从 x-real-ip 头部取值,如果不存在再回退到连接 IP(适用于直连调试)。
3. 安全建议:防止伪造 IP
用户可能伪造 X-Real-IP 请求头,因此只应信任来自 Nginx 的代理。确保:
- Swoole 服务监听 127.0.0.1 或内网 IP,不对外暴露
- Nginx 位于可信网络或做了访问控制
- 生产环境避免使用未验证的 X-Forwarded-For,它更容易被篡改
基本上就这些。只要 Nginx 正确传头,Swoole 按 header 取值,就能拿到真实 IP。










