Krysti.Engineer Official Chat
You are viewing an inferior version of the site because your browser does not support WebP. Do upgrade to something like Chrome or Firefox. Loading websites like this causes them to require a fallback set of images and they are almost always lower quality and larger in size.

NodeJS Based Websocket Server over HTTPS

This project can expand quite a bit if you just continue making commands from both the client and server design below.
2022-07-18T:00:00:00+00:00 July 19 2022 00:00:00

npm install websocket

Create a project directory. This will be a minimal environment to get this going so we're going to have to include the websocket requirements.

"use strict";
const fs = require('fs');
const WebSocket = require('ws');
const https = require('https');

First we include what we'll be working with. Only WebSocket will need the extra inclusion of being installed via npm like above.

Configure It!

Server:
Node Port:
Server Username:
 
 
This will configure it's essential information so it's properly changed but further customization will have to be made to the files you're creating to have it how you likely want it.

const server = new https.createServer({
  cert: fs.readFileSync('/etc/letsencrypt/live/yourserver.com/fullchain.pem'),
  key: fs.readFileSync('/etc/letsencrypt/live/yourserver.com/privkey.pem')
});
const wss = new WebSocket.Server({ 
	server,
	verifyClient: function (info, cb) {
		// Change this to your website domains
		if((info.req.headers.origin=='https://yourserver.com')||(info.req.headers.origin=='https://www.yourserver.com')) { 
			cb(true); 
		} else { 
			console.log("BAD ORIGIN" + info.req.headers.origin);
			cb(false, 401, 'Unauthorized');
		}
	}
});

Here we use LetEncrypt's Certbot certificates as an example. Below will be an example of how to read directly these certificates from their directory without having to copy them elsewhere. From there it creates the websocket server with a verifyClient callback function to check if the origin of the client connection is code from your website only.

function noop() {}
 
function heartbeat() {
  this.isAlive = true;
}
var json_send;
wss.on('connection', function connection(ws,req) {
    console.log("Incoming");
	ws.isAlive = true;
	ws.on('pong', heartbeat);
	ws.on('close', function close() {
        try {
            console.log("Connection leaving");
			return ws.terminate();
		} catch(e) { console.log(e); }
	});	
    ws.on('error', function(err) {
        console.log('ERROR' + err);
		if(ws.readyState==3) { return ws.terminate(); }
    });
    ws.on('message', function incoming(message) {
		var tmsg = Buffer.from(message).toString('ascii');
		try {
			var jmsg = JSON.parse(tmsg);
		} catch(e) {
			console.log("ERROR: Not JSON, skipping");
			return;
		} 
		console.log(jmsg);
		switch(jmsg.command) {
			case "WHATTIME": {	
				var ts = Math.floor(new Date().getTime() / 1000);
				json_send = {
					command:'WHATTIME',
					time: ts
				}			
				//console.log(json_send);
				break;
			}
		}
		if(json_send!='') { ws.send(JSON.stringify(json_send)); }
	});
});
wss.broadcast = function broadcast(msg) {
   wss.clients.forEach(function each(client) {
	   //console.log(client);
	   console.log("Sending to client");
       client.send(msg);
    });
};
const interval = setInterval(function ping() {
  wss.clients.forEach(function each(ws) {
        if (ws.isAlive === false) { 
			console.log("Dead client");
			return ws.terminate(); 
		}
    ws.isAlive = false;
    ws.ping(noop);
  });
}, 30000);
server.listen(9000, 'yourserver.com'); 


This will start a server that spits back the timestamp of the node server when it receives a command 'WHATTIME' then it sends that time back to the client (website) also as a command called 'WHATTIME' which the client will recognize in an example below. If you expand the server, built in already is a way to send a message to ALL the clients connected by using wss.broadcast() function instead of ws.send() that would only send to a single client on it's own. The wss.broadcast() function is the same JSON.stringify() input as ws.send() would need and that the example builds through the json_send variable.

<script>
var ts,json_send;
ts = new WebSocket("wss://yourserver.com:9000"); //change this
ts.onopen = function (event) {
	console.log('Time Server: Connection is open ...');
	console.log('ts',event);
	json_send = {
		command:'WHATTIME',
		param:31337 // nothing, just to see it
	}
	ts.send(JSON.stringify(json_send));
}
ts.onerror = function (err) {
	console.log('err: ', err);
}
ts.onmessage = function (event) {
	jsonOut = JSON.parse(event.data);
	switch(jsonOut.command) {
		case "WHATTIME": {
			if(jsonOut.time) {
				console.log("From server", jsonOut.time);
			}
			break;
		}
	}	
}
</script>

Embedding the client on the website to accommodate your WHATTIME command can be done like this. On the basis of this JSON system here you can expand this very easily for numerous projects to just have communication back and forth. Monitor this example via HTTPS and load your DevTools(F12) console also, monitor direct node output on your server and you'll see the back and forth.
chmod go+x /etc/letsencrypt/live/ /etc/letsencrypt/archive/

chown -R root:your_user /etc/letsencrypt/live/yourserver.com /etc/letsencrypt/archive/yourserver.com/

chmod -R g+r,o-rwx /etc/letsencrypt/live/yourserver.com /etc/letsencrypt/archive/yourserver.com/

This is how you can get node to read directly your SSL certificates from LetsEncrypt's Certbot. Change "your_user" in this example to your user. :P

Contact Krysti

@itskrystibitch Twitter Photo
Twitter:
@KrystiOnline
Facebook:
@KrystiOnline
IRC:
Official Chat
Direct.Me:
@Krysti
Ko-fi:
@Krysti
Photos:
Virtual Krysti
E-Mail / Notify of errors:
coder [@] krysti.engineer
Please be patient contacting me, I don't really check much of social media or anything. If you use the IRC be sure to stick around because that's how IRC works, silly. :P