A dedicated Minecraft Java Edition server gives you and your friends a world that stays online when you log off, with your own rules, whitelist and settings. In this tutorial you will install the official server from Mojang on Ubuntu 24.04, run it under a dedicated user as a systemd service, open its port in the firewall, manage it from the command line with RCON, and schedule automatic world backups.

Prerequisites

To follow this guide you need:

  • A server running Ubuntu 24.04 LTS, for example a CubePath VPS, with at least 2 vCPUs and 4 GB of RAM. Plan on about 1 GB of server heap per 5-10 active players on a vanilla world, plus 1 GB for the operating system.
  • A non-root user with sudo privileges.
  • A Minecraft Java Edition account to connect and test.
  • Optionally, a domain name with an A record pointing to your server's IP address, so players can connect with a name instead of an IP.

Step 1 - Installing Java and tools

The Minecraft server is a Java application, and each Minecraft release requires a minimum Java version. Install jq first so you can read that requirement from Mojang's version metadata:

sudo apt update
sudo apt install curl jq

Mojang publishes a manifest listing every version. Get the latest release and the URL of its metadata:

MC_VERSION=$(curl -fsSL https://piston-meta.mojang.com/mc/game/version_manifest_v2.json | jq -r '.latest.release')
MC_META=$(curl -fsSL https://piston-meta.mojang.com/mc/game/version_manifest_v2.json | jq -r --arg v "$MC_VERSION" '.versions[] | select(.id == $v) | .url')
echo "$MC_VERSION"
curl -fsSL "$MC_META" | jq '.javaVersion.majorVersion'
1.21.9
21

Your version numbers may be newer. The second line is the Java major version you need. Install the matching headless OpenJDK runtime from Ubuntu's repositories, replacing 21 if the output showed a different number:

sudo apt install openjdk-21-jre-headless
java -version
openjdk version "21.0.8" 2025-07-15
OpenJDK Runtime Environment (build 21.0.8+9-Ubuntu-0ubuntu124.04.1)
OpenJDK 64-Bit Server VM (build 21.0.8+9-Ubuntu-0ubuntu124.04.1, mixed mode, sharing)

Step 2 - Creating a dedicated user

Running the server as its own system user keeps it away from your account and the rest of the system if a plugin or exploit ever compromises it. Create a user with its home in /opt/minecraft and no login shell:

sudo useradd --system --create-home --home-dir /opt/minecraft --shell /usr/sbin/nologin minecraft
sudo mkdir -p /opt/minecraft/server /opt/minecraft/backups
sudo chown -R minecraft:minecraft /opt/minecraft

Step 3 - Downloading the server

Read the download URL of the server JAR from the version metadata you found in Step 1 and download it as the minecraft user. If you opened a new shell since then, run the two MC_VERSION and MC_META lines again first:

SERVER_URL=$(curl -fsSL "$MC_META" | jq -r '.downloads.server.url')
sudo -u minecraft curl -fsSL -o /opt/minecraft/server/server.jar "$SERVER_URL"
sudo ls -lh /opt/minecraft/server/server.jar
-rw-r--r-- 1 minecraft minecraft 57M Sep 25 10:12 /opt/minecraft/server/server.jar

Run it once to generate the configuration files. It stops immediately because the EULA has not been accepted:

sudo -u minecraft sh -c 'cd /opt/minecraft/server && java -Xmx1G -jar server.jar --nogui'
[ServerMain/WARN]: Failed to load eula.txt
[ServerMain/INFO]: You need to agree to the EULA in order to run the server. Go to eula.txt for more info.

Read the Minecraft EULA at https://aka.ms/MinecraftEULA. If you agree, accept it:

sudo -u minecraft sed -i 's/^eula=false/eula=true/' /opt/minecraft/server/eula.txt

Step 4 - Configuring server.properties

The main settings live in /opt/minecraft/server/server.properties. Open it:

sudo -u minecraft nano /opt/minecraft/server/server.properties

Change these keys and leave the rest at their defaults:

motd=My CubePath Minecraft Server
max-players=20
difficulty=normal
gamemode=survival
view-distance=10
simulation-distance=8
online-mode=true
white-list=true
enforce-whitelist=true
enable-rcon=true
rcon.port=25575
rcon.password=your_strong_password
server-port=25565

What they do:

  • online-mode=true checks every player against Mojang's authentication servers. Keep it on; turning it off lets anyone join with any name.
  • white-list and enforce-whitelist only admit players you add, and kick anyone removed from the list.
  • view-distance and simulation-distance are the biggest levers on CPU and RAM use. Lower them if the server lags.
  • enable-rcon turns on the remote console you will use to run commands. Replace your_strong_password with a long random string, for example from openssl rand -base64 24. You will not open port 25575 in the firewall, so RCON stays reachable only from the server itself.

Because the file now contains a password, restrict it to the minecraft user:

sudo chmod 600 /opt/minecraft/server/server.properties

Step 5 - Creating the systemd service

A systemd unit starts the server at boot, restarts it if it crashes and stops it cleanly on shutdown. Create the unit file:

sudo nano /etc/systemd/system/minecraft.service
[Unit]
Description=Minecraft Java Edition server
After=network-online.target
Wants=network-online.target

[Service]
User=minecraft
Group=minecraft
WorkingDirectory=/opt/minecraft/server
ExecStart=/usr/bin/java -Xms2G -Xmx2G -jar server.jar --nogui
SuccessExitStatus=0 143
Restart=on-failure
RestartSec=10
TimeoutStopSec=90
NoNewPrivileges=true
ProtectSystem=full
ProtectHome=true
PrivateTmp=true

[Install]
WantedBy=multi-user.target

-Xms2G -Xmx2G gives the server a fixed 2 GB heap; set both to the same value, and leave at least 1 GB of RAM for the operating system. On a 4 GB server, 2-3 GB is right; on 8 GB, use 5-6 GB. When systemd stops the service it sends SIGTERM, the server saves the world and exits with status 143, which SuccessExitStatus treats as a clean stop.

Load the unit and start the server:

sudo systemctl daemon-reload
sudo systemctl enable --now minecraft

The first start generates the world and takes a minute. Follow the log:

sudo journalctl -u minecraft -f
[Server thread/INFO]: Preparing level "world"
[Server thread/INFO]: Preparing spawn area: 100%
[Server thread/INFO]: Done (18.412s)! For help, type "help"
[Server thread/INFO]: Starting remote control listener
[RCON Listener #1/INFO]: RCON running on 0.0.0.0:25575

Press Ctrl+C to stop following. The Done line means the server is ready.

Step 6 - Opening the firewall

Players connect over TCP port 25565. Allow it in UFW, making sure SSH stays allowed before you enable the firewall:

sudo ufw allow OpenSSH
sudo ufw allow 25565/tcp
sudo ufw enable
sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
25565/tcp                  ALLOW       Anywhere
OpenSSH (v6)               ALLOW       Anywhere (v6)
25565/tcp (v6)             ALLOW       Anywhere (v6)

Port 25575 (RCON) is not listed, so it is blocked from the internet.

Step 7 - Managing the server with RCON

The server runs in the background, so you need RCON to type console commands. Build mcrcon, a small command line RCON client:

sudo apt install git build-essential
git clone https://github.com/Tiiffi/mcrcon.git
cd mcrcon
make
sudo make install

Store the RCON password in an environment variable for the current shell, so it does not end up on the command line of every call:

read -rs MCRCON_PASS && export MCRCON_PASS

Type the password and press Enter. Now add yourself to the whitelist and make yourself an operator, replacing your_player_name with your Minecraft username:

mcrcon -H 127.0.0.1 -P 25575 "whitelist add your_player_name" "op your_player_name"
Added your_player_name to the whitelist
Made your_player_name a server operator

Run mcrcon -H 127.0.0.1 -P 25575 -t for an interactive console, and type Q to leave it. Useful commands are list (online players), say <message>, whitelist remove <name> and save-all.

Now open Minecraft Java Edition, choose Multiplayer, Add Server, and enter your_server_ip or your_domain. The server should appear with your MOTD and you can join.

Step 8 - Scheduling automatic backups

A world copy taken while the server writes to it can be corrupted. The backup script below pauses autosaving, forces a full save, archives the world and turns autosaving back on. It keeps the last 14 archives.

Store the RCON password in a file only root can read:

sudo install -m 600 /dev/null /etc/minecraft-rcon.env
sudo nano /etc/minecraft-rcon.env
MCRCON_PASS=your_strong_password

Create the script:

sudo nano /usr/local/bin/minecraft-backup
#!/usr/bin/env bash
set -euo pipefail

SERVER_DIR="/opt/minecraft/server"
BACKUP_DIR="/opt/minecraft/backups"
KEEP=14
RCON=(/usr/local/bin/mcrcon -H 127.0.0.1 -P 25575)

restore_autosave() { "${RCON[@]}" "save-on" >/dev/null || true; }
trap restore_autosave EXIT

"${RCON[@]}" "save-off" "save-all flush" >/dev/null

archive="${BACKUP_DIR}/world-$(date +%Y%m%d-%H%M%S).tar.gz"
tar -czf "$archive" -C "$SERVER_DIR" world

find "$BACKUP_DIR" -maxdepth 1 -name 'world-*.tar.gz' -printf '%T@ %p\n' \
  | sort -rn | tail -n +"$((KEEP + 1))" | cut -d' ' -f2- | xargs -r rm --
echo "Backup written to $archive"

Make it executable:

sudo chmod 755 /usr/local/bin/minecraft-backup

Create a systemd service that runs the script as the minecraft user with the password file:

sudo nano /etc/systemd/system/minecraft-backup.service
[Unit]
Description=Back up the Minecraft world
After=minecraft.service

[Service]
Type=oneshot
User=minecraft
EnvironmentFile=/etc/minecraft-rcon.env
ExecStart=/usr/local/bin/minecraft-backup

And a timer that runs it every day at 04:30:

sudo nano /etc/systemd/system/minecraft-backup.timer
[Unit]
Description=Daily Minecraft world backup

[Timer]
OnCalendar=*-*-* 04:30:00
Persistent=true

[Install]
WantedBy=timers.target

Enable the timer and run one backup now to test it:

sudo systemctl daemon-reload
sudo systemctl enable --now minecraft-backup.timer
sudo systemctl start minecraft-backup.service
sudo journalctl -u minecraft-backup --no-pager -n 5
sudo ls -lh /opt/minecraft/backups
Backup written to /opt/minecraft/backups/world-20260925-104512.tar.gz
-rw-r--r-- 1 minecraft minecraft 38M Sep 25 10:45 world-20260925-104512.tar.gz

Backups on the same disk do not protect against losing the server. Copy /opt/minecraft/backups to another location regularly, for example with rsync or rclone to object storage.

To restore, stop the server, move the current world directory aside, extract an archive into /opt/minecraft/server with sudo -u minecraft tar -xzf <archive> -C /opt/minecraft/server, and start the server again.

Step 9 - Updating the server

When a new Minecraft version is released, players' clients update automatically and can no longer join an older server. To update, take a backup, stop the server, replace the JAR and start it again:

sudo systemctl start minecraft-backup.service
sudo systemctl stop minecraft

Repeat the commands from Step 1 to read the new version and its Java requirement (install a newer OpenJDK package if it changed), then download the new JAR as in Step 3 and start the server:

sudo systemctl start minecraft
sudo journalctl -u minecraft -f

The server converts the world to the new format on first start. That conversion cannot be undone, which is why the backup comes first.

Troubleshooting

The service fails with UnsupportedClassVersionError. The installed Java is older than the version the server needs. Check .javaVersion.majorVersion as in Step 1 and install the matching openjdk-NN-jre-headless package.

The server is killed and the journal shows Out of memory or OOM. -Xmx plus the operating system needs more RAM than the server has. Lower -Xmx in the unit file, run sudo systemctl daemon-reload and restart.

Players see Connection timed out. Confirm the server is listening with sudo ss -tlnp | grep 25565 and that UFW allows the port. If you use a domain, check that its A record points to the server.

Players see You are not white-listed on this server. Add them with whitelist add <name> through RCON. The name must match their Java Edition username exactly.

mcrcon returns Connection failed or Authentication failed. Check that enable-rcon=true is set, that the server has finished starting, and that MCRCON_PASS matches rcon.password.

The server lags with many players. Lower view-distance and simulation-distance, and check CPU with top. The server's main game loop runs on a single thread, so CPU speed per core matters more than core count.

Conclusion

Your Minecraft Java Edition server now runs as a dedicated user under systemd, starts at boot, admits only whitelisted players, can be managed over RCON from the server itself, and backs up its world every day. From here you can switch to Paper for better performance and plugin support by replacing server.jar with a Paper build, pre-generate the world to reduce lag while players explore, and copy your backups to off-site storage.