Welcome to my small, but humble Terraform module for a Minecraft server, hosted in Google Cloud Platform!
- Overview
- How to Use
- Terraform Configuration
- General Server Management
- Modded Server Management
- Troubleshooting
- Future Goals
- Inspiration
This project helps streamlines a majority of the steps needed to take when creating a new multiplayer Minecraft Server. Below describes what this Terraform Module creates:
- One GCE instance
- Assigned the default service account that is scoped to Read Only for Compute API and Read Write to Cloud Storage.
- Provided metadata scripts for bootstrapping and shutting down.
- Provided SSH keys to allow access to one outside user
- One persistent SSD to store the Minecraft Server Data
- A custom Network with one Subnetwork
- Firewall rules in the network to only allow specific traffic to:
- 22
- 25565
- icmp
- Ability to add additional TCP/UDP port(s) within the range 49152 to 65535.
- A Cloud Storage Bucket (Two if making a modded MC Server or using Cloud Functions)
- Two Cloud Functions to allow anyone to start/stop the MC Server via curl or Browser
The overall cost to run this project varies greatly with usage and instance size, but it should be fairly minimum if using the project defaults and turning off the instance when no one is playing.
Name | Version |
---|---|
terraform | > 0.12 |
archive | >= 2.2.0 |
>= 3.60.0 | |
random | >= 3.1.0 |
template | >= 2.2.0 |
Name | Version |
---|---|
archive | >= 2.2.0 |
>= 3.60.0 | |
random | >= 3.1.0 |
template | >= 2.2.0 |
- A Google Account (GCP has a free credit sytem where all acccounts can get $300 worth of usage)
terraform
CLI tool, whicch can be gotten here- Some light knowledge of Linux, GCP and Terraform
- Some familiarity with Minecraft server hosting
- Sign into your Google account and log into GCP
- Create a new project and remember the
project_id
that GCP assigns it. - In that new project, create a new service account (
IAM & Admin -> Service Accounts
)- Name the account to whatever you desire
- For the Role, specify
Owner
- Once done, navigate to that new service account and select
Keys -> Create New Key -> JSON
- Save this key in a secure location on your computer (I recommend
~/.ssh
).
Be careful with that key! It has admin API access to your entire GCP account, meaning anything can be deployed in GCP using said key. More savy GCP users can use a role that is less wide in scope for this project, but for the sake of this walkthrough, you can proceed with these permissions.
- Enable the following APIs in the GCP Console:
Compute Engine API
(Required)Cloud Storage API
(Required)IAM Service Account Credentials API
(Only if using Cloud Functions)Cloud Build API
(Only if using Cloud Functions)
- Create a Terraform directoty, using this example as a basis. Make sure to keep these in mind:
- Change the project name in
main.tf
if you are not using the project name in there. - Create a
terraform.tfvars
and define the following values:creds_json
ssh_pub_key_file
game_whitelist_ips
admin_whitelist_ips
- (Optional) Configure the initial settings of the
server.properties
in theserver_properties.tpl
- (Optional) Toggle if this server is a modded one or not via
is_modded
.
- Change the project name in
- Run
terraform init
- Run
terraform plan
(should get 10 new resources created) and it it looks good,terraform apply
- Sit back for a few mins and your new Minecraft Server should be running at the
ip_address
theterraform apply
outputs!
If one made
is_modded = true
, there are a few additonal steps needed to be done. Refer to Modded Server Management for those steps.
Name | Description | Type | Default | Required |
---|---|---|---|---|
admin_whitelist_ips | The IPs to allow for SSH and ping access, generally reseved for operational work/troubleshooting. If existing_subnetwork_name is specified, this will be ignored. | list(string) |
n/a | yes |
backup_cron | How often will the backups run on the instance? This must be written in cron syntax. Defaults to once a week on Sats at 3AM | string |
"0 3 * * 6" |
no |
backup_length | How many days will a backup last in the bucket? | number |
5 |
no |
creds_json | The absolute path to the credential file to auth to GCP. This needs to be associated with the GCP project that is being used | string |
n/a | yes |
disk_size | How big do you want the SSD disk to be? Defaults to 50 GB | string |
"50" |
no |
enable_cloud_func_management | Do we want to allow for two Cloud Functions to be created to allow anyone to start/stop the MC Server via HTTP request? Default to false. | bool |
false |
no |
existing_subnetwork_name | An existing subnetwork to leverage placing the instances. Assumes that the firewalls in the subnetwork are already configured. | string |
"" |
no |
extra_tcp_game_ports | Extra TCP ports to open on the MC instance. Note that these should be in the range of 49152 to 65535. | list(string) |
[] |
no |
extra_udp_game_ports | Extra udp ports to open on the MC instance. Note that these should be in the range of 49152 to 65535. | list(string) |
[] |
no |
game_whitelist_ips | The IPs used to connect to the Minecraft server itself through the MC client. If existing_subnetwork_name is specified, this will be ignored. | list(string) |
n/a | yes |
gcp_project_id | The Google Compute Platform Project ID. This is the ID of the project that your infrastructure is deployed under. | string |
n/a | yes |
is_modded | Is this Minecraft server modded? Defaults to false. | bool |
false |
no |
machine_type | The type of machine to spin up. If the instance is struggling, it might be worthwhile to use stronger machines. | string |
"n1-standard-2" |
no |
mc_forge_server_download_link | The direct download link to MC forge for modding support. Defaults to version 1.16.5. | string |
"https://files.minecraftforge.net/maven/net/minecraftforge/forge/1.16.5-36.1.0/forge-1.16.5-36.1.0-installer.jar" |
no |
mc_home_folder | The location of the Minecraft server files on the instance | string |
"/home/minecraft" |
no |
mc_server_download_link | The direct download link to download the server jar. Defaults to a link with 1.16.5. | string |
"https://launcher.mojang.com/v1/objects/35139deedbd5182953cf1caa23835da59ca3d7cd/server.jar" |
no |
override_server_activate_cmd | Should the bootstrap use a different server command than java -Xms server_min_ram -Xmx server_max_ram -jar /home/minecraft/server.jar nogui? If left blank, uses said default command | string |
"" |
no |
project_name | The name of the project. Not to be confused with the project name in GCP; this is moreso a terraform project name. | string |
"mc-server-bootstrap" |
no |
region | The region used to place these resources. Defaults to us-west2. | string |
"us-west2" |
no |
server_image | The boot image used on the server. Defaults to ubuntu-1804-bionic-v20191211 |
string |
"ubuntu-1804-bionic-v20191211" |
no |
server_max_ram | The maximum amount of RAM to allocate to the server process | string |
"7G" |
no |
server_min_ram | The minimum amount of RAM to allocate to the server process | string |
"1G" |
no |
server_property_template | The file path used to parse the server property file for the MC server. Defaults to the standard one in the module | string |
"./templates/server_properties.tpl" |
no |
server_world_name | The name of the world that the server will be using. By default, this is just world. | string |
"world" |
no |
ssh_pub_key_file | The SSH public key file to use to connect to the instance as the user specified in ssh_user | string |
n/a | yes |
ssh_user | The name of the user to allow to SSH into the instance | string |
"iamall" |
no |
zone_prefix | The zone prefix used for deployments. Defaults to 'a'. | string |
"a" |
no |
Name | Description |
---|---|
cloud_funcs_http_triggers | The URLs that correspond to the Cloud Functions, if created |
created_subnetwork | The name of the created subnetwork that was provisioned in this module. Can be used to provision more servers in the same network if desired |
ext_bucket_name | The name of the Cloud Storage Bucket used to hold any persistent MC data. |
server_ip_address | The ephimeral public IP address used to access this instance. |
While most of the configuration has verbose descriptions, there are some options that have a bit more complexity:
Terraform Variable | Notes |
---|---|
machine_type |
Depending on what you use, this can greatly affect the price of running this. The most cost effective, N1 should be the one you want to use, unless your server will be hostin a massive amount of players. |
game_whitelist_ips |
To ban/allow players into the game, it is handled on the infrastructure level. As such, make sure to get your friend's IPs and place them in here, so they can acces this instance! |
admin_whitelist_ips |
This should only be restricted to the person that is administrating this server. Not correlated to admin power in Minecraft; this is moreso system admin access |
mc_server_download_link |
One easy way to get different versions of Minecraft can be gotten at this link. Just find the right server version, right click on the download URL and save it, placing it in this value. |
mc_forge_server_download_link |
There are a multitude of mod loaders for MC, which would make this project rise in complexity. For simplicity sake, the project supports MC Forge as the mod loader of choice. Any other one is not supported. |
server_property_template |
This could change consistenty in the server, making it tricky to keep track of in this code. As such, any new changes made after the initial deployment of the server will NOT be reflected in code. To use a new config if one changed it outside of the server, one must manually go onto the instance and edit the config to match what is down in code. |
existing_subnetwork_name |
This allows for multiple instances of this module to be deployed in the same network, for easier management. To properly use this, make sure one module of this stack is deployed, with the other module calls referencing the created_subnetwork output of the first module. |
override_server_activate_cmd |
There is a slight change in the logic for bootstrapping Forge in 1.18, specifically with the nonexistance of the server jar to run after installing Forge. Instead, they change running the command to just a bash script, run.sh . This needs to be reflected in the command, hence this variable. |
enable_cloud_func_management |
By default, only those who have SSH access to the server and/or GCP console can turn off/on the server. However, when this is set to true , the module outputs two URLs that allow anyone to turn off/on the instance by visiting said link. |
By default, rebooting and respinning up an instance will automatically set up the Minecraft Server for you. Backups of your world are auto created when the server is terminated. No need for any action on your part!
However, if needed, the following server actions can be performed:
- Stopping the Server
/home/minecraft/scripts/stop.sh
(default location)- Stops the Minecraft server (not the instance)
- Ex:
$ cd /home/minecraft/scripts && sudo ./stop.sh
- Ex:
- To start up the Minecraft server again, run the
restart.sh
script
- Stops the Minecraft server (not the instance)
- Restarting the Server
/home/minecraft/scripts/restart.sh
(default location)- Restarts the Minecraft server (not the instance)
- Ex:
$ cd /home/minecraft/scripts && sudo ./restart.sh
- Ex:
- Restarts the Minecraft server (not the instance)
- Backup World
/home/minecraft/scripts/backup.sh
(default location)- Pushes up current state of server to Cloud Storage Buckets.
- Ex:
$ cd /home/minecraft/scripts && sudo ./backup.sh
- Ex:
- This script will also be triggered automatically by a cronjob. By default it runs once a week on Sat at 3AM.
- Pushes up current state of server to Cloud Storage Buckets.
- Restore To Backup
/home/minecraft/scripts/restore_backup.sh
(default location)- Restores the server world to the specified state
- Ex:
$ cd /home/minecraft/scripts && sudo ./restore_backup.sh nameOfBackup
- Ex:
- Restores the server world to the specified state
If enable_cloud_func_management
is set to true
, anyone with the outputted URLs that the module outputs at cloud_funcs_http_triggers
can turn off/on the instance. This can be helpful if one wants to give more control to the players on when to play/stop playing.
NOTE: By setting
enable_cloud_func_management
to true, you are RESPONSIBLE for making sure that those URLs are not misused. Please be wary of that.
There is also a python script called toggle_gcp_instance
, that can be invoked manually to help automate instance shutoff/startup. Refer to it here for more details.
Along with all of the features/scripts mentioned in the General Server Management, there are a few extra steps that need to happen before the server is completly ready.
- Once the server is done bootstrapping (easiest is to tail the logs for the MC server in
/home/minecraft/logs
), placce the mods that you want to use in the provided Cloud Storage Bucket (should have the suffix,ext
at the end.)- Make sure these mods are placed in the
mod
prefix in the bucket (i.e.bucketName/mods/modName.jar
)
- Make sure these mods are placed in the
- SSH into the server and navigate to the
scripts
directory (defaults at/home/minecraft/scripts
) and run the following script:
sudo ./mod_refresh.sh
- Once that is done, wait for a few moments as the MC server restarts up.
For the mods to show up on player's screen, they all need to have that mod installed (unless it is a server side mod)!
As mentioned previously, all modded servers have an additional script located in the script
directory:
- Syncronize Mods
/home/minecraft/scripts/mod_refresh.sh
(default location)- Syncs up the
mods
folder on the instance to match the current state of the Cloud Storage Bucket holding said mods.- Ex:
$ cd /home/minecraft/scripts && sudo ./mod_refresh.sh
- Ex:
- Syncs up the
- Problem: The server has not been started, even though the instance has been respun/started!
- Resolution: It could be the startup script failed to execute. Taint the GCP instance in Terraform and reapply the Terraform configuration to auto respin the instance and wait for the instance to spin up again.
- Problem: I'm not sure if the startup script executed?
- Resolution: Depending on the image you are using, there is a way to tell the instance to rerun the starup script. Refer to the link here for more details.
- Problem: I want to debug the running instance, what are my options?
- Resolution: Check this link to view any startup script logs. For the minecraft server itself, the logs can be viewed in the minecraft folder under
logs
.
- Resolution: Check this link to view any startup script logs. For the minecraft server itself, the logs can be viewed in the minecraft folder under
- Problem: Looking on the instance's logs, there's a crash in the Minecraft server, how can I fix this?
- Resolution: The following solutions should be attempted in order from top to bottom, stopping once a resolution has been found:
- Run the
restart.sh
script in thescripts
folder to restart the Minecraft server - Reboot the instance (
sudo reboot
) or recreate the instance in Terraform - Restore from a backup using
restore_backup.sh
- Run the
- Resolution: The following solutions should be attempted in order from top to bottom, stopping once a resolution has been found:
- Problem: I need to start my world from scratch, what can I do?
- Resolution: From least to most destructive, you have the following options (make sure to stop the minecraft server first via
stop.sh
!):- Delete the
world
folder and runrestart.sh
to start up the server again - Remove all contents of the
minecraft
folder and rerun the startup script - Perform a
terraform destroy
and then aterraform apply
- Delete the
- Resolution: From least to most destructive, you have the following options (make sure to stop the minecraft server first via
- Problem: I created the Cloud Functions, but when I navigate to them on my browser or
curl
, it takes a long time!- Resolution: Be patient! It is normal to have those links appear hanging for a few seconds. You will ALWAYS get a response back via plain HTTP after visiting those links, so just keep the tab open/command running.
- Problem: I ran the Cloud Function and it gave me an error on something failed!
- Resolution: s the message suggests, check the logs when trying to invoke the function. There is enough verbal output to allow one to troubleshoot the function.
- This blog gave me the initial idea on how this can be easily done nowadays
- My current gig involving myself being inmersed in the cloud
- A certain coworker who if you are reading this, you know who exactly 😉