06.12.2022

There is a guide about hosting a Minecraft server on the official wiki.

Standard installation§ 

Minecraft is a Java application. For most of its time, it has used Java 8. However, since Minecraft 1.17, newer versions of Java are now required. If you have already installed java, you can check which version is used by using the command java --version. Some tools, such as update-alternatives, archlinux-java or asdf can help you manage your versions of Java.

You can find the latest server on the official Minecraft website. On launching, the server will create several files and folders, so be sure you are in the right folder. You will need to edit the server.properties file, which contains you server settings.

Docker installation§ 

The following supposes you are already familiar with Docker. The itzg Minecraft Image is quite useful to host Minecraft servers. Below will be some examples of how to use it. More documentation can be found on Github.

version: "3.3"

services:
  <server-name>:
    restart: unless-stopped
    container_name: <container-name>
    image: itzg/minecraft-server:java8
    volumes:
      - ./data:/data
    ports:
      - 25565:25565
    environment:
      EULA: "TRUE"
      DEBUG: "true"
      VERSION: "1.16.5"
      MEMORY: "8G"
      ALLOW_FLIGHT: "true"
      MOTD: "Welcome to this Minecraft server !"
      WHITELIST: "Player1,Player2"
      ENFORCE_WHITELIST: "true"
      SPAWN_PROTECTION: 1
      TZ: "Europe/Paris"
      ENABLE_AUTOPAUSE: "FALSE"
    tty: true
    stdin_open: true

This should be a working docker-compose.yaml file. You could place it in such a folder :

./
./data/
./docker-compose.yaml

In data are Minecraft data : server.properties, the world folder etc... The volumes list help us bind the folder on our machine (./data in this case) to the one in the container (/data).

The image used is itzg/minecraft-server:java8. There are several tags available, to specify which version to use. It's especially important if you use an older version of Minecraft which requires Java 8.

The container uses port 25565, which is the standard Minecraft one. Here, we bind it to the local port 25565. If you plan on hosting several Minecraft server at once, you should be careful to specify a different local port for each one.

Several environment variables are specified here. The full list is available there for server settings, and here for server types. The server types allow you to specify if you want to run Forge, Paper...

Managing your server (Docker version)§ 

Creating a backup§ 

The following script creates a server backup and sends it over a distant Minio server. This is not a very sophisticated thing, but it works.

DIR="/path/to/your/server/data/"
WORLD_NAME="world"
MINIO_PREFIX="minecraft-server"
CONTAINER="container-name"

# the following block will deactivate automatic save, then make a save, then wait a while for the save to be finished
docker exec "$CONTAINER" rcon-cli save-off
docker exec "$CONTAINER" rcon-cli save-all
sleep 10



# Backup server
# The world folder is archived, then sent to a Minio server.
# A script is then called to remove old unnecessary backups
echo "Starting backup..."
filename="$MINIO_PREFIX-$(date -Iminutes).tar.gz"
tar -cpvzf "/path/to/an/intermediate/folder/worlds/$WORLD_NAME/$filename" "$DIR/$WORLD_NAME"
/usr/local/bin/mcli -C /home/admin/.mcli cp "/path/to/an/intermediate/folder/worlds/$WORLD_NAME/$filename" minio-server/minecraft-saves -q
PREFIX="$MINIO_PREFIX" /usr/bin/bash /path/minecraft/utilities/minecraft-prune-backups.sh
rm "/path/to/an/intermediate/folder/worlds/$WORLD_NAME/$filename"
echo "Backup complete"

docker exec "$CONTAINER" rcon-cli save-on

Pruning backups§ 

This is the script called by the backup script above, to prune old backups. $PREFIX is the name of the minio alias. This script removes backups older than seven days, and keep one backup a day until the day before. It keeps all the backups of the current day.

MCLI="/usr/local/bin/mcli"
BUCKET="minecraft-server/backups"

if [[ -z "$PREFIX" ]]
then
	echo "Error: PREFIX not set"
fi

files=$($MCLI ls $BUCKET | awk '{print $6}')

echo files : $files
now_7d=$(date -d 'now - 7 day' +%s)
echo One week ago : $now_7d
now_1d=$(date -d 'now - 1 day' +%s)
echo One day ago : $now_1d

# for file in folder :
for f in $files; do
	if [[ "$f" == "$PREFIX"* ]]; then
		date=$(echo $f | sed -e "s/^$PREFIX-//" | awk -F. '{print $1}' )
		echo $f : $date - $day
		if (( $(date -d "$date" +%s) < $now_7d )); then
			echo More than a week old : $f
			echo "$MCLI" rm "$BUCKET/$f"
			"$MCLI" rm "$BUCKET/$f"
		elif (( $(date -d "$date" +%s) < $now_1d )) && [[ $(echo $date | awk -FT '{print $1}') == $day ]]; then
			echo Already have $day : $f
			echo "$MCLI rm $BUCKET/$f"
			"$MCLI" rm "$BUCKET/$f"
		else
			day=$(echo $date | awk -FT '{print $1}')
		fi
	fi
done

Tools§