Valheim AWS server for friends, sleeps when nobody plays
- AWS
- EC2
- EIP
- Lambda
- API Gateway
- S3
- Docker
- systemd
- Discord
One friend's desktop was the whole infrastructure
Four friends, one Valheim world, one PC under a desk in Warsaw doing the hosting. When that machine was off, the world was off. When it was on, the host was paying with his FPS and his electricity bill. The other three were not technical, so any time the server hiccuped someone had to message him and wait.
The ask was small and clear: make this not depend on me, do not give us a setup we have to babysit, and please do not make it expensive. Not an enterprise problem. A friends-and-weekends problem. The kind where the constraints are tighter than they sound, because nobody is getting paid to operate this and nobody wants a bill surprise.
Cloud when needed, sleeping the rest of the time
Move the server to AWS so no one's home machine is on the hook, give it a static IP so the saved server address never changes, run the actual game in a Docker container so the host OS stays disposable, back the world up offsite so a bad night cannot cost weeks of progress. Then the part that makes the bill small: stop the EC2 instance whenever nobody is playing.
Starting it had to be friction-free. The friends already live in Discord, so the start button lives there too. A slash command in the channel, a Lambda behind API Gateway that verifies the Discord signature and calls EC2.startInstances. Click the chip in the demo below to watch the request travel.
- Discord/valheim start
- API GatewayPOST /discord
- Lambdaverify Ed25519, call EC2.start
- EC2pending → running
- Dockervalheim container up
- Server live203.0.113.42:2456
- 30 min idlesystemd stop-instances
One day, one server, no Terraform
A t3a.medium in eu-central-1 (close to the players, x86 because the Valheim image is x86), Elastic IP attached so stop and start cycles do not change the address, an IAM instance role scoped to writing to one S3 bucket and self-stopping. The game runs from ghcr.io/lloesche/valheim-server via docker compose, ports 2456-2458 UDP open, world and backups on a mounted volume.
Backups are layered: the container takes hourly local snapshots, a host-side aws s3 sync runs every 15 minutes through a cron entry, the bucket has a 30-day lifecycle. The auto-stop is a tiny systemd service that polls valheim-is-idle inside the container every 60 seconds and calls aws ec2 stop-instances after 30 idle minutes.
The Discord side is a Node.js 22 Lambda with no third-party dependencies, just the AWS SDK and the built-in crypto module to verify the Ed25519 signature Discord includes on every interaction. API Gateway in front, slash command registered once on the application. No Terraform, no CDK, just a few bash scripts. It is one server. The whole migration, from "can you take a look" to "server is live", took a single Saturday.
Happy friends, ~$8 a month
The friends start the server with a slash command, play, and stop thinking about it. Nobody messages the original host when they want to play. The address never changes, so the saved server entry in their game just keeps working. Backups land in S3 and roll off after a month, hands-off.
With about 15 hours of play a week the bill lands near $8 a month (most of it the Elastic IP and the EBS volume during the idle hours), versus roughly $32 if the same instance ran 24/7. Not a huge engineering project. A small one I am genuinely proud of, because the constraints were real and the result is the kind of thing that just keeps working in the background.
- One-day migration from a friend's desktop to a stable cloud setup
- ~$8/month with sleep-when-idle vs. ~$32/month always-on
- Discord /valheim start wakes the server, signed with Ed25519 and verified in Lambda
- EIP keeps the saved server address stable across stop and start cycles
- Hourly backups inside the container, synced to S3 every 15 minutes with a 30-day lifecycle
