Why I Started Hosting Tiny Web Games
I've been running game servers for years—mostly Minecraft, Valheim, that sort of thing. They're resource-heavy, need constant attention, and honestly, they're overkill for what I actually wanted: simple games I could share with friends without dealing with third-party platforms or ads.
I stumbled into this while cleaning up an old project folder. I had a collection of single-file HTML5 games—things like Snake, Tetris clones, simple puzzle games—all under 100KB. Most were just HTML with embedded JavaScript and minimal CSS. I realized I could serve these from my existing Caddy setup without spinning up anything new.
The appeal was immediate: no databases, no complex state management, no multiplayer sync headaches. Just static files that load instantly and run entirely in the browser.
My Actual Setup
I'm running Caddy on a Proxmox VM that already handles several other services. The VM has 2GB RAM and 2 CPU cores allocated, though the games themselves use almost none of it since they're client-side.
My Caddyfile configuration for the games directory is dead simple:
games.mydomain.com {
root * /var/www/games
file_server browse
encode gzip
}
That's it. The browse directive gives me a directory listing, gzip compresses files on the fly, and Caddy handles HTTPS automatically. Each game is a single HTML file or a folder with an index.html and maybe a few assets.
I keep the games in /var/www/games/ with a simple structure:
/var/www/games/ ├── snake.html ├── tetris.html ├── 2048/ │ └── index.html └── breakout.html
No build process, no npm packages, no frameworks. Just files I can edit with vim if I want to tweak something.
Resource Monitoring That Actually Matters
Since these games run in the browser, server-side monitoring is mostly about making sure Caddy stays responsive and doesn't leak memory over time. I'm not tracking game performance—that's the client's problem.
I use a simple shell script that runs every 5 minutes via cron:
#!/bin/bash
ps aux | grep caddy | grep -v grep | awk '{print $3,$4,$6}' >> /var/log/caddy-resources.log
This logs CPU percentage, memory percentage, and RSS memory in KB. It's crude but effective. I can grep through it or pipe it into a quick awk script to see trends.
For real-time checks, I just SSH in and run htop. Caddy typically sits at 0.1% CPU and around 30MB RAM for my setup. If those numbers spike, something's wrong—usually means I misconfigured a reverse proxy rule or someone's hammering the server.
I also enabled Caddy's basic access logs:
games.mydomain.com {
log {
output file /var/log/caddy/games-access.log
}
root * /var/www/games
file_server browse
encode gzip
}
I don't parse these automatically. Once a week I'll skim through to see if there's unusual traffic or 404 patterns that suggest broken links.
What Worked
The entire approach worked better than I expected. Caddy's automatic HTTPS meant I didn't waste time with certificates. The file_server directive with browse enabled gave me an instant game library interface—not pretty, but functional.
Gzip compression made a noticeable difference. A 95KB HTML file compresses to around 20KB, which loads almost instantly even on mobile connections. I tested this by temporarily disabling gzip and comparing load times on my phone over 4G.
The games themselves are surprisingly robust. Since they're self-contained HTML files with no external dependencies, they don't break when some CDN goes down or a library version changes. I have games from 2015 that still run perfectly.
Resource usage is negligible. Caddy serving static files barely registers on my monitoring. The VM could probably handle hundreds of concurrent players before I'd notice any performance impact, though I've never had more than a dozen at once.
What Didn't Work
My first attempt at monitoring was overly complicated. I tried setting up Prometheus with Caddy's metrics endpoint, but it was overkill for serving static files. The metrics didn't tell me anything useful that a simple log file couldn't. I spent two hours configuring it before realizing I was solving a problem I didn't have.
I also tried adding a simple leaderboard system using localStorage in the games. This failed immediately because localStorage is per-browser. There's no way to share scores between players without adding a backend, which defeats the entire point of keeping things minimal.
Directory browsing looks terrible. The default Caddy file_server browse template is functional but ugly. I considered writing a custom template, but that would add maintenance overhead. I left it as-is because it works, even if it's not pretty.
Some games I found online were poorly written and caused browser performance issues. One Snake clone had a memory leak that would crash mobile browsers after a few minutes. I had to test each game myself before adding it to the collection. There's no automated way to validate client-side JavaScript quality.
Limitations I Live With
These games have no multiplayer capability. Everything runs locally in the browser. If I wanted real-time multiplayer, I'd need WebSockets and a proper game server, which would completely change the resource profile.
There's no user authentication or personalization. Anyone with the URL can access the games. I'm fine with this for my use case, but it means I can't restrict access or track individual players.
Mobile support is hit-or-miss. Some games work great on touchscreens, others are unplayable without a keyboard. I can't fix this without rewriting the games, which I'm not interested in doing.
The monitoring I have is reactive, not proactive. If Caddy crashes, I won't know until I check manually or someone tells me the site is down. I could set up uptime monitoring, but I haven't bothered since this isn't a critical service.
Key Takeaways
Serving static HTML5 games is one of the lightest workloads you can run on a server. If you're already running Caddy or nginx for other services, adding a games directory costs essentially nothing.
Simple monitoring is enough for simple services. A cron job logging basic stats beats a complex monitoring stack that you'll never actually look at.
Client-side games shift all the performance burden to the player's browser. Your server just needs to deliver files quickly. Gzip compression and a CDN (if you want) are the only optimizations that matter.
The biggest limitation is discoverability. Without a proper frontend, players need to know the exact URLs or browse the directory listing. This is fine for sharing with friends but wouldn't work for a public game site.
Self-contained HTML files are remarkably durable. No dependencies means nothing breaks over time. I have games that are nearly a decade old and still work perfectly.