Running a Minecraft server on a VPS gives you 24/7 uptime, stable IP, and far more performance headroom than a home PC or a shared game panel. This guide walks through a clean setup that survives reboots, restarts itself on crashes, and backs up your world automatically.
We'll use Paper, the performance-focused Minecraft: Java Edition server software. It's fully Vanilla-compatible but handles chunk loading, redstone, and entity ticking far more efficiently than the official JAR.
minecraft usersystemd so it restarts on boot and crashes25565 on the firewallTotal time: roughly 20 minutes.
play.example.comModern Minecraft is memory-hungry. A 1 GB box technically runs it but will stutter the moment someone loads new chunks.
Minecraft 1.20.5 and newer require Java 21. Install the Temurin JDK:
sudo apt update
sudo apt install -y wget apt-transport-https gpg
wget -qO - https://packages.adoptium.net/artifactory/api/gpg/key/public \
| sudo gpg --dearmor -o /etc/apt/keyrings/adoptium.gpg
echo "deb [signed-by=/etc/apt/keyrings/adoptium.gpg] \
https://packages.adoptium.net/artifactory/deb \
$(awk -F= '/^VERSION_CODENAME/{print $2}' /etc/os-release) main" | \
sudo tee /etc/apt/sources.list.d/adoptium.list
sudo apt update
sudo apt install -y temurin-21-jre
java -version
You should see openjdk version "21.0.x". If you're running an older modpack stuck on 1.16.5, install temurin-8-jre instead.
Never run game servers as root. Create a system user with its own home directory:
sudo adduser --system --group --home /opt/minecraft minecraft
All files and the process itself will live under this user.
Switch to the new user and grab the latest Paper build for your target version:
sudo -u minecraft -H bash -lc '
cd /opt/minecraft
MC_VERSION="1.21.4"
BUILD=$(curl -s "https://api.papermc.io/v2/projects/paper/versions/$MC_VERSION/builds" \
| grep -o "\"build\":[0-9]*" | tail -1 | cut -d: -f2)
curl -o server.jar -L \
"https://api.papermc.io/v2/projects/paper/versions/$MC_VERSION/builds/$BUILD/downloads/paper-$MC_VERSION-$BUILD.jar"
'
Check the file landed:
ls -lh /opt/minecraft/server.jar
Paper requires you to accept Mojang's EULA before it starts. Create the file and do a first boot to generate defaults:
sudo -u minecraft -H bash -lc '
cd /opt/minecraft
echo "eula=true" > eula.txt
java -Xms2G -Xmx2G -jar server.jar nogui
'
The server boots, generates the world, then shuts down when you Ctrl+C. Expect this first run to take a minute or two. server.properties now exists and can be edited.
Common server.properties tweaks:
motd=My VPS-hosted Paper server
max-players=20
view-distance=10
simulation-distance=8
online-mode=true
difficulty=normal
white-list=true
Keep online-mode=true unless you know exactly why you're turning it off. Cracked servers get griefed within hours.
A rule of thumb: leave 1-2 GB for the OS, give the rest to the server. On an 8 GB VPS, allocate 6 GB:
-Xms6G -Xmx6G
Matching -Xms and -Xmx prevents the GC from resizing the heap during play. You'll wire these flags into the systemd unit in the next step.
The community-tested Aikar flags improve GC behavior on most servers:
-XX:+UseG1GC -XX:+ParallelRefProcEnabled -XX:MaxGCPauseMillis=200 \
-XX:+UnlockExperimentalVMOptions -XX:+DisableExplicitGC \
-XX:+AlwaysPreTouch -XX:G1NewSizePercent=30 -XX:G1MaxNewSizePercent=40 \
-XX:G1HeapRegionSize=8M -XX:G1ReservePercent=20 -XX:G1HeapWastePercent=5 \
-XX:G1MixedGCCountTarget=4 -XX:InitiatingHeapOccupancyPercent=15 \
-XX:G1MixedGCLiveThresholdPercent=90 -XX:G1RSetUpdatingPauseTimePercent=5 \
-XX:SurvivorRatio=32 -XX:+PerfDisableSharedMem -XX:MaxTenuringThreshold=1 \
-Dusing.aikars.flags=https://mcflags.emc.gs -Daikars.new.flags=true
Create /etc/systemd/system/minecraft.service:
[Unit]
Description=Paper Minecraft Server
After=network.target
[Service]
Type=simple
User=minecraft
Group=minecraft
WorkingDirectory=/opt/minecraft
ExecStart=/usr/bin/java \
-Xms6G -Xmx6G \
-XX:+UseG1GC -XX:+ParallelRefProcEnabled \
-XX:MaxGCPauseMillis=200 -XX:+UnlockExperimentalVMOptions \
-XX:+DisableExplicitGC -XX:+AlwaysPreTouch \
-XX:G1NewSizePercent=30 -XX:G1MaxNewSizePercent=40 \
-XX:G1HeapRegionSize=8M -XX:G1ReservePercent=20 \
-XX:G1HeapWastePercent=5 -XX:G1MixedGCCountTarget=4 \
-XX:InitiatingHeapOccupancyPercent=15 \
-XX:G1MixedGCLiveThresholdPercent=90 \
-XX:G1RSetUpdatingPauseTimePercent=5 \
-XX:SurvivorRatio=32 -XX:+PerfDisableSharedMem \
-XX:MaxTenuringThreshold=1 \
-jar server.jar nogui
Restart=on-failure
RestartSec=10s
SuccessExitStatus=0 1
[Install]
WantedBy=multi-user.target
Enable and start it:
sudo systemctl daemon-reload
sudo systemctl enable --now minecraft
sudo systemctl status minecraft
Tail the log live:
sudo journalctl -u minecraft -f
You should see the familiar Done (x.xxxs)! For help, type "help" line. The server now starts on boot and restarts on crashes.
Minecraft uses TCP 25565. If you're running UFW:
sudo ufw allow 22/tcp
sudo ufw allow 25565/tcp
sudo ufw enable
Verify from another machine:
nc -zv your-vps-ip 25565
Or just try connecting from the Minecraft client.
systemd runs the JVM in the background, which means you lose the interactive console. The cleanest workaround is to install mcrcon and use RCON.
Enable RCON in server.properties:
enable-rcon=true
rcon.password=a-strong-password
rcon.port=25575
Restart the server, then run commands from the host:
mcrcon -H 127.0.0.1 -P 25575 -p 'a-strong-password' 'say Hello from the VPS'
Never expose RCON publicly. Keep it bound to 127.0.0.1 and block 25575 at the firewall.
Create /usr/local/bin/minecraft-backup.sh:
#!/usr/bin/env bash
set -euo pipefail
SERVER_DIR="/opt/minecraft"
BACKUP_DIR="/var/backups/minecraft"
DATE="$(date +%F_%H%M)"
RCON="mcrcon -H 127.0.0.1 -P 25575 -p a-strong-password"
mkdir -p "$BACKUP_DIR"
$RCON "save-off" "save-all flush" || true
sleep 2
tar -czf "$BACKUP_DIR/world-$DATE.tar.gz" \
-C "$SERVER_DIR" world world_nether world_the_end
$RCON "save-on" || true
find "$BACKUP_DIR" -name "world-*.tar.gz" -mtime +7 -delete
Schedule a daily snapshot at 04:00:
sudo chmod +x /usr/local/bin/minecraft-backup.sh
echo "0 4 * * * root /usr/local/bin/minecraft-backup.sh" | \
sudo tee /etc/cron.d/minecraft-backup
For off-site safety, sync /var/backups/minecraft to S3, Backblaze B2, or another VPS with rclone on the same schedule.
Point a subdomain at your VPS so players don't have to remember an IP:
play.example.com A YOUR_VPS_IPV4
If you want to hide the port, add an SRV record:
_minecraft._tcp.play SRV 0 5 25565 play.example.com.
Players can then connect to play.example.com even if you later switch to a non-default port.
view-distance from 10 to 8 and TPS usually jumps./tps or /mspt command. Anything consistently under 19 means something is bottlenecked.If you also want to keep the SSH side tight, our Tailscale guide shows how to put admin access behind a private network while leaving the game port open.
Server won't start, "Unsupported class file major version" - Java version mismatch. Modern Minecraft needs Java 21.
"Failed to bind to port" - Another process already owns 25565. Find it with sudo ss -tlnp | grep 25565 and stop it, or change the port.
High CPU at idle - usually a runaway spawner or ticking entity. Install Spark and profile a tick.
Clients see "Outdated server/client" - the Minecraft version on the server doesn't match the client. Upgrade Paper or tell players to switch profiles.
A VPS-hosted Paper server, managed with systemd and backed up nightly, will outlast any home-rig setup and cost a fraction of a managed game panel. You keep full SSH access, can install any plugin, and move everything to a bigger box in minutes if your community grows.
Our Linux VPS plans are a good fit for game servers - low-latency networks, NVMe storage, and generous RAM on the larger tiers. See the options.