php ratchet websocket SSL connect?

46,145

Solution 1

If you are using Apache web server (2.4 or above), enable these modules in httpd.conf file :

  1. mod_proxy.so
  2. mod_proxy_wstunnel.so

Add this setting to your httpd.conf file

ProxyPass /wss2/ ws://ratchet.mydomain.org:8888/

Use this URL in your JavaScript call when you want a WSS connection:

var ws = new WebSocket("wss://ratchet.mydomain.org/wss2/NNN");

Restart Apache web server and make sure that your Ratchet worker (web socket connection) is open before applying the settings (telnet hostname port).

Solution 2

A few days ago I was looking for the answer of this question and I found this in the Github Ratchet issues: https://github.com/ratchetphp/Ratchet/issues/489

The last answer, answered by heidji, says this:

I only added this comment for newbies like me who need a quick instruction how to implement SSL: Via the ReactPHP docs you only need to construct the SecureServer mentioned in such manner:
$webSock = new React\Socket\Server('0.0.0.0:8443', $loop);
$webSock = new React\Socket\SecureServer($webSock, $loop, ['local_cert' => '/etc/ssl/key.pem', 'allow_self_signed' => true, 'verify_peer' => false]);
and then inject into the IoServer as mentioned by cboden above

So it seems that now there is a way to implement a secure websocket server with Ratchet without needing an HTTPS proxy.

Here you have the SecureServer class documentation: https://github.com/reactphp/socket#secureserver

Solution 3

The problem is that React (which Ratchet is built on) does not support direct SSL connections. See this issue.

There is a simple workaround. Use stunnel with a config like:

[websockets]
accept = 8443
connect = 8888

Stunnel will handle SSL traffic on port 8443 and port them to your websocket server.

Solution 4

I found this answer on Ratchet's google group by Chris Boden:

The best solution would be to use Nginx as your web server. Have Nginx listen on port 80 for incoming connections and have it handle your SSL. Nginx will forward incoming connections to PHP-FPM for your regular website and if it detects a connection is a WebSocket connection have it proxy to your running Ratchet application on a port of your choice. Your javascript could then connect via wss://mydomain.org

This is an alternative way to using stunnel if your application is going to be served using nginx.

Solution 5

If you're using Nginx, just write this in your SSL server block:

location /services/myservice {
    # switch off logging
    access_log off;

    # redirect all HTTP traffic to localhost
    proxy_pass http://localhost:1234;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    # WebSocket support (nginx 1.4)
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";

    # Path rewriting
    rewrite /services/myservice/(.*) /$1 break;
    proxy_redirect off;

    # timeout extension, possibly keep this short if using a ping strategy
    proxy_read_timeout 99999s;
}

This will upgrade any wss://yoursite.com/services/myservice call to a socket running on port 1234. Just make sure you remember not to leave port 1234 open to the world.

Share:
46,145
Viet Nguyen
Author by

Viet Nguyen

Nothing special.

Updated on March 28, 2021

