I Built an On‑Demand Minecraft Host on AWS Fargate to Stop Paying Monthly Fees
Source: Dev.to
Introduction
Most Minecraft server hosts have a fundamental flaw: they charge a monthly subscription for a server that sits empty 90 % of the time.
I realized I was paying €20 / month for a server my kids and I only played on for a few hours most weekends. That was the spark for ERGamesPRO – an on‑demand Minecraft hosting platform built on AWS where the goal is simple:
If no one is playing, I shouldn’t be paying.
(By “serverless,” I mean no always‑on compute: no EC2 fleet to patch, and billing for CPU/RAM stops when the server is off. Storage/mission‑control costs remain, but they’re small compared to 24/7 compute.)
The Architecture: Why Fargate?
I chose AWS Fargate (ECS) to get scale‑to‑zero behavior without managing instances.
- Start – Clicking “Start” on the dashboard provisions a fresh Fargate task dedicated to that specific server.
- Stop – Clicking “Stop” terminates the task, and compute cost drops to zero.
High‑Level Stack
| Layer | AWS Service |
|---|---|
| Compute | AWS Fargate (ECS) – Docker containers on ARM64 (Graviton) |
| Storage | Amazon EFS – persistent world data |
| Orchestration/Billing | AWS Lambda + EventBridge |
| Database | DynamoDB – user profiles & server metadata |
| Authentication | Amazon Cognito |
| DNS | Amazon Route 53 – per‑server hostnames |
Stable Join Address (No Load Balancer)
I’m not using an NLB/ALB or Cloud Map. ECS tasks run in public subnets and receive a public IP.
When a server starts, the control plane automatically updates a Route 53 record under the domain ergamespro.click to map a custom hostname (e.g., myserver.ergamespro.click) to that task’s public IP.
- TTL: 60 seconds
- Connection method: Players always connect via the hostname, even though the underlying IP can change on restart.
The “Scale to Zero” Problem
The hardest part of an on‑demand host is knowing when to turn the lights off safely.
I built a reconciliation loop using AWS Lambda + EventBridge:
- Watchdog Lambda runs every few minutes.
- It pings each running server with a TCP‑based Minecraft Server List Ping to read the live player count.
- If player count > 0 → keep the server running.
- If player count = 0 for 10 minutes → trigger a shutdown event.
If the ping fails or times out, the watchdog fails open and retries to avoid false shutdowns. When the shutdown event fires, the Fargate task stops and compute billing ends immediately. For idle‑heavy usage (e.g., weekend sessions), this can reduce costs by ~70–80 % versus 24/7 hosting.
Challenges Along the Way
1️⃣ The 500‑Resource Limit (CDK)
- Problem: Using AWS CDK (Python) I hit CloudFormation’s hard limit of 500 resources per stack.
- Solution: Split the monolith into seven independent stacks (Foundation, Data, Compute, etc.). Deployments became faster, safer, and easier to reason about.
2️⃣ Startup Times & Golden Images
- Problem: Fargate isn’t instant. Pulling a ~1 GB image at runtime adds painful cold‑start latency.
- Solution: Build a pipeline that pre‑bakes “golden images” for each Minecraft version (Vanilla, Paper, Forge) targeting ARM64 (Graviton).
- Graviton is cheaper.
- For typical Java‑based Minecraft workloads it performs extremely well.
Note: Heavily modded servers with 100 + mods may benefit from higher‑clock‑speed x86, but for Vanilla and lighter modpacks, ARM is excellent.
3️⃣ Persistent Storage with EFS
- Problem: Fargate tasks are ephemeral; the container filesystem disappears when a task stops.
- Solution: Use Amazon EFS with dedicated Access Points. Each server gets an isolated directory mounted at
/data, so worlds, configs, and backups persist across restarts.- EFS runs in bursting throughput by default (configurable to Elastic or Provisioned).
- Bursting works great at small scale; provisioned throughput can become cost‑prohibitive, so bursting remains the default.
4️⃣ File Access (SFTP) in an Ephemeral World
- Problem: On a VPS you’d SSH in and upload mods. With Fargate there’s nothing to “SSH into” when the server is stopped.
- Solution: Sidecar pattern – when a user starts a server, launch the Minecraft container alongside an SFTP sidecar.
| Feature | Details |
|---|---|
| Volume | Both containers mount the same EFS volume |
| Service | Locked‑down, chrooted SFTP server |
| Credentials | Generated on the fly, short‑lived |
| Endpoint | Same DNS name, fixed port 2222 |
| Lifecycle | Disappears when the task stops |
Because client IPs are unpredictable, SFTP isn’t source‑IP allowlisted. Access is controlled via the short‑lived credentials and a locked‑down SFTP config, keeping file management convenient without breaking the on‑demand model.
5️⃣ Real‑Time Console Streaming
- Problem: I wanted live logs in the web dashboard. Kinesis Data Streams was too costly for a bootstrapped project.
- Solution: CloudWatch Logs + WebSockets
- Fargate streams logs to CloudWatch Logs.
- A Lambda polls for new entries.
- Updates are pushed to the frontend via API Gateway WebSocket connections.
The delay is ~1–2 seconds – acceptable given the major cost reduction.
The Platform Today
The result feels like a premium host but behaves like a cloud‑native app:
- Start times: ~50–90 s from click to joinable for light servers; ~3–4 min for heavy modpacks.
- Isolation: each server runs in its own Fargate task (no noisy neighbors).
- Cost model: you pay only for the time the server is running.
What’s Next?
- Multi‑region support – deploy closer to players.
- Multiple worlds per server – store several world directories on EFS and let users choose which one to boot.
End of document.
ETA is live at ergames.pro.
I have a few invite codes left for developers and gamers who want to stress‑test the architecture — raw feedback is welcome.
If you want details on the AWS CDK structure, Lambda logic, or Fargate tuning, ask in the comments.
