Preparing the Minecraft Server JAR and Terraform Inputs

Official server JAR, Java version, SHA-256, EULA, firewall IP, and bucket names

Every required value in terraform.tfvars.example is a placeholder starting with replace-. Until they are swapped for the real project, firewall, Minecraft JAR, and backup bucket values, the preflight checks do not pass.

Prerequisites

Remote backend initialization is finished in the minecraft-one-root directory in Cloud Shell. Unless a command says otherwise, run it in that directory.

The state bucket already exists, but the Minecraft VM and the network do not. The commands below check inputs only and do not create a billable server.

Which Values You Prepare

minecraft-one-root/
├── README.md
├── terraform.tfvars.example
├── backend.hcl.example
├── versions.tf
├── variables.tf
├── project.tf
├── network.tf
├── storage.tf
├── compute.tf
├── outputs.tf
├── tests/
│   ├── configuration.tftest.hcl
│   └── *-in-container.sh container test scripts
└── scripts/
    ├── preflight.sh
    ├── prepare-server-jar.sh
    ├── review-plan.sh
    ├── validate-world-archive.sh
    ├── import-world.sh
    ├── startup.sh
    ├── shutdown.sh
    ├── backup.sh
    ├── restore.sh
    ├── restore-config.sh
    └── verify-backup.sh

Terraform reads the .tf files in the directory as one root. Keeping the network and VM configuration in separate files makes the place to edit quick to find. File names do not set the apply order. Terraform computes the order from the references between resources.

Copy the input sample.

Run

cp terraform.tfvars.example terraform.tfvars
nano terraform.tfvars

nano is an editor that runs in the terminal. Move with the arrow keys to fix values, save with Control+O followed by Enter, and close with Control+X. The sections below build the values one at a time, and you paste them into this file. If you are unsure whether you closed it without saving, open nano again and check.

Project and Backup Bucket Names

project_id takes the project ID, not the project name shown in the Console.

Check

gcloud config get-value project

The backup bucket name also has to be globally unique. Use a different name from the state bucket.

project_id         = "my-project-id"
backup_bucket_name = "my-project-id-minecraft-backup"

Names cannot contain non-ASCII characters, underscores, or uppercase letters. Combine the project ID and the purpose instead of personal information.

The Public IPv4 Allowed for SSH

admin_cidr is the one public IPv4 of the terminal that will run gcloud compute ssh. Run the command below in Cloud Shell.

Check

export ADMIN_IP="$(
  curl --fail --silent --show-error \
    https://api4.ipify.org
)"
printf '%s/32\n' "${ADMIN_IP}"

Put the printed IPv4 into terraform.tfvars including the trailing /32.

admin_cidr = "my.public.IPv4/32"

Leaving the placeholder replace-with-your-public-ip/32 in place gets rejected by the preflight checks. Cloud Shell’s public IP can differ in a new session. When that happens, update the SSH firewall with the procedure in part 08. On local macOS or WSL, use the public IP of the same Internet line as that terminal.

Game port 25565 is open to the Internet by default, but the Minecraft whitelist is what limits the actual players. If every player uses a static public IP, put each real address into game_source_cidrs as a /32. If some players are on changing addresses, as on a mobile network, keep the default ["0.0.0.0/0"]. Even then, an empty whitelist blocks the first connection. SSH port 22 opens only to the single admin_cidr address, and RCON is not exposed externally.

Official Server JAR, SHA-256, and Java Version

The JAR file is the Minecraft Java Edition server program that runs on the VM. Saving only its URL does not tell you whether a later download matches the file checked during preparation. scripts/startup.sh starts the service only when the downloaded file’s SHA-256 matches the input. A one-byte change produces a different SHA-256 value.

The preparation script finds the latest release in Mojang’s official version metadata, downloads the JAR, and computes its SHA-256. It does not modify terraform.tfvars for you.

Run: latest release

scripts/prepare-server-jar.sh \
  | tee server-jar-values.txt

To install a specific version, pass the version number as an argument. Minecraft uses year-based version names from 2026 on (26.1, 26.2, …), and 1.21.11 is the last of the 1.21 line.

Conditional run: pinning a version

scripts/prepare-server-jar.sh "26.2" \
  | tee server-jar-values.txt

The script first verifies the download against the SHA-1 Mojang provides, then prints these three values.

server_jar_url    = "https://piston-data.mojang.com/..."
server_jar_sha256 = "64-character-lowercase-hash"
server_java_major = 25

