MCPcopy
hub / github.com/doctorray117/minecraft-ondemand

github.com/doctorray117/minecraft-ondemand @main sqlite

repository ↗ · DeepWiki ↗
26 symbols 51 edges 10 files 1 documented · 4%
README

minecraft-ondemand

Almost free serverless on-demand Minecraft server in AWS

Table of Contents

Quick Start

Too much text for you? Click the cdk folder in the source above for a fast and relatively-automated walkthrough.

Background

Instead of paying a minecraft hosting service for a private server for you and your friends, host it yourself. By utilizing several AWS services, a minecraft server can automatically start when you're ready to use it, and shut down when you are done. The final cost will depend on use but can be as little as a a dollar or two per month. The cost estimate breakdown is below.

This is a reasonably cost effective solution for someone that doesn't need their server running 24/7. If that's you, read on!

Workflow

The process works as follows:

  1. Open Minecraft Multiplayer, let it look for our server, it will time out.
  2. The DNS lookup query is logged in Route 53 on our public hosted zone.
  3. CloudWatch forwards the query to a Lambda function.
  4. The Lambda function modifies an existing ECS Fargate service to a desired task count of 1.
  5. Fargate launches two containers, Minecraft and a watchdog, which updates the DNS record to the new IP
  6. The watchdog optionally sends a text message through Twilio and/or publishes to an SNS topic when the server is ready.
  7. Refresh Minecraft server list, server is ready to connect.
  8. After 10 minutes without a connection or 20 minutes after the last client disconnects (customizable) the watchdog sets the desired task count to zero and shuts down.

Diagram

Basic Workflow

Requirements

  • AWS Account
  • Domain name with public [DNS served from Route 53]. Does not need to be registered through Route 53.
  • Minecraft Java edition OR Bedrock edition client
  • Use of the excellent [Minecraft Java Docker] or [Minecraft Bedrock Docker] server image (used within task definition, no direct download required)

Cost Breakdown

  • Link to [AWS Estimate] assuming 20 hours a month usage.
  • tl;dr : $0.50 per month for DNS zones, $0.0149 (one point five cents) per hour for Fargate Spot or $0.049 (four point nine cents) per hour for regular Fargate. All other costs negligible, a couple of pennies per month at most.
  • tl;dr;tl;dt : $1.50 / month for 20 hours of play.

Installation and Setup

For a quick start, a Cloud Deployment Kit (CDK) implementation is available! Click on the cdk folder in the source for the instructions. The documentation will be refined soon to expand on this to help novice users. What follows is a manual walkthrough that anyone should be able to complete.

Checklist of things to keep track of

To simplify the procedure, your ECS cluster name, service name, and sns topic name need to be defined before you start. This is because we will be referencing them before they are created. In the documentation I use these:

  • Cluster name : minecraft
  • Service name : minecraft-server
  • SNS Topic : minecraft-notifications

Things you need to go find because they'll be used in the procedure are:

  • AWS Account ID. This is a 12 digit number (at least mine is). [Finding your AWS account ID]. Put this in the IAM policies where I've put zzzzzzzzzzzz
  • Hosted Zone ID. This is a variable length string tied to your domain name in the Route 53 console.
  • VPC IPv4 CIDR. It looks like (and very well may be) 172.31.0.0/16. Find it by opening the VPC console, tapping on Your VPCs and looking in the IPv4 CIDR column.

Things you will locate as you go along and will need during IAM policy creation:

  • EFS File System ID
  • EFS Access Point ID

Region Selection

While it doesn't matter which region you decide to run your server in, Route 53 will only ship its logs to us-east-1, which in turns means that the lambda function also has to be in us-east-1. This lambda function can fire off the server in another region without issue, as long as the destination region is specified within the lambda function code. For the purposes of this documentation, I'm using us-west-2 to run my server.

Double check the region in anything you're copy/pasting.

VPC

A VPC with Subnets must exist in order for Fargate tasks to launch and for EFS shares to be mounted. A subnet should exist in each availability zone so that Fargate (and Fargate Spot, if used) can properly launch the tasks in an AZ with plenty of capacity. A security group for our task is required but is easiest configured when setting up the Task Definition below.

A [Default VPC] should do the trick, chances are you've already got one. We'll be modifying the default security group within the EFS setup below.

Elastic File System

