tcp服务上层做nginx四层tcp代理,结果TcpConnection没办法透过代理取到客户端的真实IP了

cqqjj1029

我是用Webman做的,其实Workerman也是同样的道理。

服务端:

config/process.php

<?php

return [
    'node_center' => [
        // 对应的服务类
        'handler' => process\NodeCenter::class,
        // 监听的协议 ip 及端口 (可选)
        'listen'  => 'tcp://0.0.0.0:4608',
        // 进程数 (可选,默认1)
        'count' => 1,
        // 进程运行用户 (可选,默认当前用户)
        'user' => '',
        // 进程运行用户组 (可选,默认当前用户组)
        'group' => '',
        // 当前进程是否支持reload (可选,默认true)
        'reloadable' => false,
        // 是否开启reusePort (可选,此选项需要php>=7.0,默认为true)
        'reusePort' => false,   // 异步任务的reusePort要设置为false,让任务自动分配到空闲进程中
        // transport (可选,当需要开启ssl时设置为ssl,默认为tcp)
        'transport' => 'tcp',
        // context (可选,当transport为是ssl时,需要传递证书路径)
        'context' => [],
        // 进程类构造函数参数,这里为 process\Pusher::class 类的构造函数参数 (可选)
        'constructor' => [],
    ],
];

process/NodeCenter.php

<?php

namespace process;

use Workerman\Connection\TcpConnection;
use Workerman\Worker;

class NodeCenter
{    
    public function onWorkerStart(Worker $worker)
    {

    }

    public function onConnect(TcpConnection $connection)
    {
        $ip = $connection->getRemoteIp();
        var_dump($ip);  // 得到的是nginx的ip
        var_dump($_SERVER);
    }

    public function onMessage(TcpConnection $connection, $data)
    {

    }

    public function onClose(TcpConnection $connection)
    {

    }

}

nginx做tcp代理的配置(nginx的ip是192.168.1.100)

upstream callserver-center {
    server 192.168.1.101:4608;
}

server {
    listen 24608;
    proxy_pass callserver-center;
}

客户端(伪代码):

$url = "tcp://192.168.1.100:24608";
$con = new AsyncTcpConnection($url);
$con->onConnect = function ($connection) {
    $data = [
        'command' => 'register',
        'handler' => env('NODE_HANDLER', 1000),
    ];
    $connection->send(json_encode($data));
};
$con->onClose = function ($connection) {
    $connection->reConnect(5);
};
$con->onError = function ($connection) {
    $connection->reConnect(5);
};
$con->connect();

以上配置做好后,当客户端启动后,可以正常连接到服务端,但是服务端$ip = $connection->getRemoteIp();得到的是nginx的192.168.1.100,而在var_dump($_SERVER);中完全没有任何与IP有关的信息。

参照https://www.workerman.net/doc/workerman/faq/get-real-ip-from-proxy.html
试着做proxy_set_header X-Real-IP $remote_addr;配置,但是在nginx的stream段做tcp代理时不支持proxy_set_header配置,把我难住了。

我知道这是nginx的问题而不是workerman的问题,但是我确实找不到相关资料去搞定,所以在社区求助。

1136 2 1
2个回答

nitron
server {
    listen 24608 proxy_protocol;
    proxy_pass callserver-center;
    proxy_protocol    on;
    set_real_ip_from  $proxy_protocol_addr;
}
  • cqqjj1029 2022-09-27

    nginx: [emerg] "set_real_ip_from" directive is not allowed here in /www/server/panel/vhost/nginx/tcp/center.conf:9
    nginx: configuration file /www/server/nginx/conf/nginx.conf test failed

  • nitron 2022-09-27

    我看你既然说了"四层tcp代理", 就默认你安装了stream_module和stream_realip_module,看来是没有
    重新编译nginx吧,带上--with-stream --with-stream_realip_module进行编译

  • cqqjj1029 2022-09-27

    刚看到了,--with-stream_realip_module是这个模块确实没装,我试一下,谢谢

  • cqqjj1029 2022-09-27

    [emerg] host not found in set_real_ip_from "$proxy_protocol_addr"

  • nitron 2022-09-27

    Try this

    stream {
        server {
            listen   24608 ;
            proxy_pass  192.168.1.101:4608;
            proxy_protocol on;
        }
    }
xiuwang

tcp代理无法透传ip。http可以是因为nginx会在http头部加一个X-Real-IP的header。
tcp是更底层的传输层协议,没办法透传

  • 暂无评论
年代过于久远,无法发表回答
🔝