Scaling and Securing WebSockets with HAProxy

sddefault

In this blog, I will discuss Websockets, Scaling and Securing WebSockets with HAProxy , Coding and many more. Let’s Begin!

What is WebSockets?

Whenever a client tries to establish a connection from a web server, the First thing that browser does is that it sends the connection as “Upgrade” in a Request Header. When the Web Server receives an upgrade header, It tells the server that it wants to change the connection to WebSocket instead of HTTP.

Upgrade Header is used to confirm that the client is entitled to request an upgrade to WebSocket. The Upgrade general header allows the client to specify what additional communication protocols it supports and would like to use if the server finds it appropriate to switch protocols.

Scaling and Securing WebSockets with HAProxy

What is a Reverse Proxy?

reverse proxy accepts a request from a client, forwards it to a server that can fulfil it, and returns the server’s response to the client.

Scaling and Securing WebSockets with HAProxy

Scaling WebSockets

In the below illustration, we have 2 clients and 2 backends with WebSocket running. If Client 1 makes a request to reverse proxy by sending an upgrade packet then it basically forward to one of the backend servers. All Reverse Proxy does not support WebSocket. Only a few support such as NgINX, HAProxy etc. We can assume that the load-balancing algorithm is Round Robin so it is going to connect to SERVER1.

Now We have one TCP connection between Client & WebSocket and another TCP Connection between Reverse Proxy & WebSocket Server. Since this is WebSocket Protocol, so Reverse Proxy will act as Layer 4 Proxy. It will Stream Every Single Packet that you send from Client 1 will be sent to Server 1. There is a dedicated TCP Connection to Client 1. It will act as a 1:1 TCP Connection.

Scaling and Securing WebSockets with HAProxy
Scaling and Securing WebSockets with HAProxy

Similarly, Client 2 Make a request and the request is sent to WebSocket 2. The main issue is that If Client 1 wants to send a message to Client 2 then in that case since the connection is established between Client 1 and Server 1 so Server 2 is unaware of Server 1. To make aware of Sever 2 we need to use Redis. Redis helps in Passing events between Servers.

Coding

The server only has a list of clients who are connected to a particular server. If you want to pass messages from one server to another server then you must store data in the shared database like Redis between servers using Publisher/Subscriber framework like RabbitMQ. In this, I have configured HAProxy and Pass messages to all the connected clients.

I have taken 3 Server. 1 Master and 2 Slaves.

Master: 3.144.84.135 -> For HAProxy Configuration

Slave : 18.218.115.196 , 52.14.245.146 -> Run WebSockets

STEP 1: Install HAProxy and Configure with the below instructions in Master Server

frontend haproxynode
        bind *:80
        default_backend backendnodes

backend backendnodes
        balance roundrobin
        server server1 18.218.115.196:4000 check
        server server2 52.14.245.146:4000 check

STEP 2: Configure Slave Server with below Instruction. Create index.html file and replace IP with HAProxy IP.

<html lang="en">
    <head>
        <title>WebSocket Server 1</title>
    </head>
    <body>
        <h1>WebSocket Example Server 1</h1>

        <form>
            <label for="message">Message:</label><br />
            <input type="text" id="message" name="message" /><br />
            <input type="button" id="sendButton" value="Send" />
        </form>

        <div id="output"></div>

        <script type="text/javascript">
            window.onload = function() {
                // connect to the server
                let socket = new WebSocket("ws://3.144.84.135/ws/echo");
                socket.onopen = () => socket.send("Client connected!");

                // send a message to the server
                var sendButton = document.getElementById("sendButton");
                var message = document.getElementById("message");
                sendButton.onclick = () => {
                    socket.send(message.value);
                }

                // print a message from the server
                socket.onmessage = (evt) => {
                    var output = document.getElementById("output");
                    output.innerHTML += `<div>${evt.data}</div>`;
                }
            }
        </script>
    </body>
</html>

STEP 3: Configure Slave Server with the below code. Create an index.js file and run the server.

const express = require('express');
const app = express();
const path = require('path');
const expressWs = require('express-ws')(app);

// Serve web page HTML
app.get('/ws', (req, res) => {
    res.sendFile(path.join(__dirname + '/index.html'));
});

// WebSocket function
app.ws('/ws/echo', (ws, req) => {
    // receive a message from a client
    ws.on('message', msg => {
        console.log(msg);

        // broadcast message to all clients
        var wss = expressWs.getWss();
        wss.clients.forEach(client => client.send("Received: " + msg));
    })
});

app.listen(4000);

STEP 4: Below screenshot displays an input box that the user types a message and send to the WebSocket server. The WebSocket server then echoes that message back to all connected clients.

Scaling and Securing WebSockets with HAProxy
Scaling and Securing WebSockets with HAProxy

Secure WebSocket Connection

  1. Enable Cors
  2. Restrict payload size
  3. Authenticate users before WS connection establishes
  4. Use SSL over websocket

For more detail visit: Secure WebSocket Connection

Hope you like our Scaling and Securing WebSockets with HAProxy Blog. Please Subscribe to our blog for an upcoming Blog.

Happy Coding!

Read More: Important HAProxy Sticky Sessions Tutorial

Be the first to comment on "Scaling and Securing WebSockets with HAProxy"

Leave a comment

Your email address will not be published.


*