A photo of Evan Pratten
Evan Pratten

My snapshot-only Minecraft server

The freshest Minecraft server around

Recently, I’ve set up a Minecraft server for my friends.

Generally, we pick an interesting sounding modpack to play, or choose a recent-but-well-mod-supported version to use with client-side QoL mods. This time, I’m trying something different.

This server is always pinned to the latest Minecraft snapshot.

For the uninitiated, there are multiple Minecraft release types. Most commonly known: release, snapshot, old_beta, and old_alpha. Where release is what the majority of people experience when they open up the game launcher. Snapshots are weekly-ish builds of whatever new features are being worked on, before they are rolled up into a proper release number.

Pinning to snapshots

By pinning my server to only run the latest snapshot, I’ve given the group the ability to experience new game features before release, and we collectively contribute to some valuable community bug hunting while doing so.

To keep the server up-to-date without manually tracking new game builds, I’ve written a small set of scripts. The first of which being the startup script:

#! /bin/bash
set -e

# Config vars
SERVER_DIR=/opt/minecraft

# Game metadata
LATEST_VERSION_JSON=$(curl "https://launchermeta.mojang.com/mc/game/version_manifest.json" 2>/dev/null | jq -r '[.versions[] | select(.type=="snapshot")][0]')
LATEST_VERSION=$(echo "$LATEST_VERSION_JSON" | jq -r '.id')
SERVER_JAR_URL=$(curl "$(echo "$LATEST_VERSION_JSON" | jq -r '.url')" 2>/dev/null | jq -r '.downloads.server.url')

echo "Launching Minecraft Server ${LATEST_VERSION}"

# If we don't already have a copy of the server jar on disk, fetch it
if ! [[ -f "${SERVER_DIR}/${LATEST_VERSION}.jar" ]]; then
        echo "This version has not been run before. Fetching ${LATEST_VERSION}.jar"
        wget "$SERVER_JAR_URL" -O "${SERVER_DIR}/${LATEST_VERSION}.jar"

        # Notify Discord
        curl -H "Content-Type: application/json" \
                "https://discord.com/api/webhooks/<REDACTED>/<REDACTED>" \
                -d "{\"content\": \"The Minecraft server has updated to version \`${LATEST_VERSION}\`\"}"
fi

# Launch the server jar
java -Xmx8192M -Xms8192M -jar "${SERVER_DIR}/${LATEST_VERSION}.jar" nogui

To launch the server (via the startup script), I’ve put together a simple Systemd unit:

[Unit]
Description=Minecraft
After=network.target

[Service]
Type=simple
WorkingDirectory=/opt/minecraft
ExecStart=/opt/minecraft/run.sh
ExecStop=/bin/sh -c 'echo "stop" > /proc/$MAINPID/fd/0'
Restart=on-failure
TimeoutStopSec=30

[Install]
WantedBy=multi-user.target

And finally, to keep the server up to date, it needs to be occasionally restarted. I’ve chosen to do this with a simple cron job that runs when we are all asleep. The server update is pretty quick (on the order of seconds), so even if someone was up late playing the game, they aren’t interrupted for long.

0 4 * * * systemctl restart minecraft

FAQ

Why not update immediately after release?

I’ve chosen to search for and apply updates at 4am to minimize interruptions to my friends. I think we can handle being a few hours out-of-date in favour of not being kicked for updates mid-day.

What if the script crashes? Where’s your error handling?

My friends will annoy me on Discord until I fix it by hand. Think of it like human-powered PagerDuty.