EFS is where the world data and server properties are stored, and persists between runs of the minecraft server. By using an "Access Point" the mounted folder is created automatically, so no mounting of the EFS to an external resource is required to get up and running. To make changes to the files like server.properties later however, a user can either mount the EFS file system to a Linux host in their account if they're comfortable with that, or I detail another method below using AWS DataSync and S3 that anyone can use without Linux experience.

Creating the EFS

Open the Elastic File System console and create a new file system. Believe it or not, all the defaults are fine here! It will create an EFS available in each subnet within your VPC.

Select your newly created filesystem, and tap the Access Points tab. Create a new access point using the following specifics:

  • Details
  • Root directory path : /minecraft
  • POSIX User
  • User ID : 1000
  • Group ID : 1000
  • Root directory creation permissions (this is required, otherwise our container won't be able to create the folder to store its data the first time)
  • Owner user ID : 1000
  • Owner group ID : 1000
  • POSIX Permissions : 0755

Click Create access point. Record the File System ID and the Access Point ID for our checklist. They are in the format fs-xxxxxxxx and fsap-xxxxxxxxxxxxxxxxx respectively.

Allow access to EFS from within the VPC

Our EFS by default is assigned the default security group, which allows connections from all members of that default security group. Our ECS Service will not be using the default security group however, because we are opening Minecraft to the public internet. So, we need to add EFS access to the default security group (more advanced users may want to create a new dedicated security group with this rule and assign it to the mount points within the EFS console, however that will not be described here).

Open the VPC console, find Security Groups on the left hand side. Select the default security group in the list, then click on Edit inbound rules. Add a new rule, select NFS in the Type list and put your VPC IPv4 CIDR from your checklist as the source. After clicking Save rules double check that it added successfully by viewing it in the Security Groups detail pane.

Lambda

A lambda function must exist that turns on your minecraft service. We do this with a simple python function that change the "Tasks Desired" count from zero to one when it is invoked. We haven't created the ECS service yet, but that's okay, because we decided on the cluster name and service name before we started.

Because we are relying on Route 53+CloudWatch to invoke the Lambda function, it must reside in the N. Virginia (us-east-1) region.

From the Lambda console, create a new function using Author from scratch. I've used Python 3.9 but the latest version available should be fine. Call it minecraft-launcher. The other defaults are fine, it will create an IAM role we will modify afterward. We do not need to specify a VPC.

Once the function has been created and you're in the code editor, replace the contents of the default lambda_function.py with this:

import boto3

REGION = 'us-west-2'
CLUSTER = 'minecraft'
SERVICE = 'minecraft-server'


def lambda_handler(event, context):
    """Updates the desired count for a service."""

    ecs = boto3.client('ecs', region_name=REGION)
    response = ecs.describe_services(
        cluster=CLUSTER,
        services=[SERVICE],
    )

    desired = response["services"][0]["desiredCount"]

    if desired == 0:
        ecs.update_service(
            cluster=CLUSTER,
            service=SERVICE,
            desiredCount=1,
        )
        print("Updated desiredCount to 1")
    else:
        print("desiredCount already at 1")

This file is also in this repository in the lambda folder. Change the region, cluster, or service on lines 3-5 if needed. Then, click the Deploy button. Switch back to your server region now so that we don't create anything in the wrong region later.

Lambda can be very inexpensive when used sparingly. For example, this lambda function runs in about 1600ms when starting the container, and in about 500ms if the container is already online. This means, running at a 128MB memory allocation, it will cost $0.00000336 the first time the server is launched from an off state, and about $0.00000105 every time someone connects to an online server, because anyone connecting will have to perform a DNS lookup which will trigger your lambda function. If you and four friends played once a day for a month, it would come out to $0.0002583, which is 2.6% of a single penny.

Route 53

Ensure that a domain name you own is set up in Route 53. If you don't own one, consider registering one. You can use Route 53 for convenience or go to one of the big domain providers. Either way, ensure you've got your nameservers set to host out of Route 53 as it's required for the on-demand functionality.

Server DNS Record

Add an A record with a 30 second TTL with a unique name that you will use to connect to your minecraft server. Something like minecraft.yourdomainname.com, or more complex if desired, as every time anyone in the world performs a DNS lookup on this name, your Minecraft server will launch. The value of the record is irrelevant because it will be updated every time our container launches. Use 1.1.1.1 or 192.168.1.1 for now if you can't think of anything. The low TTL is so that the DNS clients and non-authoritative DNS servers won't cache the record long and you can connect quicker after the IP updates.

Query Logging

The magic that allows the on-demand idea to work without any "always on" infrastructure comes in here, with Query logging. Every time someone looks up a DNS record for your domain, it will hit Route 53 as the authoritative DNS server. These queries can be logged and actions performed from them.

From your hosted zone, click Configure query logging on the top right. Then, click Grant Permission so that it will apply appropriate policies for queries to be logged. Finally, in Log group select Create log group and use the suggested name with your domain name in the string, /aws/route53/yourdomainname.com and click Create.

Optional SNS Notifications

You can receive a text or email or anything else you want to consume via Amazon SNS, if Twilio isn't your thing. This also allows this to be a 100% AWS solution.

From the SNS console, create a Standard topic called minecraft-notifications. Also at your convenience, create a Subscription to the topic to a destination of your choice. Email is easy and free, SMS is beyond the scope of this documentation but there's plenty of resources out there to help you set it up.

IAM

The IAM Console is where we configure the roles and policies required to give access to the Task running the Minecraft server and the Lambda Function used to start it.

We will be creating four distinct policies and one role. The policies will then be attached to the appropriate roles.

Policies

EFS Policy

This policy will allow for read/write access to our new Elastic File System Access Point. In the policy below, replace the zzz's with your account id and put your file system and access point id in the appropriate places. Change the region if necessary.

Call this policy efs.rw.minecraft-data

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "elasticfilesystem:ClientMount",
        "elasticfilesystem:ClientWrite",
        "elasticfilesystem:DescribeFileSystems"
      ],
      "Resource": "arn:aws:elasticfilesystem:us-west-2:zzzzzzzzzzzz:file-system/fs-xxxxxxxx",
      "Condition": {
        "StringEquals": {
          "elasticfilesystem:AccessPointArn": "arn:aws:elasticfilesystem:us-west-2:zzzzzzzzzzzz:access-point/fsap-xxxxxxxxxxxxxxxxx"
        }
      }
    }
  ]
}

