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>
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
Post a Comment