Backend challenges when building a web based network game

Feb 28, 2025

I am making Paint Fight, a game where you compete to throw more paint on the screen than your opponents. It will be a fast paced yet subtly strategic action game (once complete).


This game is still very much in progress fyi

Building a backend

I chose to build Paint Fight's backend with free, widely accepted open source solutions. I wanted to survey the landscape to see how straightforward it is to roll a webserver without prepackaging much.

Setting up a WebSocket server

Paint Fight is a real time game with bidirectional data needs. After doing enough research on WebSockets to write an entire post, I ended up choosing uWebSockets since I wanted a more performant, foundational experience than to build upon a library like Socket.IO (which I've used in the past) and its more full featured offering (e.g. with heartbeats and client management out of the box). I'll save the real-time and performance tweaking for another post, but uWebSockets wasn't just performant, it also provided useful features like pub-sub and SSL termination. I was able to use pub-sub to match communication to players in the same game and uWebSockets' SSL termination let me avoid introducing nginx or some other web service.

I haven't set up SSL in a long time (many web platforms handle this trouble) but I was able to use certbot to get Let's Encrypt certificates. I have only nice things to say about certbot, as it handles the entire process of verifying that you control your web server by hosting a few SSL challenge files. Certificate renewal is manual but you can set up a cronjob for certbot, so much easier than manually solving the challenges.

Deploying a server from scratch

I haven't manually set up a server in the cloud in years - instead relying on services like Heroku or Amazon Machine Images to get up and running quickly. So with this project, I wanted to survey the landscape to see how straightforward it is to roll your own servers.

Here were my requirements:

  • My application should be composed of well orchestrated containers
  • Code deployments to be as simple as pushing to a Git repository

Containers

I spent a day diving into Docker - learning that most folks use standard images as lego pieces to build up their application. For me, it was straightforward to setup a standard Redis image and write a custom Dockerfile image for my NodeJS WebSocket server. Then I was able to specify initialization order and communication between my containers via Docker Compose's compose.yaml. I didn't get to use Docker Swarm as I'm not deploying to multiple hosts.

Dockerized Paint Fight Web Service

I also set up my environment variables to run some of these containers locally during development. Ensuring things run locally always saves me a lot of debugging on the servers directly.

Docker made all of this pretty easy, so I can see why it's become the de-facto standard.

Deploying through Git

I know a lot of people that will refuse to do any real work until their workspace/environments are clean. I apparently have the same tendency to procrastinate on my projects by working incessantly on tooling, and this project was no exception.

The biggest reason I reach for platforms-as-a-service (e.g. Heroku) is that they have such quick and easy tooling to deploy from Git. So how do you set that up yourself? Here's what I ended up with:

Paint Fight Continuous Deployment Automated deployments with a 'git push' from my command line, chef's kiss.

  1. git push to my GitHub remote repository
  2. GitHub Actions triggers my workflow on a Linux VM Action Runner
  3. Action Runner builds and uploads Docker image to GitHub Container Registry (amazing resource)
  4. Action Runner SSH's onto my Paint Fight server, downloads the multicontainer image, and runs it
  5. We're deployed!

Not only are these deployments straightforward, they only using free services. It's impressive that GitHub offers a container registry for its users, as my server's image is over 500MB and hosting that on S3 + CloudFront would cost $0.10 per download/deploy.

Conclusion

Running a server for an application is easier and cheaper than ever. There are a lot of tools at your disposal and you can build a pretty robust system for development without relying on Vercel or hosted platform services. Hopefully some of the ideas I've presented are ones you could try for your own projects.

For any questions or comments, you can reach me at [my full name] at gmail, or @stoneG_ on X.