Skip to main content

Scaling and Securing WebSockets with HAProxy - Explained

Scaling and Securing WebSockets with HAProxy - Explained
In this article, I will discuss Websockets and how to Scale and Secure WebSockets with HAProxy, Coding and many more.

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.

What is a Reverse Proxy

A 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 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.

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);

Secure WebSocket Connection

  • Enable Cors.
  • Restrict payload size.
  • Authenticate users before WS connection establishes.
  • Use SSL over websocket.

To learn more: visit secure your WebSocket connections.

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

Comments

Popular posts from this blog

Blogger Landing Page Template - Free Landing Page Templates

If you are looking for free Blogger (Blogspot) landing page templates, then you have come to the right place. There are a lot of available templates in WordPress with landing pages, but there is a scarcity of Blogger landing page templates. 

How to Close Flipkart Pay Later Account - Step by Step

Flipkart Pay Later is a convenient and flexible payment option that allows you to buy products from Flipkart and pay later within a period. However, there may be some reasons why you may want to close your Flipkart Pay Later account, such as:

Docker Compose file vs Dockerfile - Differences - Explained

The Dockerfile is used to build a custom image and does not directly generate a container. It’s just that you can run the container while running the image. The container orchestration to deploy the environment is done using the docker-compose.yml file, which may require a Dockerfile.