This project deploys a secure, Minecraft server using a Hybrid Cloud Architecture.
Game Server: Runs locally, dockerized on your hardware.
Gateway: Runs on a cheap AWS Lightsail instance (provisioned with Terraform).
Tunnel: Traffic is securely tunneled (FRP) from the Cloud to your local.
graph LR
User([Minecraft Client]) -- 1. Resolve Domain --> DNS[DuckDNS Service]
DNS -- 2. Return Static IP --> User
subgraph AWS [AWS Lightsail Gateway]
IP[Static IP]
FRP_S[FRP Server :7000]
FW[Lightsail Firewall :25565]
end
User -- 3. Connects to IP:25565 --> FW
FW --> FRP_S
subgraph Home [Home Server / Docker]
FRP_C[FRP Client]
MC[Minecraft Server :25565]
DDNS[DuckDNS Container]
end
FRP_S <== 4. Encrypted Tunnel ==> FRP_C
FRP_C --> MC
DDNS -- 5. Updates IP if changed --> DNS
- Provides DDoS protection via AWS.
- Low cost (uses cheap cloud compute only for traffic forwarding).
- Hides your home IP address.
- Portable config (Infrastructure as Code).
cloud/ - Terraform code to provision the AWS Lightsail Gateway.
local/ - Docker Compose files to run the Minecraft Server & Tunnel Client.
local/config-overrides/ - Game configuration (Whitelists, MOTD, etc.) & additional mods
Terraform Installed: sudo apt install terraform
AWS CLI Installed: sudo apt install awscli
Docker & Compose: Installed on your local machine.
DuckDNS Account: A domain (e.g., myserver.duckdns.org) and a Token.
AWS IAM User: With LightsailFullAccess permissions.
Custom IAM Policy - LightsailFullAccess
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["lightsail:*"],
"Resource": "*"
}
]
}- Configure credentials - Create a (preferably, named) profile for Terraform to use.
aws configure --profile terraform-lightsailRegion: eu-west-2 (or your preference) Output: json 2. Configure Terraform variables - Create your secret variables file.
cp cloud/terraform.tfvars.template cloud/terraform.tfvarsEdit cloud/terraform.tfvars and add your DuckDNS Token and Domain.
- Deploy Infrastructure - Terraform will provision the server, install Docker, and start the tunnel server.
cd cloud
terraform init
terraform applyVerify: The public_ip output matches the IP on your DuckDNS dashboard.
Note: Terraform generates an SSH key (id_rsa.pem) in the cloud/ folder. Keep this private.
- Configure Secrets - set up the tunnel client authentication.
cd local
cp .env.template .envEdit .env to match the tokens used in Terraform.
- Configure Game Rules & Whitelist - We use split configuration to keep secrets out of Git.
local/config-overrides/minecraft-public.env: (Commit this) Game rules, MOTD, Difficulty.
local/config-overrides/minecraft-private.env: (GitIgnored) Whitelist, Ops, Sensitive settings.
- Start the Server
docker-compose up -dCheck Logs: docker-compose logs -f
Wait for: Done! (Server Ready) and [ssh] start proxy success (Tunnel Ready).
How to Connect Server Address: your-domain.duckdns.org
Port: Default (25565) - No port number needed in client.
Terraform generates a keypair automatically. To debug the cloud server:
cd cloud
ssh -i id_rsa.pem ubuntu@$(terraform output -raw public_ip)Do not use in-game commands like /whitelist add as they will be overwritten on restart.
Edit local/config-overrides/minecraft-private.env.
Add names to OPS= or WHITELIST=.
Apply changes:
docker-compose up -dSwitching from one modpack to another (e.g., Vanilla to All The Mods) requires clearing old mod files while preserving your world data.
Stop the server
docker-compose downUpdate configuration - edit your docker-compose.yml (or your .env file if you used variables) to point to the new pack.
e.g. CF_SLUG=better-mc-forge-bmc4 => CF_SLUG=all-the-mods-9. (Verify java version for the docker image in local/docker-compose.yml) DATA_FOLDER=bmfb4 => atm9
Backups are automatically generated by the backup container and stored in local/backups/.
- Stop the server
docker-compose down- Locate the backup
cd local/backups
ls -lhExample file: 2026-02-08_12-00-00.tgz
- Move or delete the current world folder to prevent file conflicts.
cd ../minecraft-data
mv world ../corrupted/OR
sudo rm -rf world- Extract the backup
# Adjust the filename below to match your backup
sudo tar -xzvf ../backups/2026-02-08_12-00-00.tgz -C .- Fix permissions - Files extracted via sudo are owned by root. The Minecraft container runs as a specific user (UID 1000) and will crash if it cannot read them.
sudo chown -R 1000:1000 .- Restart server
cd ..
docker-compose up -d"Connection Refused": Check if the Tunnel is up (docker-compose logs frpc).
"Unknown Host": DNS propagation lag. Wait 5 mins or try the raw IP.
Wrong IP in DuckDNS/Lightsail: Run terraform apply again to force an update.