wss fails over https on apache server

1.6k views Asked by At

I have a server in digital ocean which is using StartCOM class I primary intermediate CA for ssl. I have set u a websocket server and I want to make a connection to it from a page which is served by https.

When I try to connect to the websocket using just http it works fine. But when I try to use it over https by changing the websocket uri from ws to wss it does not connect.

What am I doing wrong. Connection is made using fancywebsockets.js

fancywebsockets.js

var FancyWebSocket = function(url)
{
    var callbacks = {};
    var ws_url = url;
    var conn;

    this.bind = function(event_name, callback){
        callbacks[event_name] = callbacks[event_name] || [];
        callbacks[event_name].push(callback);
        return this;// chainable
    };

    this.send = function(event_name, event_data){
        this.conn.send( event_data );
        return this;
    };

    this.connect = function() {
        if ( typeof(MozWebSocket) == 'function' )
            this.conn = new MozWebSocket(url);
        else
            this.conn = new WebSocket(url);

        // dispatch to the right handlers
        this.conn.onmessage = function(evt){
            dispatch('message', evt.data);
        };

        this.conn.onclose = function(){dispatch('close',null)}
        this.conn.onopen = function(){dispatch('open',null)}
    };

    this.disconnect = function() {
        this.conn.close();
    };

    var dispatch = function(event_name, message){
        var chain = callbacks[event_name];
        if(typeof chain == 'undefined') return; // no callbacks for this event
        for(var i = 0; i < chain.length; i++){
            chain[i]( message )
        }
    }
};

Client Side JS

var Server;

        function log( text ) {
        console.log(text) 
    }

        function send( text ) {
            Server.send( 'message', text );
        }

        $(document).ready(function() {
            log('Connecting...');
            Server = new FancyWebSocket('ws://www.myserver.com:9400');

            $('#message').keypress(function(e) {
                if ( e.keyCode == 13 && this.value ) {
                    log( 'You: ' + this.value );
                    send( this.value );


                }
            });

            //Let the user know we're connected
            Server.bind('open', function() {
                log( "Connected." );
            });

            //OH NOES! Disconnection occurred.
            Server.bind('close', function( data ) {
                log( "Disconnected." );
            });

            //Log any messages sent from server
            Server.bind('message', function( payload ) {
                log( payload );
            });

            Server.connect();
        });

Server.php

<?php
// prevent the server from timing out
set_time_limit(0);

// include the web sockets server script (the server is started at the far bottom of this file)
require 'class.PHPWebSocket.php';

// when a client sends data to the server
function wsOnMessage($clientID, $message, $messageLength, $binary) {
    global $Server;
    $ip = long2ip( $Server->wsClients[$clientID][6] );

    // check if message length is 0
    if ($messageLength == 0) {
        $Server->wsClose($clientID);
        return;
    }

    //The speaker is the only person in the room. Don't let them feel lonely.
    if ( sizeof($Server->wsClients) == 1 )
        $Server->wsSend($clientID, "There isn't anyone else in the room, but I'll still listen to you. --Your Trusty Server");
    else
        //Send the message to everyone but the person who said it
        foreach ( $Server->wsClients as $id => $client )
            if ( $id != $clientID )
                $Server->wsSend($id, "Visitor $clientID ($ip) said \"$message\"");
}

// when a client connects
function wsOnOpen($clientID)
{
    global $Server;
    $ip = long2ip( $Server->wsClients[$clientID][6] );

    $Server->log( "$ip ($clientID) has connected." );

    //Send a join notice to everyone but the person who joined
    foreach ( $Server->wsClients as $id => $client )
        if ( $id != $clientID )
            $Server->wsSend($id, "Visitor $clientID ($ip) has joined the room.");
}

// when a client closes or lost connection
function wsOnClose($clientID, $status) {
    global $Server;
    $ip = long2ip( $Server->wsClients[$clientID][6] );

    $Server->log( "$ip ($clientID) has disconnected." );

    //Send a user left notice to everyone in the room
    foreach ( $Server->wsClients as $id => $client )
        $Server->wsSend($id, "Visitor $clientID ($ip) has left the room.");
}

// start the server
$Server = new PHPWebSocket();
$Server->bind('message', 'wsOnMessage');
$Server->bind('open', 'wsOnOpen');
$Server->bind('close', 'wsOnClose');
// for other computers to connect, you will probably need to change this to your LAN IP or external IP,
// alternatively use: gethostbyaddr(gethostbyname($_SERVER['SERVER_NAME']))
$Server->wsStartServer('my.ip.add.ress', 9400);

?>

Server Screen Shot

enter image description here

It keeps on getting disconnected

1

There are 1 answers

0
Gilles Lesire On

I ran into the same issue (I even use the same PHP script) and manage to resolve this using stunnel. With a lot of trial-and-error from all kind of different, contradicting sources I managed to get it running. However you won't get client ip addresses anymore, you'll have to send it to the server manually if you need it. I read somewhere that you could forward the client IP using proxy but haven't yet been able to set that up myself.

Install stunnel on server

Login to your server through ssh make sure your system is fully up to date.

apt-get update
apt-get upgrade

Install the stunnel package

apt-get install stunnel4 -y

Configure stunnel

Create a config file for stunnel by running the following command

nano /etc/stunnel/stunnel.conf

Write the following into the file

foreground = yes
key = /path/to/your/ssl/cert.key
cert =  /path/to/your/ssl/cert.pem
CAfile = /path/to/your/ssl/cert.pem
debug = 7
output = /var/log/stunnel_websocket.log

[websocket]
accept = myserver.com:9401
connect = 9400

Personally I just used the same certificate for the stunnel as I did for the HTTPS setup.

Run the stunnel

You have to keep the stunnel running like you have to keep the websocket running. Do this with the command:

/etc/init.d/stunnel4 restart

Alter your PHP script

Change the PHP file server.php

$Server->wsStartServer('my.ip.add.ress', 9400);

to

$Server->wsStartServer('localhost', 9400);

Alter the client side JS script

Server = new FancyWebSocket('ws://www.myserver.com:9400');

should be changed to

Server = new FancyWebSocket('wss://www.myserver.com:9401');

So if you are running the stunnel and the websocket you should now be able to send and receive data over the socket again with the only difference that all clients now appear to be coming from 127.0.0.1 according to the websocket script.