server_java_major comes out as 25 on 26.1 and later, and 21 from 1.20.5 through 1.21.11.

If download verification fails, sha1sum: WARNING: 1 computed checksum did NOT match appears and the script stops. Do not copy the values in that case. Check whether it is a network problem or a mismatch between the official metadata and the file, then run it again.

If the Java the Minecraft metadata requires is neither 21 nor 25, the script stops. scripts/startup.sh installs only those two versions on Ubuntu 24.04. Replace the matching entries in terraform.tfvars with the three printed lines. Do not change only one of the URL, the hash, and the Java major.

Accepting the EULA

Only someone who has read the Minecraft EULA and agrees to its server operation terms changes this value.

accept_minecraft_eula = true

Neither a script nor Terraform can accept it on your behalf. With false, both the preflight checks and the plan stop.

What the Finished Input File Looks Like

The following example shows the field layout. Do not copy the values inside angle brackets as they are.

project_id         = "<my-project-id>"
region             = "asia-northeast3"
zone               = "asia-northeast3-a"
bucket_location    = "ASIA-NORTHEAST3"
backup_bucket_name = "<globally-unique-backup-bucket>"

admin_cidr = "<my-public-IPv4>/32"
game_port  = 25565
game_source_cidrs = ["0.0.0.0/0"]

machine_type      = "e2-standard-2"
boot_disk_size_gb = 30

server_jar_url    = "<https-url-printed-by-prepare-server-jar>"
server_jar_sha256 = "<64-character-sha-256-printed-by-prepare-server-jar>"
server_java_major = 25

accept_minecraft_eula    = true
enable_automatic_backup  = false
deletion_protection      = true
backup_world_directories = ["world"]

# Optional values such as the boot image, backup retention days, and backup
# time are added only when needed; see the commented list in
# terraform.tfvars.example (boot_image, backup_live_days, backup_schedule).

In nano, save with Control+O and Enter, and close with Control+X. terraform fmt fixes the alignment spacing, so there is no need to line it up by hand.

The Google Cloud Resources These Inputs Create

From these inputs, Terraform ties a dedicated VPC and subnet, a static external IPv4, the game and SSH firewalls, a dedicated service account, the backup bucket, and the Spot VM into one plan.

  • A dedicated VPC reduces the chance that existing firewall rules on the default network mix into the server.
  • The static IPv4 keeps the connection address across a stop and start of the VM.
  • The VM service account reaches the backup bucket with short-lived tokens from the metadata server, with no JSON key.
  • A backup bucket with force_destroy = false is not deleted along with the rest while objects remain in it.
  • The Spot VM lowers cost, but Google Cloud can stop it without notice.

The world and the server settings live in /srv/minecraft on the boot disk. Removing the VM removes the disk too, so do not entrust an important world to it before the backup and isolated restore test in part 06.

Terraform passes the JAR URL, the hash, and the backup settings through VM metadata, a set of keys and values. Ubuntu’s startup script reads these values at boot and creates the server files and the service.

Preflight Checks

terraform validate checks the configuration in the .tf files. scripts/preflight.sh checks the actual variable values in terraform.tfvars first.

Run

terraform fmt
scripts/preflight.sh

The script checks the following items.

  • No replace-*, .invalid, documentation IPv4, or unaccepted EULA is left
  • The current gcloud project matches project_id
  • The SHA-256 is the same when the server JAR is downloaded again
  • The Java major of the JAR classes matches server_java_major exactly
  • The Terraform formatting and configuration are valid

The last line of a normal result is the following.

Preflight checks passed.

If any item ends in an error, do not create a plan. Fix the input the message points to and run the script again from the start.

Testing the Configuration Without a Real Provider

tests/configuration.tftest.hcl uses a mock Google provider. Without calling APIs on the project or creating resources, it checks the Spot settings, the firewall ranges, and the rejection of dangerous sample values.

Run

terraform test

A normal result is a summary saying every test passed. The test count can change as the example is updated, so read the failure count.

Success! ... passed, 0 failed.

Finally, check the formatting you edited by hand.

Check

terraform fmt -check -recursive
terraform validate

Input preparation is done once Success! The configuration is valid. appears. Keep the verified terraform.tfvars and backend in place, then create the plan in Applying a Terraform Plan and Connecting to Minecraft.

References

Comments

Comments

    Image preview