June 8, 2020
Traditionally, bringing up a Minecraft server involves manually installing all separate components and spending too much time in the command line. Using the Terraform recipe from this blog post we can easily bring up our own server without worrying about the granularities of manual deployment. Not only that, but with a new Google Cloud Platform (GCP) account, you get $300 worth of credits, which will allow you to do this for virtually free.
There are a lot of good reasons to bring up your own Minecraft server. It can serve as a shared digital space for you and your friends to keep in touch, or for your kids/gremlins to jump onto. The limitations of Minecraft Realms (Mojang’s own server solution) such as the low 10-block draw distance and the choice between expensive third-party providers make self-deployment an easy choice.
I will be diverging from several aspects of the original Futurice code by adding a few more twists into it. A 35GB SSD instead of a 20 GB HDD, a non-preemptive instance, and 3 GB of RAM allocated to Minecraft are some examples. I will be using macOS, but will have links for other systems.
GCP will host our infrastructure, which will be comprised of a compute instance with an attached 35 GB SSD. This combination will run Google's container-optimized operating system known as COS (comes with Docker pre-installed). Docker will be pulling and running a Docker Minecraft image in a container using the startup script in our Terraform configuration. We will set up a snapshot schedule which will take automatic snapshots every 24 hours as our backup solution. Finally, we will have a bucket housing our remote .tfstate.
GCP is where we create a project for the resources to live in, a bucket to store the “.tfstate” (more on this later), and an instance we can connect to. The Google Cloud SDK will allow us to interact with GCP from the command line. https://cloud.google.com/compute/docs/regions-zones is a good place to find your closest/default region.
gcloud auth application-default login
Terraform allows you to declaratively provision and manage code. When you run a Terraform configuration for the first time, it creates a ".tfstate" file, which keeps a detailed map of our infrastructure. This includes our instance network information, our disk ID, and anything else Terraform provisions. The ".tfstate" file acts as a record of the infrastructure at the time of provisioning.
Every subsequent run of the configuration file will check the real infrastructure before committing any changes. If we add another instance to our configuration file, then Terraform will refresh the ".tfstate" with the new real infrastructure (which includes all our old resources + our additional instances.)
This also means that if you create a small change in your configuration file, then only that change will be committed rather than your whole configuration file. Our ".tfstate" file will be stored remotely in the bucket we created earlier.
terraform {
backend "gcs" {
prefix = "minecraft/state"
bucket = "<BUCKET_NAME>"
}
}
This is where remote state path is laid
locals {
project = "<PROJECT_ID>"
region = "<REGION>"
zone = "<REGION>"
}
resource "google_compute_disk" "minecraft" {
name = "minecraft-disk"
type = "pd-ssd"
size = 35
zone = local.zone
image = "cos-cloud/cos-stable"
}
metadata_startup_script = "docker run -e EULA=TRUE -e MEMORY=3G -d -p 25565:25565 -v /var/minecraft:/data --name mc itzg/minecraft-server:latest;"
The important part here is that we're allocating 3 GB of memory for Minecraft to use
scheduling {
preemptible = false # True closes within 24 hours
automatic_restart = false
}
terraform init
terraform apply
Now go back to https://console.cloud.google.com/compute/ and watch as your instance is initialized. There are handy performance-metrics you can view by clicking "SHOW INFO PANEL" on the top right side. From here you can also connect to the instance by clicking on SSH. The external IP is what you and your friends will use to connect to your Minecraft session.
The steps above will generate a new world, but we can import our own existing world. Skip this section if you want to start with a new world.
tar -czvf newworld.tar.gz "<YOUR_WORLD>"
gcloud compute scp "<YOUR_WORLD.TAR.GZ>" minecraft:~
sudo su
Run this whenever you open a new SSH session
tar -xvf "<YOUR_WORLD.TAR.GZ>"
mkdir -p /var/minecraft/myworld && cp -R "<YOUR_WORLD>" /var/minecraft/
cd /var/minecraft
nano server.properties
level-name=world
to level-name="<YOUR_WORLD>"
chown -R chronos:chronos "<YOUR_WORLD>"
docker stop mc
docker ps -al
chown -R chronos:chronos "<YOUR_WORLD>"
docker start mc
docker logs -f mc
Container logs are vital to troubleshooting any issues that might arise
This post is already long, and there's so much more you can do with this framework. I suggest checking out the original blog post and attached Google Doc for more ways to customize your experience. Different disk sizes, machine types, operating systems ("debian-cloud/debian-9"
instead of "cos-cloud/cos-stable"
), keeping preemptive on, giving permission to friends to turn the server on etc. There's a lot of fun stuff to play around with here.