Set Up a Minecraft Java Server on a Linux VPS
We use Ubuntu 24.04 LTS and the official Vanilla server in this guide. The Java 25 commands suit the Minecraft 26.3 setup described here. Use the same Minecraft release on the server and player clients. Check the release notes before applying these commands to another version.
This setup covers Java Edition. For Bedrock or home-PC hosting, start with our Minecraft server setup guide.
Check Your VPS and Minecraft Requirements
A VPS gives us control over the operating system, game files, and update schedule. It also makes us responsible for Linux updates, access rules, backups, and recovery.
Before starting, prepare:
- A fresh Ubuntu 24.04 LTS VPS with systemd.
- An administrator account with SSH and sudo access.
- Access to the provider’s recovery console.
- A public IP address, or the provider’s documented port mapping.
- A Minecraft Java Edition account and matching client release.
- Storage for the world, working files, and backup copies.
For a small private test world, we can start with 4 GB of VPS memory and a 2 GB maximum Java heap. This is a starting configuration, not a player-capacity promise. World activity, CPU performance, view distance, and other processes change the requirements.
Leave memory for Linux and for Java allocations outside the heap. More RAM will not fix a slow or heavily shared CPU.
Choose One Server Type
| Server software | Main use | Scope of this guide |
|---|---|---|
| Vanilla | Official Minecraft behavior | Full setup below |
| Paper | Server plugins and additional administration options | Separate installation and migration checks |
| Fabric or NeoForge | Compatible mods and modpacks | Follow the selected loader and pack requirements |
Paper and mod loaders have their own release requirements. Do not swap server files on an existing world without a backup and compatibility check. Paper’s setup documentation explains its installation path.
Keep These Setup Values Consistent
| Item | Value used here |
|---|---|
| Linux service account | minecraft |
| Live server directory | /opt/minecraft/server |
| Server file | /opt/minecraft/server/server.jar |
| Fixed Java launcher | /opt/minecraft/java |
| Service name | minecraft.service |
| Game port | TCP 25565 |
| Starting heap | 1G |
| Maximum heap | 2G |
| Local backup directory | /var/backups/minecraft |
Run Linux commands through your administrator SSH session unless a step says otherwise. Blocks labeled Minecraft console contain game commands, not Linux commands.
Step 1. Connect to the VPS and Prepare Linux
On your computer, replace ADMIN_USER and VPS_IP with your details:
ssh ADMIN_USER@VPS_IP If your provider uses a custom SSH port, add -p PORT to that command.
On the VPS, check the operating system, architecture, memory, and disk:
cat /etc/os-release
uname -m
free -h
df -h /
sudo -v Confirm Ubuntu 24.04 before using this package setup. Then update the fresh host and install the tools we need:
sudo apt update
sudo apt upgrade
sudo apt install curl ca-certificates gpg nano ufw unzip If Linux requests a reboot, restart now and reconnect. Keep the provider console available while changing network rules later.
Step 2. Install the Required Java Version
Minecraft and Java have separate version numbers. Installing Java 21 does not make every newer Minecraft server work. Mojang’s Minecraft 26.1 release notes specify Java 25.
For this Java 25 setup, we use Eclipse Temurin through the official Adoptium package repository. The JDK includes the runtime needed to launch Minecraft.
Download the repository key:
curl -fsSL https://packages.adoptium.net/artifactory/api/gpg/key/public \
-o /tmp/adoptium-key.asc
gpg --dearmor --output /tmp/adoptium-key.gpg /tmp/adoptium-key.asc
sudo install -m 0644 /tmp/adoptium-key.gpg /usr/share/keyrings/adoptium.gpg Stop if a command fails. Add the repository for Ubuntu 24.04, whose release name is noble:
echo 'deb [signed-by=/usr/share/keyrings/adoptium.gpg] https://packages.adoptium.net/artifactory/deb noble main' \
| sudo tee /etc/apt/sources.list.d/adoptium.list
sudo apt update
sudo apt install temurin-25-jdk Find the Java executable installed by that package:
JAVA_BIN=$(dpkg -L temurin-25-jdk | awk '/\/bin\/java$/ {print; exit}')
printf '%s\n' "$JAVA_BIN"
"$JAVA_BIN" -version The output must identify Java 25. If the path is empty or the version differs, stop and check the installation.
Create a fixed launcher path for the game service:
sudo install -d -m 0755 /opt/minecraft
sudo ln -s "$JAVA_BIN" /opt/minecraft/java
/opt/minecraft/java -version We use this launcher in every later command. It avoids accidentally running Minecraft through another Java version selected as the system default. Check it again after Java package changes.
Step 3. Create a Separate Minecraft Account
Run the game under its own Linux account. Keep administrative access in your normal sudo account.
sudo useradd --system --user-group \
--home-dir /opt/minecraft \
--shell /usr/sbin/nologin minecraft
sudo install -d -o minecraft -g minecraft -m 0750 /opt/minecraft/server The minecraft account owns the game directory. It does not need an interactive login shell.
Check ownership:
ls -ld /opt/minecraft/server Both the owner and group should be minecraft. Do not use chmod 777 to work around permission errors.
Step 4. Download the Official Server JAR
Open the official Minecraft Java server download page or the 26.3 release page. Copy the server JAR link for the release you selected.
Replace the placeholder below with that link:
sudo -u minecraft curl -fL \
'PASTE_OFFICIAL_SERVER_JAR_URL_HERE' \
-o /opt/minecraft/server/server.jar Check that the download completed and that the archive is readable:
sudo -u minecraft ls -lh /opt/minecraft/server/server.jar
sudo -u minecraft unzip -t /opt/minecraft/server/server.jar An archive check can find a broken file, but it does not prove its origin. Use the official HTTPS download and compare its hash with official release metadata when available.
Record the release for future recovery:
printf 'Minecraft Java 26.3\n' \
| sudo -u minecraft tee /opt/minecraft/server/installed-version.txt Change that text if you selected another release. Keep the download version, client version, and record in agreement.
Step 5. Review the EULA and Start the Server Once
For the initial setup, bind Minecraft to the VPS loopback address. This prevents direct remote game connections while we prepare access controls.
On this fresh installation, create the initial settings:
sudo -u minecraft tee /opt/minecraft/server/server.properties > /dev/null <<'EOF'
server-ip=127.0.0.1
server-port=25565
online-mode=true
white-list=true
enforce-whitelist=true
enable-rcon=false
EOF Move into the game directory and run the server:
sudo -u minecraft /bin/bash -c \
'cd /opt/minecraft/server && exec /opt/minecraft/java -Xms1G -Xmx2G -jar server.jar nogui' | Option | Meaning |
|---|---|
-Xms1G | Start with a 1 GB Java heap |
-Xmx2G | Allow the heap to grow to 2 GB |
-jar server.jar | Run the downloaded server file |
nogui | Run without the graphical server window |
The first launch normally stops and creates eula.txt. Read the Minecraft EULA. If you agree, edit the file:
sudo -u minecraft nano /opt/minecraft/server/eula.txt Change eula=false 于 eula=true, save, and run the launch command again.
Wait for world preparation to finish and the console to report that startup is complete. Startup time depends on the host and world. Do not treat a fixed number of seconds as a pass condition.
Add Approved Players
In the Minecraft console, replace the example names:
whitelist add YourJavaName
whitelist add FriendJavaName
op YourJavaName Grant operator access only to people who need administration rights. A player does not need operator rights simply to join.
Stop the server through the Minecraft console:
stop Wait for the world-saving messages and the return of the Linux prompt.
Step 6. Set Player Access and World Options
With Minecraft stopped, open the settings file:
sudo -u minecraft nano /opt/minecraft/server/server.properties Update existing entries rather than adding duplicate keys.
| Setting | Starting value | Purpose |
|---|---|---|
server-ip | Leave empty | Allow listening on the host’s available interfaces |
server-port | 25565 | Set the game TCP port |
online-mode | true | Keep account authentication active |
white-list | true | Restrict access to approved players |
enforce-whitelist | true | Enforce the approved-player list |
max-players | 10 | Set an example admission limit |
gamemode | survival | Set the default game mode |
difficulty | normal | Set game difficulty |
level-name | world | Use the world folder created earlier |
view-distance | 8 | Set an initial chunk viewing distance |
simulation-distance | 6 | Set an initial simulation distance |
enable-rcon | false | Keep remote-console access off |
The empty address entry should read server-ip=. Do not enter a public address that the VPS does not own on its network interface.
These values are starting choices. A ten-player limit does not promise ten-player performance on every VPS.
Set access rules explicitly. Mojang changed the default white-list value in Minecraft 26.3, so old tutorials may describe different defaults.
Step 7. Start Minecraft Automatically with systemd
systemd manages the Minecraft process after SSH closes and can start it when the VPS boots. It also gives us one place to check status and logs.
Create the service file:
sudo nano /etc/systemd/system/minecraft.service Add:
[Unit]
Description=Minecraft Java Server
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=minecraft
Group=minecraft
WorkingDirectory=/opt/minecraft/server
ExecStart=/opt/minecraft/java -Xms1G -Xmx2G -jar server.jar nogui
Restart=on-failure
RestartSec=10
TimeoutStopSec=180
KillSignal=SIGTERM
UMask=0027
NoNewPrivileges=true
PrivateTmp=true
[Install]
WantedBy=multi-user.target Reload systemd and enable the service:
sudo systemctl daemon-reload
sudo systemctl enable --now minecraft
sudo systemctl status minecraft --no-pager
sudo journalctl -u minecraft -n 60 --no-pager active (running) shows that the process is running. Also inspect the logs for successful world startup. A process can run before the world is ready.
Use these commands for daily control:
sudo systemctl stop minecraft
sudo systemctl start minecraft
sudo systemctl restart minecraft
sudo journalctl -u minecraft -f Press Ctrl+C to leave the log viewer. That does not stop the service.
journalctl shows output; it is not a Minecraft command console. Once connected, an operator can run approved game commands from in-game chat, with a leading /.
Check a controlled stop before relying on backups. The service sends SIGTERM and allows up to 180 seconds before forced termination. Confirm world-saving messages and a clean stop in your logs. If the server times out, fix the shutdown problem or allow more time before proceeding.
Step 8. Open the Firewall and Join the Server
A public IP does not prove that the game port is reachable. The operating-system firewall and the provider’s network rules can each block a connection.
Preserve SSH Access First
Inspect the existing rules:
sudo ufw status verbose For SSH on the standard TCP port 22, allow:
sudo ufw allow 22/tcp If SSH uses another port, allow that actual port instead. Keep the current session open and the recovery console available.
Allow the Minecraft port, then enable UFW if it is not already active:
sudo ufw allow 25565/tcp
sudo ufw enable
sudo ufw status verbose Open a second SSH session to confirm that administrative access still works. Ubuntu’s firewall documentation explains UFW rule management.
In your provider panel, allow inbound TCP 25565 if a separate cloud firewall applies. Preserve the provider’s SSH rule as well. A NAT-based VPS also needs the provider’s assigned external port mapping.
A VPS with a directly assigned public address does not need a port-forwarding rule on your home router.
Check the Listener and Join
On the VPS:
sudo ss -ltnp 'sport = :25565' Look for a Java listener on a reachable interface, rather than only 127.0.0.1.
From another computer, use a TCP test if available:
nc -vz VPS_IP 25565 On Windows PowerShell, the equivalent check is:
Test-NetConnection VPS_IP -Port 25565 Then open the matching Minecraft Java client:
- Select Multiplayer.
- Select Add Server.
- Enter VPS_IP:25565.
- Join with an approved account.
Walk through the world and make a small change that you can recognize later. A TCP probe alone cannot confirm player authentication, release compatibility, or world access.
Log out of SSH and confirm the game remains available. Then announce a brief interruption, reboot the VPS, and check that players can rejoin:
sudo reboot Use a Domain Name
Create a DNS A record such as play.example.com pointing to the public IPv4 address. With the default game port, players can usually enter that name without a port suffix.
Use DNS-only mode unless your DNS provider offers a specific Minecraft-compatible proxy service. Add an AAAA record only when IPv6 connectivity and firewall rules work end to end.
An SRV record can advertise a custom port. It does not open a firewall or hide the underlying server address.
Step 9. Back Up the Server and Test Recovery
For this first server, we use a stopped backup. The job briefly takes the game offline, waits for shutdown, copies the server directory, and starts the service again.
This approach is simpler to inspect than a live backup that depends on remote-console save commands. Schedule it during a quiet period and tell players about the interruption.
Create the Backup Job
Create a private backup location:
sudo install -d -o root -g root -m 0700 /var/backups/minecraft
sudo nano /usr/local/sbin/minecraft-backup Add this script:
#!/usr/bin/env bash
set -euo pipefail
umask 077
exec 9>/run/lock/minecraft-backup.lock
flock -n 9 || exit 1
was_running=0
if systemctl is-active --quiet minecraft; then
was_running=1
fi
restart_if_needed() {
if [ "$was_running" -eq 1 ]; then
systemctl start minecraft
fi
}
trap restart_if_needed EXIT
systemctl stop minecraft
if systemctl is-active --quiet minecraft; then
echo 'Backup stopped: Minecraft is still active.' >&2
exit 1
fi
result=$(systemctl show minecraft -p Result --value)
if [ "$result" != 'success' ]; then
echo "Backup stopped: service result is $result." >&2
exit 1
fi
stamp=$(date -u +%Y%m%dT%H%M%S%NZ)
archive="/var/backups/minecraft/server-$stamp.tar.gz"
tar -czf "$archive.partial" -C /opt/minecraft server
tar -tzf "$archive.partial" >/dev/null
mv "$archive.partial" "$archive"
printf 'Created %s\n' "$archive" Set permissions and run it once:
sudo chmod 0750 /usr/local/sbin/minecraft-backup
sudo /usr/local/sbin/minecraft-backup
sudo systemctl status minecraft --no-pager
sudo ls -lh /var/backups/minecraft The script keeps the JAR, version record, world files, configuration, and player lists in the archive. It does not remove older backups. Check available disk space and remove old copies only after confirming your retention needs and off-server copies.
If the copy fails, inspect the error and any .partial archive. The script attempts to restart a service that was running before the backup, but check the logs and confirm players can reconnect.
Schedule the Backup
Create /etc/systemd/system/minecraft-backup.service:
[Unit]
Description=Back up Minecraft with a short service stop
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/minecraft-backup Create /etc/systemd/system/minecraft-backup.timer:
[Unit]
Description=Daily Minecraft backup
[Timer]
OnCalendar=*-*-* 04:00:00
Unit=minecraft-backup.service
[Install]
WantedBy=timers.target The schedule uses the VPS time zone. Check it with timedatectl, then enable the timer:
sudo systemctl daemon-reload
sudo systemctl enable --now minecraft-backup.timer
sudo systemctl list-timers minecraft-backup.timer Review job results regularly:
sudo journalctl -u minecraft-backup.service -n 50 --no-pager
sudo systemctl --failed This timer runs at the scheduled time when the VPS is online; it does not catch up a missed run at boot. Choose a schedule and monitoring method that meet your recovery needs.
Keep a copy outside the VPS. A local archive does not protect against loss of the VPS disk. Also save the service unit and backup job configuration in your recovery records.
Restore a Copy Before You Need It
Choose a completed archive from the backup listing. Replace BACKUP_FILENAME.tar.gz below with its exact name:
sudo install -d -o minecraft -g minecraft -m 0750 /opt/minecraft/restore-test
sudo tar -xzf /var/backups/minecraft/BACKUP_FILENAME.tar.gz \
-C /opt/minecraft/restore-test
sudo chown -R minecraft:minecraft /opt/minecraft/restore-test Use a fresh test directory for each exercise. Edit the restored settings with sudo -u minecraft nano /opt/minecraft/restore-test/server/server.properties so they use:
server-ip=127.0.0.1
server-port=25566 Keep authentication and the allowlist active. On a small VPS, stop the live server during this test so two Java processes do not exhaust memory:
sudo systemctl stop minecraft-backup.timer
sudo systemctl stop minecraft
sudo -u minecraft /bin/bash -c \
'cd /opt/minecraft/restore-test/server && exec /opt/minecraft/java -Xms1G -Xmx2G -jar server.jar nogui' From a second terminal on your computer, create an SSH tunnel:
ssh -N -L 25566:127.0.0.1:25566 ADMIN_USER@VPS_IP Add your custom SSH port if needed. In Minecraft, join localhost:25566. Confirm the expected world, your player data, and the change made before the backup.
In the restored server’s Minecraft console, enter stop. Close the tunnel, then start the live service and timer:
sudo systemctl start minecraft
sudo systemctl start minecraft-backup.timer Record the archive name, restored release, result, and recovery time. An archive that opens is useful; a world that you can restore and join provides stronger proof.
Step 10. Update Minecraft and Roll Back Safely
Read the new release notes before updating. Check its Java requirement and coordinate the client update with players.
Use this order:
- Stop the backup timer and ensure no backup job is running.
- Stop Minecraft cleanly.
- Run the backup script while Minecraft is stopped. It will leave the service stopped.
- Record the completed pre-update archive name.
- Test the new release against a separate copy of that backup.
- Download the approved new JAR as server.jar.new and check it.
- Replace the live JAR while the service remains stopped.
- Update the version record and start Minecraft.
- Check logs, player access, world state, and saving.
- Start the backup timer again.
Do not let a scheduled backup race with an update or restore. If a backup job is active, let it finish before changing the live files.
Restore the Pre-Update State
If an update fails, stop the service and timer. Preserve the failed state before restoring:
sudo systemctl stop minecraft-backup.timer
sudo systemctl stop minecraft
cd /opt/minecraft
sudo mv server "server-before-rollback-$(date -u +%Y%m%dT%H%M%SZ)"
sudo tar -xzf /var/backups/minecraft/PRE_UPDATE_BACKUP.tar.gz -C /opt/minecraft
sudo chown -R minecraft:minecraft /opt/minecraft/server Replace PRE_UPDATE_BACKUP.tar.gz with the recorded archive. Confirm that /opt/minecraft/java still points to a runtime supported by the restored release. Restore its previous setting if you changed it during the update.
Then start the service, check the world, and restart the timer:
sudo systemctl start minecraft
sudo journalctl -u minecraft -n 60 --no-pager
sudo systemctl start minecraft-backup.timer Rollback returns the world to the backup time. Players lose changes made after that point. Replacing only the JAR does not reverse changes a newer release made to world data.
Fix Common Minecraft Linux Server Errors
Start with the service log:
sudo journalctl -u minecraft -n 100 --no-pager | Symptom | First checks | Next action |
|---|---|---|
| UnsupportedClassVersionError | Server release and /opt/minecraft/java -version | Install the required runtime and correct the launcher path |
| EULA message repeats | eula.txt and service working directory | Check agreement status and file location |
| Unable to access JAR | JAR path and permissions | Correct the filename or ownership |
| Invalid or corrupt JAR | Download and archive check | Download again from the official source |
| Service fails at CHDIR | Working directory and parent permissions | Correct directory access |
| Failed to bind to port | Listening processes and configured address | Stop duplicate instances or correct the bind address |
| Connection refused | Process, listening socket, address, and reject rules | Check the listener before changing network rules |
| Connection times out | Provider firewall, UFW, routing, and NAT mapping | Test the network path from another host |
| Player is not allowed | Account name and allowlist | Add the intended account through an operator or console |
| Client/server version mismatch | Both Minecraft releases | Use matching releases |
| Process disappears or reports Killed | Kernel log and available memory | Check for memory exhaustion before increasing the heap |
| Disk is full | World growth, logs, and backups | Free space without deleting the only recovery copy |
For memory-related shutdowns, inspect:
sudo journalctl -k -n 100 --no-pager
free -h
df -h Do not turn off authentication or the entire firewall to make a connection test pass. Fix the failed layer.
Check Performance Before Buying More Resources
Minecraft performance problems can come from the network, the server, or the player’s computer.
| Problem | Typical sign | Useful check |
|---|---|---|
| Network delay | Delayed actions while server processing remains healthy | Player routes, latency, and packet loss |
| Slow server ticks | World actions fall behind for several players | Tick timing, CPU load, active chunks, and entities |
| Client frame-rate limits | One player sees poor rendering performance | Client settings and local hardware |
Minecraft normally targets 20 ticks per second. That leaves about 50 milliseconds for each tick at that rate. Repeated processing above that budget can make the world fall behind.
Use the profiling tools available in your selected release. Do not copy a Paper-only command into a Vanilla server and assume it exists there.
Check view distance and simulation distance before increasing heap size. Change one setting, repeat the same workload, and compare the result. More memory helps only when memory is part of the limit.
A VPS near the main player group can reduce network delay, but location cannot fix an overloaded CPU. Choose resources and location as separate decisions.
Minecraft Java Server on Linux VPS FAQs
Which Java version does my Minecraft server need?
Use the requirement for your exact Minecraft release. Minecraft 26.1 moved to Java 25. Older servers and modpacks can need another runtime. Check the release notes before downloading the JAR, and confirm which executable your service runs.
Does Minecraft keep running after I close SSH?
Yes, when systemd manages it as shown here. A directly launched process in a normal SSH terminal may stop when the session closes. Also enable the service if you want Minecraft to start after a VPS reboot.
Do I need port forwarding on a VPS?
A VPS with a directly assigned public address normally needs firewall rules, not home-router port forwarding. A NAT-based VPS needs its provider’s port mapping. Check the address and network model included with your plan.
Why can I reach port 25565 but still not join?
A reachable TCP port only proves that a service accepts a connection. Check the Minecraft release, Java Edition client, allowlist, account authentication, and server log. A different process can also be listening on the expected port.
Can I run Minecraft on a VPS with 4 GB of RAM?
A 4 GB VPS can be a starting point for a small private Vanilla workload. Leave space for Linux and Java memory outside the heap. Test your world and settings before setting a player limit. CPU performance can become the limit first.
Can Bedrock players join this Java server?
Not through the standard Vanilla setup shown here. Crossplay needs additional software such as Geyser and a supported deployment method. Check its current client support, authentication requirements, and network ports before offering crossplay.
Can I move a single-player world to the VPS?
Yes. Back up both worlds, stop the service, and copy a compatible Java world into the server directory. Set level-name to its folder name and correct ownership. Keep the original copy until you have checked player data, world loading, and saving.
Can I undo a Minecraft server update?
You can restore the pre-update world, configuration, and compatible software from a backup. Do not assume a world opened by a newer release can safely run on an older JAR. A rollback also removes changes made after the backup.
Choose Hosting for Your Minecraft Workload
A useful Minecraft setup starts with the release, world, players, and location. Choose a plan from those needs, then measure the server under normal play.
Our Linux VPS hosting page provides a starting point for comparing VPS options. For a workload that needs a hardware review, see our dedicated game servers.
Share your expected active players, Minecraft release, mods or plugins, player locations, and budget with our team. We can discuss the infrastructure options against those requirements.
