Moving an Existing Minecraft World to Google Cloud

Checking an existing world archive, staging it on the VM, replacing the test world, connecting, and creating a new backup

Check an existing Java Edition world’s archive paths and level.dat, then extract it into a temporary directory on the VM. After the checks, stop the server, replace the world in one step, and put the old test world back if the start fails.

Prerequisites

You must have finished the backup and the isolated load test for the Google Cloud test world in part 06. The source server you are moving from must also be able to shut down cleanly.

Verification scope

The archive check and the rollback branch were tested in an Ubuntu container. No personal world was uploaded to a real VM or swapped in. The current state is local and container verification complete, real Google Cloud apply unverified.

The Source Server and the World Folder

Copying while the source server writes files can mix chunks from different points in time. Disconnect the players and shut the source Minecraft server down cleanly. Copy the world folder after the Java process exits.

level.dat must sit directly inside the folder.

world/
├── level.dat
├── region/
├── data/
├── playerdata/
├── DIM-1/
└── DIM1/

There must not be an extra folder level, as in world/world/level.dat. If that is what you have, the migration target is the inner world folder that directly contains level.dat, not the outer one. Move the inner folder somewhere else, such as the desktop, and build the archive below from that folder. On a Paper-family server where the Nether and End are separate top-level folders, do not merge them with this vanilla example. Check how your server implementation lays out dimensions and plan that move separately.

Creating world.tar.gz

In Windows PowerShell, move to the parent directory of the world folder and run the commands there. The parent directory is the location where File Explorer shows the world folder. Click the File Explorer address bar, copy the path, and paste it after cd. If the server folder is C:\my-server, for example, run cd C:\my-server first.

Conditional run: Windows

tar -czf world.tar.gz world
tar -tf world.tar.gz | Select-Object -First 20

On macOS or Linux, run it in the same location.

Conditional run: macOS or Linux

tar -czf world.tar.gz world
tar -tf world.tar.gz | sed -n '1,20p'

The first path in the listing should be world/, and world/level.dat should appear. Do not put the source server.properties, whitelist, or operator list into this archive. That keeps the Google Cloud server’s whitelist and port settings in place.

Checking the Archive in Cloud Shell

Open Cloud Shell in the Google Cloud Console and click Upload in the three-dot menu at the top right. Select the world.tar.gz you just created. When the upload finishes, move to the server example directory.

Run

cd "${HOME}/minecraft-one-root"
scripts/validate-world-archive.sh \
  "${HOME}/world.tar.gz" \
  world

The check rejects absolute paths, .., symbolic links, hard links, device files, and any other top-level folder. It also fails when world/level.dat is missing. A normal result shows the expected extracted size and the SHA-256.

Do not copy the archive to the VM when an error appears. Fix the source folder structure, build a new archive, and start again from the check.

Copying to VM Staging

Read the VM name and zone from the Terraform outputs and send the archive to /tmp.

Run

export MINECRAFT_INSTANCE="$(
  terraform output -raw minecraft_instance_name
)"
export MINECRAFT_ZONE="$(
  terraform output -raw minecraft_zone
)"

gcloud compute scp \
  "${HOME}/world.tar.gz" \
  "${MINECRAFT_INSTANCE}:/tmp/world.tar.gz" \
  --zone="${MINECRAFT_ZONE}"

If the transfer breaks, run the same command again and then compare the hash on the VM.

Check

export LOCAL_SHA="$(
  sha256sum "${HOME}/world.tar.gz" | cut -d' ' -f1
)"
export REMOTE_SHA="$(
  gcloud compute ssh "${MINECRAFT_INSTANCE}" \
    --zone="${MINECRAFT_ZONE}" \
    --command="sha256sum /tmp/world.tar.gz" | cut -d' ' -f1
)"
printf 'local  %s\nremote %s\n' "${LOCAL_SHA}" "${REMOTE_SHA}"
[[ "${LOCAL_SHA}" == "${REMOTE_SHA}" ]] \
  && echo "SHA-256 OK" \
  || echo "SHA-256 MISMATCH"

Instead of eyeballing two 64-character values, read SHA-256 OK on the last line. On MISMATCH, do not replace anything; run gcloud compute scp again.

Replacing the Production World

This command uses minecraft-world-archive-check installed on the VM to rerun the archive check you ran in Cloud Shell, against the same criteria. Repeating the check confirms that the validated archive structure is still present after upload. It then extracts into a temporary directory and fails before stopping the server when there is not enough free disk space. Only after the check passes does it move the current test world into a rollback directory.

Run: this replaces the production world

gcloud compute ssh "${MINECRAFT_INSTANCE}" \
  --zone="${MINECRAFT_ZONE}" \
  --command="sudo minecraft-world-import \
    /tmp/world.tar.gz \
    world"

If the file move, the ownership change, the service start, or the is-active check fails, the script clears the imported world away and puts the previous test world back. If errors appear during the rollback as well, do not run more move commands; record the current listing of /srv/minecraft and the systemd log.

The Done Log and the First Connection

Check: up to 10 minutes

gcloud compute ssh "${MINECRAFT_INSTANCE}" \
  --zone="${MINECRAFT_ZONE}" \
  --command='
    active_since="$(
      systemctl show minecraft \
        --property=ActiveEnterTimestamp \
        --value
    )"
    for attempt in $(seq 1 60); do
      sudo journalctl \
        -u minecraft \
        --since "${active_since}" \
        --no-pager |
        grep -q "Done (.*)! For help" && exit 0
      sudo systemctl is-active --quiet minecraft || exit 1
      sleep 10
    done
    exit 1
  '

If the command fails, read the first error from sudo journalctl -u minecraft -n 200 --no-pager. Do not open a world in an older JAR once a newer version has opened it. On a version mismatch, prepare the Minecraft version and Java major that last ran the source correctly, using the procedure in part 08, and move the world again.

Once Done appears, connect with the operator account you registered in part 05. Check the coordinates you wrote down before the move, along with chest contents, signs, and player inventories. The whitelist and ops.json keep the Google Cloud server’s existing settings.

A New Backup Right After the Move

Once the connection check is done, back up the new state.

Run

gcloud compute ssh "${MINECRAFT_INSTANCE}" \
  --zone="${MINECRAFT_ZONE}" \
  --command="sudo systemctl start minecraft-backup.service"

Find the new archive name the same way as in part 06 and run minecraft-backup-verify. Do not delete the source server or the source archive until the new archive passes the isolated load test.

Delete the temporary upload file on the VM after the new backup is verified.

Deletes data: the temporary file on the VM, after the new backup is verified

gcloud compute ssh "${MINECRAFT_INSTANCE}" \
  --zone="${MINECRAFT_ZONE}" \
  --command="sudo rm -- /tmp/world.tar.gz"

Completion Check

  • You created the archive after shutting the source server down cleanly.
  • The archive check and the SHA-256 comparison between local and VM both passed.
  • You saw Done (...)! with the new world.
  • You checked the recorded coordinates and the player data yourself.
  • The backup made right after the move passed the isolated load test.
  • You kept the source world and archive until the new backup was verified.

After verifying the new backup, use Minecraft Server Power and Version Changes for VM stops and JAR replacement.

Comments

Comments

    Image preview