NGINX: Websockets Demo
NGINX: Websockets Demo
Node.js server code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
const http = require("http");
const WebSocketServer = require("websocket").server
const PORT = process.argv[2] || 8080;
let connection = null;
//create a raw http server (this will help us create the TCP which will then pass to the websocket to do the job)
const httpserver = http.createServer();
//pass the httpserver object to the WebSocketServer library to do all the job, this class will override the req/res
const websocket = new WebSocketServer({
"httpServer": httpserver
})
httpserver.listen(PORT, () => console.log(`My server is listening on port ${PORT}`))
//when a legit websocket request comes listen to it and get the connection .. once you get a connection thats it!
websocket.on("request", request=> {
connection = request.accept(null, request.origin)
connection.on("close", () => console.log("CLOSED!!!"))
connection.on("message", message => {
console.log(`Received message ${message.utf8Data}`)
connection.send(`Server ${PORT} responded to your message: ${message.utf8Data}`)
})
})
Configure Nginx as Layer 4 WebSocket Proxy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
stream {
upstream allbackend {
server 127.0.0.1:2222;
server 127.0.0.1:3333;
server 127.0.0.1:4444;
server 127.0.0.1:5555;
}
server {
listen 8080;
proxy_pass allbackend;
}
}
events { }
- Listening on port 8080
- Any TCP connection request is a tunnel and always goes to the websocket app
- Paths don’t matter (layer 7)
- ws://localhost/ -> websocket app
- ws://localhost/blahblah -> websocket app
- Layer 4 proxying blindly tunnels everything to the backend
- Any connection request to port 8080 will be tunneled to the websocket app backend
Run below code to connect to webSockets
1
2
3
4
let ws = new WebSocket("ws://localhost:8080");
ws.onmessage = message => console.log(`Received: ${message.data}`);
ws.send("Hello! I'm client")
ws
create a tunnel which is sticky and request goes to same server. If any path is used here, it will not be checked and request is blindly passed to server.
Configure Nginx as Layer 7 WebSocket Proxy
- Intercept the path and “route” appropriately
- http://localhost/ -> open main html page
ws -> websocket app
ws/chat -> another websocket app for chatting
ws://localhost/chat
- Can’t do that in Layer 4 since port 80 is blindly tunnels
HTML frontend code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>Hello, WebSockets</h1>
<input type = 'text' id = 'txt'>
<div id = 'divOut'></div>
<script>
const txtBox = document.getElementById("txt");
const divOut = document.getElementById("divOut");
const ws = new WebSocket("ws://localhost/wsapp/")
ws.onmessage = e=> divOut.innerHTML += e.data + "<br/>";
txtBox.addEventListener("keypress", e=> {
if (e.keyCode === 13){
ws.send(txtBox.value);
txtBox.value ="";
}
})
</script>
</body>
</html>
Nginx config
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
http {
upstream allbackend {
server 127.0.0.1:2222;
server 127.0.0.1:3333;
server 127.0.0.1:4444;
server 127.0.0.1:5555;
}
server {
listen 80;
location / {
root /Users/HusseinNasser/javascript/javascript_playground/nginx-websockets/;
}
location /wsapp/ {
proxy_pass http://allbackend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
}
}
}
# due to some reasons, NGINX requires this block!
events { }
This post is licensed under CC BY 4.0 by the author.