Run a Minecraft server on AWS without paying to leave it running all the time. Friends can sign in, check the server status, and start it when they want to play.
Monitor |
Manage |
Budget |
Backup |
- Web panel for start, stop, resume, and hibernate
- Google sign-in with admin and allowed-user roles
- Optional Minecraft DNS: Cloudflare, free DuckDNS, or raw public IP mode
- Backup and restore with Google Drive
- Optional CLI commands
Most Minecraft hosting is priced like you are going to use the server all month. If you only play occasionally, that means paying for a box that sits idle most of the time.
Self-hosting at home avoids the monthly bill, but it creates a different problem: if your friends want to play, you either leave the server running all the time or you have to be around to start it.
This project is the middle path. The server runs on AWS, friends can start it from the control panel, and the instance can shut down when nobody is playing.
The cost model is different from a flat monthly host:
| State | What You Pay For | Rough Cost |
|---|---|---|
| Hibernated | No EC2 compute, no attached EBS volume | $0.00/month for server compute/storage |
| Stopped | EBS volume remains attached | about $0.75/month for an 8 GB GP3 volume |
| Running | EC2 compute while people play | about $0.03-0.04/hour for the default instance class |
If you play for 8 hours in a month and hibernate the rest of the time, the server compute cost is measured in cents, not a fixed monthly fee. Exact pricing depends on region, instance type, storage size, backups, and AWS pricing changes.
On-demand providers like Exaroton or ServerWave can be a better fit if you want less setup. They are easier to use and have their own feature sets. The reason to use this project is not just penny-level savings. The reason is control.
You own the infrastructure. You can change the instance size, replace the backup flow, add plugins, edit the startup scripts, build a Discord or web portal, add custom scheduled behavior, wire in AWS services, or extend the CDK stack however you want.
That matters more now that AI can do a lot of the glue work. You can ask an agent to add a new admin route, generate a plugin workflow, change the deploy stack, add a custom automation, or build a small portal around your server without waiting for a hosting provider to expose that feature.
You are not at the whim of a provider's dashboard, pricing model, plugin support, or product roadmap. It is your server and your hosting platform.
Complete these first. These are very common and well-documented paths, so ask your AI to help you if you get stuck:
Optional:
- Set up a Cloudflare-managed domain, if you want a custom Minecraft hostname
- Set up DuckDNS, if you want a free Minecraft hostname
- Create an EC2 key pair, if you want SSH key access
- Configure SES email features, if you want email-triggered actions and notifications
- Configure Google Drive backups, if you want backup, restore, and hibernate workflows
After the prerequisites are done, run the setup script from your fork:
git clone https://github.com/<you>/mc-aws.git
cd mc-aws
bash ./setup.shThe script installs the project toolchain, collects credentials, deploys AWS infrastructure, writes deployment outputs, and deploys the web app to Cloudflare.
For the Minecraft connection address, setup supports three modes:
- Cloudflare custom domain: friends connect to
mc.example.com. - DuckDNS free subdomain: friends connect to
myserver.duckdns.org. - No-domain mode: friends connect to the public IP shown in the panel.
For the full walkthrough, use Setup and Run.
Use mock mode if you want to work on the app without AWS:
pnpm install
pnpm dev:mockOpen http://localhost:3000/api/auth/dev-login to sign in as a local admin.
More detail:
The web app is the primary interface. It handles:
- Server status, health, and player visibility
- Start, stop, resume, and hibernate operations
- Backup, restore, and backup listing
- Cost views and email allowlist management
- Admin shortcuts for common operations
Roles:
ADMIN_EMAIL: full accessALLOWED_EMAILS: can check status and start- Other signed-in users: status-only
start: starts the server in the normal pathstop: stops the instance but keeps storage attachedhibernate: backs up the server, stops the instance, and deletes attached instance volumesresume: recreates storage and brings a hibernated server back online
Use stop for shorter pauses. Use hibernate when the server will be idle long enough that you want to avoid EBS storage cost too.
Hibernate is intentionally destructive. Resume reconstructs the root volume from the instance's own source AMI metadata. If that metadata cannot be resolved, resume fails instead of guessing.
Backup and restore use Google Drive.
If Google Drive is not configured, backup, restore, and hibernate flows are not useful. Configure it during setup or from the web panel before relying on those operations.
See Operations Guide for day-to-day backup, restore, and recovery notes.
The CLI is optional. It calls the app API and defaults to http://localhost:3000/api.
pnpm server:status
pnpm server:start
pnpm server:stop
pnpm server:resume
pnpm server:hibernate
pnpm server:backup
pnpm server:backups
pnpm server:restore -- <backup-name>To point it at another panel API:
API_BASE=https://panel.yourdomain.com/api pnpm server:statusAdvanced shell access:
./bin/connect.sh
./bin/console.shFor app updates:
pnpm deploy:cfFor infrastructure changes:
pnpm cdk:diff
pnpm cdk:deployThis can reduce idle cost compared with leaving a server running all the time, but it does not make AWS free.
stopstops compute, but attached EBS storage still costs moneyhibernateremoves attached instance volumes after backup, so it is better for longer idle periods- Cloudflare, AWS, Google, and GitHub setup are still your responsibility
- Check AWS Billing and Cost Explorer after deployment, especially while testing
Setup:
- Fork this repo
- Create a GitHub token
- AWS account setup
- Cloudflare setup
- Google OAuth setup
- Setup and Run
Operations:
Development:
- Run
aws sts get-caller-identityand confirm AWS CLI access works - Check
.env.productionfor missing values - Re-run
bash ./setup.sh
- Add the exact callback URLs in Google Cloud
- Make sure
NEXT_PUBLIC_APP_URLmatches the deployed panel URL
- Use Wrangler OAuth for deployment auth
- Keep
CLOUDFLARE_DNS_API_TOKENfor runtime DNS updates only - Do not export the DNS token globally in your shell




