Skip to content

Instantly share code, notes, and snippets.

@CraigWilsonOZ
Last active July 5, 2025 20:06
Show Gist options
  • Save CraigWilsonOZ/983bd539a1bbc17a1a726e63b885a6f6 to your computer and use it in GitHub Desktop.
Save CraigWilsonOZ/983bd539a1bbc17a1a726e63b885a6f6 to your computer and use it in GitHub Desktop.
Minecraft: Java Edition server on Ubuntu setup script
#!/bin/bash
#==============================================================================
# Minecraft Java Server Setup Script
#
# Author: Craig Wilson
# Version: 1.2
# Last Modified: 2025-06-21
#
# Description:
# This script automates the setup of a Minecraft Java Edition server on a
# Debian-based system. It is designed to be rerunnable; it will check the
# system state and only perform actions that are necessary.
#
# Features:
# - Installs necessary dependencies.
# - Creates a dedicated user and directories for the server.
# - Downloads the Minecraft server JAR file (if not present).
# - Configures server properties and RCON access.
# - Sets up scripts for starting the server and managing backups.
# - Schedules a daily backup via a cron job (if not present).
#
# Security Note:
# The scripts 'start-service-minecraft.sh' and 'stop-service-minecraft.sh'
# require the '$MINECRAFT_USER' user to have sudo privileges for systemctl.
#
# Tested on:
# - Ubuntu 24.04 (Lunar Lobster)
# - Minecraft Java Edition 1.21.7
# - Openjdk-21-jre-headless
#
# Readme:
# https://craigwilson.blog/post/2025/2025-06-21-minecraftserver/
#==============================================================================
# --- Script Configuration and Preamble ---
# Exit immediately if a command exits with a non-zero status.
set -euo pipefail
# Set DEBIAN_FRONTEND to noninteractive to prevent prompts.
export DEBIAN_FRONTEND=noninteractive
# --- Function Definitions ---
#
# Performs initial checks to ensure script can run successfully.
#
initial_checks() {
echo "▶ Performing initial checks..."
# Check for root privileges
if [ "$EUID" -ne 0 ]; then
echo "ERROR: Please run this script as root or using sudo." >&2
exit 1
fi
}
#
# Displays the help message for the script.
#
display_help() {
cat << EOF
Minecraft Java Server Setup Script - v1.2
This script automates the setup of a Minecraft Java Edition server on a Debian-based system.
It is rerunnable and will skip steps that are already completed.
Usage:
sudo ./setup-minecraft.sh
Options:
-h, --help Display this help message and exit.
The script must be run with root (sudo) privileges. All server configuration
can be adjusted in the '== Configuration ==' section of the script file.
EOF
}
# === Configuration ===
MINECRAFT_USER="minecraft"
INSTALL_DIR="/opt/minecraft"
SERVER_DIR="$INSTALL_DIR/server"
TOOLS_DIR="$INSTALL_DIR/tools"
LOGS="$INSTALL_DIR/logs"
BACKUP_DIR="$INSTALL_DIR/backup"
MCRCON_DIR="$TOOLS_DIR/mcrcon"
MINECRAFT_JAR_URL="https://piston-data.mojang.com/v1/objects/05e4b48fbc01f0385adb74bcff9751d34552486c/server.jar"
# Addtional server.jar files can be found at
# https://gist.github.com/cliffano/77a982a7503669c3e1acb0a0cf6127e9
JAR_NAME="server.jar"
PASSWORD=$(date +%s | sha256sum | base64 | head -c 32 ; echo)
# Memory settings for the server.
# Adjust these values based on your system's available RAM.
MAX_MEMORY="8192M" # Maximum Heap memory allocation for the server
MIN_MEMORY="8192M" # Initial memory allocation for the server
# Minecraft and RCON ports.
MINECRAFT_PORT="25565"
RCON_PORT="25575"
# Maximum number of players allowed on the server.
MAX_PLAYERS="20"
# Open JDK version to use.
# Ensure this matches the installed version on your system.
JDK_VERSION="openjdk-21-jre-headless"
# --- Script Execution ---
# Parse command-line options for help flag
if [[ "${1-}" =~ ^(-h|--help)$ ]]; then
display_help
exit 0
fi
# Call the initial checks function.
initial_checks
echo "[+] Starting Minecraft Java Server Setup"
# === Install Dependencies ===
echo "▶ Installing dependencies..."
sudo apt-get update
sudo apt-get install -y $JDK_VERSION git build-essential cron
# === Create User and Directories ===
echo "▶ Ensuring user and directories exist..."
# Create the user; the || true part prevents errors on reruns
sudo useradd -r -m -U -d "$INSTALL_DIR" -s /bin/bash "$MINECRAFT_USER" || echo "✔ User '$MINECRAFT_USER' already exists."
# Create the main directories
sudo mkdir -p "$SERVER_DIR" "$TOOLS_DIR" "$BACKUP_DIR"
# NEW: Create a symbolic link for the logs
# First, remove the logs directory if it exists as a normal directory
if [ -d "$LOGS" ] && [ ! -L "$LOGS" ]; then
sudo rmdir "$LOGS"
fi
# Then, link the server's default log directory to our desired location
if [ ! -e "$LOGS" ]; then
echo "▶ Linking server logs directory..."
# The server will create /opt/minecraft/server/logs, so we link it to /opt/minecraft/logs
sudo -u "$MINECRAFT_USER" ln -s "$SERVER_DIR/logs" "$LOGS"
fi
# Set final ownership
sudo chown -R "$MINECRAFT_USER":"$MINECRAFT_USER" "$INSTALL_DIR"
# We use -h to change the ownership of the link itself, not what it points to
sudo chown -h "$MINECRAFT_USER":"$MINECRAFT_USER" "$LOGS"
# === Download Minecraft Server ===
if [ ! -f "$SERVER_DIR/$JAR_NAME" ]; then
echo "▶ Downloading Minecraft server JAR..."
sudo -u "$MINECRAFT_USER" wget -O "$SERVER_DIR/$JAR_NAME" "$MINECRAFT_JAR_URL"
else
echo "✔ Server JAR already exists. Skipping download."
fi
# === Accept EULA ===
echo "▶ Ensuring EULA is accepted..."
sudo -u "$MINECRAFT_USER" tee "$SERVER_DIR/eula.txt" > /dev/null <<EOF
eula=true
EOF
# === Create Server Properties ===
echo "▶ Creating/updating server.properties..."
sudo -u "$MINECRAFT_USER" tee "$SERVER_DIR/server.properties" > /dev/null <<EOF
#Minecraft server properties
accepts-transfers=false
allow-flight=false
allow-nether=true
broadcast-console-to-ops=true
broadcast-rcon-to-ops=true
bug-report-link=
difficulty=easy
enable-command-block=false
enable-jmx-monitoring=false
enable-query=false
enable-rcon=true
enable-status=true
enforce-secure-profile=true
enforce-whitelist=false
entity-broadcast-range-percentage=100
force-gamemode=false
function-permission-level=2
gamemode=survival
generate-structures=true
generator-settings={}
hardcore=false
hide-online-players=false
initial-disabled-packs=
initial-enabled-packs=vanilla
level-name=world
level-seed=
level-type=minecraft\:normal
log-ips=true
max-chained-neighbor-updates=1000000
max-players=$MAX_PLAYERS
max-tick-time=60000
max-world-size=29999984
motd=A Minecraft Server
network-compression-threshold=256
online-mode=true
op-permission-level=4
pause-when-empty-seconds=60
player-idle-timeout=0
prevent-proxy-connections=false
pvp=true
query.port=$MINECRAFT_PORT
rate-limit=0
rcon.password=$PASSWORD
rcon.port=$RCON_PORT
region-file-compression=deflate
require-resource-pack=false
resource-pack=
resource-pack-id=
resource-pack-prompt=
resource-pack-sha1=
server-ip=
server-port=$MINECRAFT_PORT
simulation-distance=10
spawn-monsters=true
spawn-protection=16
sync-chunk-writes=true
text-filtering-config=
text-filtering-version=0
use-native-transport=true
view-distance=10
white-list=false
EOF
# === Install and Build MCRCON ===
if [ ! -d "$MCRCON_DIR" ]; then
echo "▶ Cloning and building mcrcon..."
sudo -u "$MINECRAFT_USER" git clone https://github.com/Tiiffi/mcrcon.git "$MCRCON_DIR"
sudo -u "$MINECRAFT_USER" bash -c "cd '$MCRCON_DIR' && gcc -std=gnu11 -pedantic -Wall -Wextra -O2 -s -o mcrcon mcrcon.c"
else
echo "✔ mcrcon directory already exists. Skipping clone and build."
fi
# === Create Helper Scripts ===
echo "▶ Creating/updating helper scripts..."
sudo -u "$MINECRAFT_USER" tee "$TOOLS_DIR/connect-mcrcon.sh" > /dev/null <<EOF
#!/bin/bash
$MCRCON_DIR/mcrcon -H 127.0.0.1 -P $RCON_PORT -p "$PASSWORD" -t
EOF
sudo -u "$MINECRAFT_USER" tee "$TOOLS_DIR/backup-minecraft.sh" > /dev/null <<EOF
#!/bin/bash
function rcon {
"$MCRCON_DIR/mcrcon" -H 127.0.0.1 -P $RCON_PORT -p "$PASSWORD" "\$1"
}
echo "Running Minecraft backup..."
rcon "save-off"
rcon "save-all"
sleep 10 # Give the server a moment to save
tar -cvpzf "$BACKUP_DIR/server-\$(date +%F-%H-%M).tar.gz" "$SERVER_DIR"
rcon "save-on"
echo "Backup complete."
# Delete older backups
find "$BACKUP_DIR" -type f -mtime +31 -name '*.gz' -delete
EOF
sudo -u "$MINECRAFT_USER" tee "$TOOLS_DIR/start-minecraft.sh" > /dev/null <<EOF
#!/bin/bash
cd "$SERVER_DIR" || exit
/usr/bin/java -Xmx$MAX_MEMORY -Xms$MIN_MEMORY -jar "$JAR_NAME" nogui
EOF
sudo -u "$MINECRAFT_USER" tee "$TOOLS_DIR/start-service-minecraft.sh" > /dev/null <<EOF
#!/bin/bash
sudo systemctl start minecraft
EOF
sudo -u "$MINECRAFT_USER" tee "$TOOLS_DIR/stop-service-minecraft.sh" > /dev/null <<EOF
#!/bin/bash
sudo systemctl stop minecraft
EOF
# Make all scripts in the tools directory executable
sudo chmod +x $TOOLS_DIR/*.sh
# === Create Backup Cron Job ===
CRON_JOB="0 3 * * * $TOOLS_DIR/backup-minecraft.sh >> $LOGS/backup.log 2>&1"
if ! sudo -u "$MINECRAFT_USER" crontab -l | grep -Fq "$CRON_JOB"; then
echo "▶ Creating daily backup cron job..."
(sudo -u "$MINECRAFT_USER" crontab -l 2>/dev/null || true; echo "$CRON_JOB") | sudo -u "$MINECRAFT_USER" crontab -
else
echo "✔ Backup cron job already exists. Skipping."
fi
# === Create Systemd Service ===
echo "▶ Creating/updating systemd service file..."
sudo tee /etc/systemd/system/minecraft.service > /dev/null <<EOF
[Unit]
Description=Minecraft Java Server
After=network.target
[Service]
User=$MINECRAFT_USER
WorkingDirectory=$SERVER_DIR
ExecStart=/usr/bin/java -Xmx$MAX_MEMORY -Xms$MIN_MEMORY -jar $SERVER_DIR/$JAR_NAME nogui
ExecStop=$MCRCON_DIR/mcrcon -H 127.0.0.1 -P $RCON_PORT -p $PASSWORD stop
Restart=on-failure
SuccessExitStatus=0 1
[Install]
WantedBy=multi-user.target
EOF
# === Enable and Start Service (Safely) ===
sudo systemctl daemon-reload
if ! sudo systemctl is-active --quiet minecraft; then
echo "▶ Starting and enabling the minecraft service..."
sudo systemctl enable --now minecraft
else
echo "✔ Minecraft service is already active. Ensuring it is enabled on boot."
sudo systemctl enable minecraft
echo "[!] The service definition or server properties may have changed. Run 'sudo systemctl restart minecraft' to apply all changes."
fi
echo ""
echo "[+] Setup Complete."
echo "[*] To connect to the server console, run: $TOOLS_DIR/connect-mcrcon.sh"
echo "[*] Your RCON password is: $PASSWORD"
echo ""
echo "### Security Note ###"
echo "To use the 'start/stop-service-minecraft.sh' scripts, you must grant sudo privileges."
echo "Run 'sudo visudo' and add the following line:"
echo "$MINECRAFT_USER ALL=(ALL) NOPASSWD: /usr/bin/systemctl start minecraft, /usr/bin/systemctl stop minecraft"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment