HAProxy Enterprise Documentation 1.6r2
WebSocket
There is almost nothing needed to proxy WebSocket connections through HAProxy Enterprise. The load balancer knows how to upgrade an HTTP connection to a WebSocket connection and once that happens, messages will travel back and forth through a WebSocket tunnel.
However, you must design your system for scale if you plan to load balance multiple WebSocket servers. Each client connects to one of your servers, where it then opens a persistent WebSocket connection. Because each server has only its own list of connected clients, messages passed to one server must be shared with the other servers somehow. Similarly, when you want to broadcast a message to all clients, all servers must receive and relay it. A typical way to solve this is to store messages in a shared database like Redis or pass messages between servers using a Publish/Subscribe framework like Kafka or RabbitMQ.
Example WebSocket client and server
-
Use the WebSocket Javascript API to create a client application. Below is an example web page named index.html. Change the WebSocket URL ws://192.168.50.25/ws/echo to use your load balancer's IP address:
<!DOCTYPE html>
<html lang="en">
<head>
<title>WebSocket Example</title>
</head>
<body>
<h1>WebSocket Example</h1>
<form>
<label for="message">Message:</label><br />
<input type="text" id="message" name="message" /><br />
<input type="button" id="sendBtn" value="Send" />
</form>
<div id="output"></div>
<script type="text/javascript">
window.onload = function() {
// connect to the server
let socket = new WebSocket("ws://192.168.50.25/ws/echo");
socket.onopen = () => socket.send("Client connected!");
// send a message to the server
var sendButton = document.getElementById("sendBtn");
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>
-
Create the WebSocket server. The following node.js application file is named index.js. It serves the web page from the previous step and hosts the /ws/echo WebSocket function:
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(3000);
-
Add the following node.js package.json file to your project and start the application with the npm start
command:
{
"name": "websocket-server",
version": "1.0.0",
"description": "Example WebSockets application",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"author": "Your Name",
"license": "ISC",
"dependencies": {
"express": "^4.17.1",
"express-ws": "4.0.0"
}
}
-
Now that the node.js application is listening, load balance it by adding a frontend
and backend
to your HAProxy Enterprise configuration that routes traffic to port 3000:
frontend fe_main
bind :80
default_backend websocket_servers
backend websocket_servers
option http-server-close
option logasap
timeout tunnel 1h
server s1 127.0.0.1:3000 check
The web page displays a text box that the user types a message into to send to the WebSocket server. The server then echoes that message back to all connected clients.
Next up
Session Persistence