Zach Posten - 2022 Jun 30
Websockets are really cool for instances when you need real time communication between your users
I set out to build a cool Jackbox-style trivia game and along the way I learned a lot about websockets, HTTPS, and Digital Ocean. Unlike many of my posts, this article is going to focus on backend technologies as once you understand that the frontend becomes like any other web app for the most part. Specifically, I'm going to talk a lot about the specific process I used to get the backend server deployed and accessible over HTTPS (actually WSS, surprise!) to hopefully remove the some of the mystery for anyone else going through the process.
I decided to use a library called socket.io as a wrapper around my websockets code. It provides a bunch of really nice features:
My initial socket.io/express server code looked like this:
I chose to go with Digital Ocean this time because they have a 60 day free trial, so these instructions are going to be pretty specific to them.
A droplet is what Digital Ocean calls an individual one of their virtual machines. They also have a "marketplace" of preconfigured VMs that you can use to not be starting from scratch (but so far as I know they're all free). The one we're interested in for this purpose is the NodeJS one, published by Digital Ocean themselves.
Choose your CPU & data center options, and then decide to authenticate to it. You can choose either an SSH key or a password. The password is simpler but the SSH key is more secure. Your choice!
Then go ahead and click the Create Droplet button at the bottom.
If you're unfamiliar with it, here is a summary of a few of the most common commands that you'll need.
SSH into your new droplet VM by running
ssh root@<ip addr of vm>. If you secured it with a password you'll have to enter that here.
Once you're in,
/var/www/html, this is where you'll find
hello.js, the default Node.js app that was preconfigured to run on this machine. This is also where you should clone your repository into. If for some reason you're not using source control, you can directly upload files to the droplet using SFTP.
Now that your code is here:
cd down into the directory where your root server file lives
Install your dependencies (
pnpm i, etc.)
Launch your app with
pm2 start ./server.js (remember if you didn't switch to the nodejs user earlier, you'll have to prefix this command;
sudo -u nodejs pm2 start ./server.js)
Then you'll need to map the port that your app runs on to an HTTP URL.
To do this, open
/etc/nginx/sites-available/default in your favorite termainal text editor
You'll see a block near the bottom of the file that looks like this
You can either duplicate that block, adding the copy right beneath it, or just edit that
proxy_pass line to use port number that your server runs on (unless that happens to be 3000, then you're golden).
Kill the example
hello Node.js app with
pm2 stop hello (this is especially important if your app also runs on port 3000)
sudo systemctl restart nginx to enable your new nginx config
pm2 save to schedule your code to run at launch
Test it out! You should now be able to access your server at
http://<ip addr of vm>
Your frontend will need to use the socket.io-client library to to your socket.io backend. You'll also want to persist that connection somehow so that you're not reconnecting to the backend every time the user navigates to a new page in your app.
Security, the bane of devlopers and the savior of users. Because it's so good for your users, most platforms where you might want to deploy your frontend (Vercel or Netlify for example) do not allow you to deploy using HTTP, and require HTTPS.
Digital Ocean has a quite thorough blog post about adding HTTPS, which you should absolutely read through. Here I'm just going to quickly summerize that what blog post explains in greater depth:
www.here, but you could possibly use a subdomain of one of your domains so that you don't hog the whole thing just for a backend. To do so, just make the A record point to that subdomain.
server_nameentry to an Nginx file. For simplicity I added it to
/etc/nginx/sites-available/default, but you could instead create a specific one for this particulary domain. I'm not super informed about the tradeoffs of these two approaches.
sudo nginx -t
sudo systemctl reload nginx
sudo certbot --nginx -d example.com(or if you are using a subdomain you would replace
There's one last tricky bit here. Earlier we set our frontend to connect to the backend over the websockets protocol at
ws://188.8.131.52. Just like HTTP becomes HTTPS when you add SSL, WS becomes WSS.
So now that your backend is deployed to an HTTPS domain name, you're going to connect to it at
wss://example.com (again if you used a subdomain just add that here).
At some point you will update your server code and want to deploy those updates. Here is a quick summary of the commands necessary to log into your droplet and do so:
That's it! I hope that was helpful if you would like to do something similar. I was intentionally very light on the specifics of the app that I built in this post, but you can find the source code for it here.