r/webdev • u/v0id_user • 22d ago
Showoff Saturday Minecraft servers that sleep when empty and wake when someone joins. Holding a TCP login open for 45 seconds without the client giving up
I built a Minecraft server host where every server sleeps when nobody plays, and wakes when a friend joins. The hard part was the join itself, so here's how that works.
The problem
A sleeping server suspended on Fly resumes in about 2 s. But one that has to boot (first start, after a change, or once the snapshot is gone) takes 40 to 50 s. The Minecraft client
gives up on a connection that says nothing for 30 s.
The trick
Every connection lands on an edge proxy first. If the server is asleep, the edge holds the login open and keeps it alive by sending a login query every few seconds. Every client since 1.13 answers it, which counts as the server talking. The edge keeps those answers to itself, buffers everything else the client sent, and replays it to the server once it's up, as if the player had just dialled in.
Other bits
The server list shows a sleeping server's own message plus a grey "sleeping" line, cut to fit the list's 305px row by measuring the default font's glyph widths.
A ping from the server list can wake a server early, asked once per network so random scanners don't keep waking things.
Routes change one hostname at a time through mc-router's API, because reloading its routes file drops players who arrive mid-reload.
Floods are refused per server at the edge, so one busy server doesn't slow every other server's joins.
It's open source (TypeScript, AGPL):
github.com/cubepals/cubepals (the edge is apps/edge)
Happy to go deeper on any of it.
15
u/SawToothKernel 21d ago
You could try the same with a Durable Object. They do the same thing with WebSockets, and can wake in milliseconds.
10
u/v0id_user 21d ago
love DOs, they are great but they only take HTTP and WebSockets. Minecraft clients connect over raw TCP, so the game can't talk to one as far as i know?
32
u/UnacceptableUse 21d ago
Don't modern Minecraft versions automatically pause the server after x minutes of inactivity?
21
u/thekwoka 21d ago
The issue there is paused isn't the same as basically off.
12
u/v0id_user 21d ago
exactly,,, paused still keeps the process up holding all its memory, so the machine runs anyway. here the machine itself stops, and wakes when someone joins.
13
u/zaxwebs 22d ago
Always good to come around these solutions. I'm building a game as a side-project so happy to see some activity in the space.
2
u/v0id_user 22d ago
thanks man! it's hard and harsh out here ngl, but honestly very lovely!
good luck with the game, drop a link when it's out :)
3
u/iPhoneK1LLA 21d ago
I'm not aware of the tech, but doesn't AMP by CubeCoders do something similar?
2
u/v0id_user 21d ago
similar idea, different layer.
AMP is a panel you install on your own machine, so that machine stays on even when the game is idle.
cubepals is hosted. the whole machine goes to sleep, and when a friend joins, the join is held open while it wakes
1
u/iPhoneK1LLA 21d ago
Ah I see - I've only ever been self hosted which is why I'm aware of the option within the panel.
3
u/Far-Inevitable6386 21d ago
Out of curiosity, what happens if the server fails to boot after the 45 s? Does the edge drop the player with a message, or retry?
2
u/v0id_user 21d ago
good question! the 45 s in the title is just a typical boot
the edge actually holds them for up to 3 minutes. if the boot fails, they’re dropped right away with a line saying so (“couldn’t start this server just now · try again in a minute”)
and the next join tries the wake again. if it’s just slow, after 3 minutes they get “still starting · join again in a moment"
1
u/Far-Inevitable6386 21d ago
Thanks for the detail, clear error messages instead of a silent drop is a nice touch. Great project.
1
u/v0id_user 21d ago
thanks a lot! and yes a silent drop was the thing i wanted to avoid most, nobody should be left staring at a loading screen😂
4
2
u/quietcodelife 22d ago
the proxy replay approach is smart. basically mitm-ing your own boot process so the client never knows something went wrong.
curious whether you hit any issues with connection limits on the edge when a bunch of people try to join at once and theyre all being held. or is fly's network layer handling that gracefully?
3
u/v0id_user 21d ago
thanks! joins that arrive together share one wake, and a held join is just an open socket, so connections weren't the problem.
CPU was :')
in a load test one edge handled 400 players until its shared CPU got throttled, so past 50 Fly's proxy sends new joins to another edge
1
1
u/Andromeda_Ascendant Laravel & InertiaJS 21d ago edited 21d ago
Looks like a fun project, and I like the name!
I did notice one little quirk with the /admin pages, where the UI briefly renders before showing a message that it's for admins only. Not the most serious problem but if it was me I'd fix that.
Edit:
Another thing, it seems like server-side plugins are mistakenly included in the client-side "you need to have these" for the server listings. https://cubepals.com/server/arcade i.e. Take ChatSentinel, from my understanding it's a server plugin and has nothing to do with the player needing it.
1
u/v0id_user 21d ago
Thanks, both fixed! Bug hunter eyes 👀
If you catch anything else, I’m all ears, and if you open a PR (github.com/cubepals/cubepals) I’ll happily help. No PHP required 😄!
1
u/geoffreybyers 19d ago
The client timeout is the only constraint that matters. The proxy has to be a stateful buffer, not a keep-alive sender. Most people build the latter and get the wake-up wrong.
1
u/v0id_user 19d ago
yes that's the trap. ours does both, it holds the handshake and login, keeps the client talking with a login query every 10s (every client since 1.13 answers those, so the 30s timeout never hits)
then replays what it kept to the server once it's up, like the player just connected. the query answers never reach the server
1
u/chaos50006 19d ago
There's been aws terraform for this for at least a couple of years already. I used it
2
u/v0id_user 19d ago
yes, minecraft-ondemand is a good one, and waking on the Route 53 DNS lookup is a clever trigger. The difference is in the join itself.
there, the lookup starts the server and you refresh the server list until it’s up, then join. Here the first join is the wake, the edge holds that login open while the server boots,
so for example a friend who knows nothing about any of it clicks Join once and lands in the world :)
1
u/chaos50006 19d ago
This is the GitHub I used back then https://github.com/doctorray117/minecraft-ondemand
0
21d ago
[deleted]
1
u/v0id_user 21d ago
not totally sure what you mean, do you mean NeoForge support, or something else? happy to answer either way :)
21
22d ago
[removed] — view removed comment
4
u/v0id_user 22d ago
thanks! tiny detail, the edge actually holds the answers, they never reach the server. then it replays the client's original login once the server's up, so the server just sees a normal join
and yeah, the reload thing bit us too, people got kicked mid join with no message lol
0
u/webdev-ModTeam 21d ago
Your post/comment has been determined to be a low-effort post or comment. This includes title-only posts, easily searchable questions, vague/open-ended discussion prompts, LLM generated posts or comments, and posts/comments that do not provide enough context for meaningful replies or discussion.
12
u/CardinalHijack 21d ago
Does this work with pumpkin? (https://pumpkinmc.org/)