ECS Policy

This policy will allow for management of the Elastic Container Service tasks and service. This lets the Lambda function start the service, as well as allows the service to turn itself off when not in use. The ec2:DescribeNetworkInterfaces section is so that the task can determine what IP address is assigned to it to properly update the DNS

Extension points exported contracts — how you extend this code

SSMParameterReaderProps (Interface)
(no doc)
cdk/lib/ssm-parameter-reader.ts
DomainStackProps (Interface)
(no doc)
cdk/lib/domain-stack.ts
MinecraftStackProps (Interface)
(no doc)
cdk/lib/minecraft-stack.ts
CWGlobalResourcePolicyProps (Interface)
(no doc)
cdk/lib/cw-global-resource-policy.ts
TwilioConfig (Interface)
(no doc)
cdk/lib/types.ts

Core symbols most depended-on inside this repo

getParameterValue
called by 2
cdk/lib/ssm-parameter-reader.ts
stringAsBoolean
called by 2
cdk/lib/util.ts
resolveMinecraftEnvVars
called by 1
cdk/lib/config.ts
resolveConfig
called by 1
cdk/lib/config.ts
isDockerInstalled
called by 1
cdk/lib/util.ts
getMinecraftServerConfig
called by 1
cdk/lib/util.ts
lambda_handler
called by 0
lambda/lambda_function.py
constructor
called by 0
cdk/lib/ssm-parameter-reader.ts

Shape

Class 8
Interface 7
Function 6
Method 5

Languages

TypeScript96%
Python4%

Modules by API surface

cdk/lib/ssm-parameter-reader.ts5 symbols
cdk/lib/minecraft-stack.ts4 symbols
cdk/lib/domain-stack.ts4 symbols
cdk/lib/cw-global-resource-policy.ts4 symbols
cdk/lib/util.ts3 symbols
cdk/lib/types.ts3 symbols
cdk/lib/config.ts2 symbols
lambda/lambda_function.py1 symbols

Dependencies from manifests, versioned

@types/jest26.0.10 · 1×
@types/node10.17.27 · 1×
aws-cdk-lib2.89.0 · 1×
constructs10.0.0 · 1×
dotenv10.0.0 · 1×
execa5.1.1 · 1×
source-map-support0.5.16 · 1×
ts-node9.0.0 · 1×
typescript3.9.7 · 1×

For agents

$ claude mcp add minecraft-ondemand \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact