Jump to content

Reverse proxy pass websocket request with PHP in apache


Go to solution Solved by kicken,

Recommended Posts

I have a websocket server that I need to protect behind a PHP session and currently I'm unable because I can't make PHP to reverse proxy to the websocket server. Let's go to the details.

 

I have a NGINX server acting as general reverse proxy, that passes the request to the apache server that it's running with the PHP module. This apache-php server is the one that should check if the user has a valid session (no problem with that) and if it does redirect the request to the final websocket server, a x11VNC. If I remove the apache step and proxy pass NGINX directly to x11VNC it works perfectly, but once I want to add the session check, I get stuck.

 

Searching the internet I have been able to write the following code:

$vnc_request_headers = apache_request_headers();
$vnc_request_headers_simple_array = [];
foreach ($vnc_request_headers as $vnc_request_header => $value) {
    array_push($vnc_request_headers_simple_array, $vnc_request_header . ': ' . $value);
}

$options = [
    CURLOPT_HTTPHEADER     => $vnc_request_headers_simple_array,
    CURLOPT_RETURNTRANSFER => true,     // return web page
    CURLOPT_HEADER         => true,     // return headers
    CURLOPT_FOLLOWLOCATION => true,     // follow redirects
    CURLOPT_ENCODING       => "",       // handle all encodings
    CURLOPT_AUTOREFERER    => true,     // set referer on redirect
    CURLOPT_CONNECTTIMEOUT => 120,      // timeout on connect
    CURLOPT_TIMEOUT        => 120,      // timeout on response
    CURLOPT_MAXREDIRS      => 10,       // stop after 10 redirects
];

$ch = curl_init('http://192.168.100.13:5900');
curl_setopt_array($ch, $options);

$vnc_response_headers = [];
// this function is called by curl for each header received
curl_setopt($ch, CURLOPT_HEADERFUNCTION,
function($curl, $header) use (&$vnc_response_headers)
    {
        $len = strlen($header);
        $header = explode(':', $header, 2);
        if (count($header) < 2) // ignore invalid headers
          return $len;

        $vnc_response_headers[strtolower(trim($header[0]))][] = trim($header[1]);

        return $len;
    }
);

$vnc_response = curl_exec($ch);
$vnc_header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$vnc_httpCode = curl_getinfo($ch , CURLINFO_HTTP_CODE);
curl_close($ch);

$vnc_body = substr($vnc_response, $vnc_header_size);

http_response_code($vnc_httpCode);

foreach ($vnc_response_headers as $vnc_response_header => $array) {
    foreach($array as $vnc_response_header_value) {
        header($vnc_response_header . ": " . $vnc_response_header_value);
    }
}

echo $vnc_body;

 

This grabs the apache icomming headers and forward them to the proxied server, and then graps the proxied answer along with the response headers and code. Then sets the headers and the code and finally echoes the body. I have tested it and works perfectly with standard http(s) requests. The request headers reach the proxied server and the response headers reach the client browser.

 

But it doesn't work when working with websocket connections, curl gets stuck in curl_exec(). Maybe because websocket connections are never really closed until the data streamming it's closed from one party? I'm pretty lost because it's my first time working with websockets.

 

How to reverse proxy the websocket request, and all the following messages exchange that is going to take place between x11VNC and the client, with PHP?

 

Thanks for your time!

 

 

Héctor

Edited by H25E
2 hours ago, H25E said:

Maybe because websocket connections are never really closed until the data streamming it's closed from one party? I'm pretty lost because it's my first time working with websockets.

That's exactly the issue.  Websockets are a persistent and bi-directional connection, unlike your typical http requests.  This means they don't really work with your typical HTTP tools, you need something that can specifically deal with websockets.

As far as I know you can't really use PHP to deal with a websocket via apache, nor do I expect it to be a good idea even if you could.  What you'd typically do is essentially write your own websocket server in PHP that is run as it's own service, separate from apache or nginx.  You could then code your server to act as a proxy between the vnc server and the browser with whatever extra checks you want.

  • Solution

As an alternative to making your own proxy server (or finding one) you might be able to simply configure Nginx to authenticate the request for you by making a sub-request to your PHP script.  I don't use Nginx so not sure if that would work but it sounds promising.

 

2 hours ago, kicken said:

As an alternative to making your own proxy server (or finding one) you might be able to simply configure Nginx to authenticate the request for you by making a sub-request to your PHP script.  I don't use Nginx so not sure if that would work but it sounds promising.

 

Wow, that has been great!! Didn't know something like that existed!!

Works perfectly and probably with better performance, and barely without any extra code!!

 

Thank you so much!!

Edited by H25E
This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.