Comments

  • Viet Nguyen
    Viet Nguyen about 3 years

    I have a ratchet chat server file

    use Ratchet\Server\IoServer;
    use Ratchet\WebSocket\WsServer;
    use MyAppChat\Chat;
    require dirname(__DIR__) . '/vendor/autoload.php';
    $server = IoServer::factory(
        new WsServer(
            new Chat()
        )
      , 26666
    );
    $server->run();
    

    I using Websocket to connect with ws and it works fine

    if ("WebSocket" in window) {
        var ws = new WebSocket("ws://ratchet.mydomain.org:8888");
        ws.onopen = function() {
            // Web Socket is connected. You can send data by send() method.
            ws.send("message to send");
        };
        ws.onmessage = function (evt) { 
            var received_msg = evt.data;
        };
        ws.onclose = function() { 
            // websocket is closed. 
        };
    } else {
      // the browser doesn't support WebSocket.
    }
    

    I want secure connection, so I try to connect with SSL but is not work.

    if ("WebSocket" in window) {
        var ws = new WebSocket("wss://ratchet.mydomain.org:8888");
        ws.onopen = function() {
            // Web Socket is connected. You can send data by send() method.
            ws.send("message to send");
        };
        ws.onmessage = function (evt) { 
            var received_msg = evt.data;
        };
        ws.onclose = function() { 
            // websocket is closed. 
        };
    } else {
      // the browser doesn't support WebSocket.
    }
    

    My question is how to connect websocket with SSL connection

    Any idea?

  • Viet Nguyen
    Viet Nguyen over 10 years
    Thanks for your answer, i done this work :D, now i will work with scapy in python for spoof source ip address but really hard work :( can you help me?
  • Songo
    Songo about 10 years
    @temuri yea I found a gist sometime ago with the configuration to make it work. Sadly I can't find it now
  • temuri
    temuri about 10 years
    argh... Is there stunnel config sample?
  • temuri
    temuri about 10 years
    @Songo Thank you! Unfortunately, I am not an expert in nginx config. I am not sure how to alter my existing config. Here's my shot at it: gist.github.com/temuri416/9633097. What am I doing wrong?
  • temuri
    temuri about 10 years
  • Arun Poudel
    Arun Poudel over 9 years
    Not that nginx supports proxy_passing websocket, I will suggest using it. This way we can facilitate serving wss on port 443 hence not being blocked by most of corporate firewalls.
  • amcastror
    amcastror over 8 years
    Nice, this works, but a question: why the "/NNN" at the end? Thanks!
  • webcoder
    webcoder over 8 years
    Referring our next URL parameters (eg: /wss2/param1/param2...) which can be use by our system to identify the request purpose. You may remove it if not needed, but please note that you must have the same matching identity url parameter (in this case '/wss2/') so the server able to match/catch the request and forward it to custom domain/port.
  • mitchken
    mitchken about 8 years
    This does actually work on APache 2.4 with cboden/ratchet, thx a lot
  • Flo Schild
    Flo Schild over 7 years
    In what kind of vhost do those directives work? Which port do you need to listen to? Would it be possible to give a vhost example including HTTP and WS protocoles?
  • Joe Leonard
    Joe Leonard over 7 years
    Does this work for localhost? Is it just ProxyPass /wss2/ ws://ratchet.localhost:8888/ ??? How do I get this working properly on localhost? ws works great for Opera and Chrome, but wss for Firefox and others has been a significant hurdle.
  • Joe Leonard
    Joe Leonard over 7 years
    As a follow-up: I finally got this working on localhost for Chrome and Firefox using https, but in my case I had to use port 8080... I was confused about which port to use and this led to a lot of trial and error. Mostly error. This is what worked for me: var conn = new WebSocket('wss://localhost/wss2/'); ProxyPass /wss2/ ws://localhost:8080/ $server = IoServer::factory( new HttpServer( new WsServer( new Chat() ) ), 8080 );
  • Deepak M
    Deepak M almost 7 years
    By doing this, Will it affect the perfomance or cause any vulnerabilities ?
  • Mushfiqur Rahman
    Mushfiqur Rahman over 5 years
    Hi @RaisinBranCrunch would you please tell me then what will be final code then? I mean for this line of code var ws = new WebSocket("wss://ratchet.mydomain.org/wss2/NNN"); what would be the changes. Thanks
  • RaisinBranCrunch
    RaisinBranCrunch over 5 years
    @MushfiqurRahman Before the location block in my post, I have in my server block the line: server_name subdomain.mysite.com; So, that means with the location block in my post being /services/myservice, the final thing in the Javascript would be var ws = new WebSocket("wss://subdomain.mysite.com/services/myservice");.
  • Param sohi
    Param sohi over 4 years
    In which file do we need to add this in apache 2.4 ?
  • BenMorel
    BenMorel over 4 years
    Looks like SSL is supported now, since early 2017. See reactphp/socket#55 and @Jordi's answer below.
  • BenMorel
    BenMorel over 4 years
    This is the most up-to-date answer and should probably be the accepted answer now that SSL support has been added!
  • dror shalit
    dror shalit over 3 years
    This is The Bets Answer That I have Found After HOURS!!!!! of searching for an answer! Thank YOU!!!!!!!
  • fred
    fred about 3 years
    This worked for me! Only thing is I used 127.0.0.1 in javascript. No need to open the port on the firewall.
  • s.abbaasi
    s.abbaasi over 2 years
    By doing a ProxyPass, one should consider raising ServerLimit in Apache prefork. Because it may become a bottleneck as a connection in Apache remain open and busy during the socket lifetime. see here: stackoverflow.com/a/70347693/2962705
  • Sajjad Hossain Sagor
    Sajjad Hossain Sagor over 2 years
    in httpd.conf file! the file httpd.conf should be under dir /conf/httpd.conf