How to Deploy a Paper Minecraft Server on Ubuntu 20.04

Paper is a high-performance Minecraft server implementation that extends Spigot with patches for improved tick performance, configurable gameplay mechanics, and an expanded plugin API. It remains compatible with Bukkit and Spigot plugins while correcting mechanics inconsistencies present in the vanilla server.
This article explains how to deploy Paper on an Ubuntu 20.04 server. It covers installing the Eclipse Temurin Java runtime from the Adoptium package repository, downloading a verified Paper build through the PaperMC Fill API, running the server under a dedicated system account managed by systemd, and opening the required firewall port.
Prerequisites
Before you begin, you need to:
- Have access to an Ubuntu 20.04 server instance as a non-root user with sudo privileges.
- Allocate at least 4 GB of RAM to the instance. Paper reserves a fixed Java heap at startup, and a 4 GB instance supports a 2 GB heap.
Install the Java Runtime
Paper requires Java 25 or later starting with Minecraft 26.1. Eclipse Temurin provides supported OpenJDK builds through the Adoptium package repository at packages.adoptium.net.
Update the package index.
console$ sudo apt update
Install the packages required to fetch the repository key and query the Paper API.
console$ sudo apt install -y wget gnupg apt-transport-https jq curl
Create the keyring directory.
console$ sudo install -m 0755 -d /etc/apt/keyrings
Download the Adoptium signing key and convert it to a binary keyring.
console$ wget -qO - https://packages.adoptium.net/artifactory/api/gpg/key/public \ | gpg --dearmor \ | sudo tee /etc/apt/keyrings/adoptium.gpg > /dev/null
Grant read access to the keyring so that APT can verify the repository.
console$ sudo chmod a+r /etc/apt/keyrings/adoptium.gpg
Add the Adoptium repository and bind it to the keyring.
console$ 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
The
awkexpression resolves the release codename from/etc/os-release, which returnsfocalon Ubuntu 20.04. Thesigned-byoption scopes the key to this repository alone, unlike the deprecatedapt-key addcommand, which trusted a key across every configured repository.Refresh the package index to include the new repository.
console$ sudo apt update
Install Temurin 25.
console$ sudo apt install -y temurin-25-jdk
Verify the installed runtime.
console$ java -version
The output confirms a Temurin LTS build:
openjdk version "25.0.4" 2026-07-21 LTS OpenJDK Runtime Environment Temurin-25.0.4+7 (build 25.0.4+7-LTS) OpenJDK 64-Bit Server VM Temurin-25.0.4+7 (build 25.0.4+7-LTS, mixed mode, sharing)
Create a Service Account
Running a public-facing game server under a dedicated unprivileged account limits the damage a compromised plugin or exploit can cause. The account requires no login shell because systemd starts the process directly.
Create a system user with a home directory and no interactive shell.
console$ sudo useradd -r -m -U -d /opt/minecraft -s /usr/sbin/nologin minecraft
Create the server directory and assign ownership to the new account.
console$ sudo install -d -o minecraft -g minecraft /opt/minecraft/paper
Deploy Paper
PaperMC distributes builds through the Fill API at fill.papermc.io. The previous api.papermc.io/v2 endpoint now returns HTTP 410 Gone and cannot supply builds. Every Fill response includes a SHA-256 checksum, which lets you confirm the download before running it.
Query the API for the current version identifier.
console$ PAPER_VERSION=$(curl -s https://fill.papermc.io/v3/projects/paper \ -H "accept: application/json" \ | jq -r '.versions | to_entries | map(select(.key|test("^[0-9]"))) | .[0].value[0]')
Display the resolved version.
console$ echo "$PAPER_VERSION"
The output shows the newest release, such as
26.2.Fetch the metadata for the latest build of that version.
console$ BUILD_META=$(curl -s "https://fill.papermc.io/v3/projects/paper/versions/${PAPER_VERSION}/builds/latest" \ -H "accept: application/json")
Extract the download URL and its checksum.
console$ PAPER_URL=$(echo "$BUILD_META" | jq -r '.downloads["server:default"].url') $ PAPER_SHA=$(echo "$BUILD_META" | jq -r '.downloads["server:default"].checksums.sha256')
In the above command:
PAPER_URL: The signed object URL onfill-data.papermc.iothat serves the server JAR.PAPER_SHA: The SHA-256 digest published alongside the build.
Download the server JAR.
console$ sudo curl -fsSL -o /opt/minecraft/paper/paper.jar "$PAPER_URL"
Verify the download against the published checksum.
console$ echo "$PAPER_SHA /opt/minecraft/paper/paper.jar" | sha256sum -c -
The output reports
OK. Stop and download the file again if the check reports a mismatch./opt/minecraft/paper/paper.jar: OKTransfer ownership of the JAR to the service account.
console$ sudo chown minecraft:minecraft /opt/minecraft/paper/paper.jar
Query the version list and pick any entry rather than accepting the newest release.
List the available versions.
console$ curl -s https://fill.papermc.io/v3/projects/paper -H "accept: application/json" | jq '.versions'
Set the version manually, then repeat the metadata and download steps above.
console$ PAPER_VERSION=1.21.11
Accept the End User License Agreement
Mojang requires explicit acceptance of the Minecraft End User License Agreement before a server accepts connections. The first launch writes a template eula.txt and exits without binding a port.
Run the server once to generate the configuration files.
console$ sudo -u minecraft java -Xms2G -Xmx2G -jar /opt/minecraft/paper/paper.jar --nogui
The server writes its default files and exits with a notice:
[21:47:15 WARN]: Failed to load eula.txt [21:47:15 INFO]: You need to agree to the EULA in order to run the server. Go to eula.txt for more info.Open the generated agreement file.
console$ sudo -u minecraft nano /opt/minecraft/paper/eula.txt
Change the
eulavalue totrueafter reading the agreement.inieula=true
Save and close the file.
Run Paper as a systemd Service
A systemd unit starts Paper at boot, restarts it after a crash, and routes its console output to the journal. Stopping the unit sends SIGINT, which Paper traps to save every loaded world before exiting.
Create the unit file.
console$ sudo nano /etc/systemd/system/paper.service
Add the following configuration:
ini[Unit] Description=Paper Minecraft Server After=network-online.target Wants=network-online.target [Service] Type=simple User=minecraft Group=minecraft WorkingDirectory=/opt/minecraft/paper ExecStart=/usr/bin/java -Xms2G -Xmx2G -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 /opt/minecraft/paper/paper.jar --nogui KillSignal=SIGINT SuccessExitStatus=0 130 143 Restart=on-failure RestartSec=10s PrivateTmp=true NoNewPrivileges=true ProtectSystem=full [Install] WantedBy=multi-user.target
Save and close the file.
ExecStart: Launches Paper with the G1 garbage collector tuned for a fixed heap. Match-Xmsand-Xmxto each other, and leave at least 2 GB of system memory outside the heap for the operating system and Java metadata.KillSignal=SIGINT: Delivers the interrupt that Paper handles as a graceful shutdown, saving all dimensions before the process exits.SuccessExitStatus=0 130 143: Treats the exit codes produced bySIGINT(130) andSIGTERM(143) as clean. Without130, a normalsystemctl stopleaves the unit in afailedstate.Restart=on-failure: Recovers the server after a crash, but leaves it stopped after a deliberatesystemctl stop.ProtectSystem=full: Mounts/usrand/bootread-only for the service, restricting writes to the server directory.
Reload the systemd manager configuration.
console$ sudo systemctl daemon-reload
Enable the service to start at boot.
console$ sudo systemctl enable paper
Start the service.
console$ sudo systemctl start paper
Confirm the service is running.
console$ sudo systemctl status paper
Verify that the output reports
Active: active (running).Follow the startup log until the server reports readiness.
console$ sudo journalctl -u paper -f -o cat
World generation on a new server takes roughly 20 to 45 seconds:
[21:48:21 INFO]: Done (41.618s)! For help, type "help"Press
Ctrl+Cto stop following the log. The server keeps running.
Configure the Firewall
Paper listens on TCP port 25565. Ubuntu ships with ufw inactive, so enable it and permit both SSH and the game port before locking the host down.
Allow SSH so that enabling the firewall does not end your session.
console$ sudo ufw allow OpenSSH
Allow Minecraft client traffic.
console$ sudo ufw allow 25565/tcp
Enable the firewall.
console$ sudo ufw enable
The command warns that it may disrupt existing SSH connections and asks for confirmation. Enter
yto proceed. The preceding rule keeps your session open.Review the active rules.
console$ sudo ufw status
The output lists both services:
Status: active To Action From -- ------ ---- OpenSSH ALLOW Anywhere 25565/tcp ALLOW Anywhere OpenSSH (v6) ALLOW Anywhere (v6) 25565/tcp (v6) ALLOW Anywhere (v6)
Verify the Server
Confirm that Paper holds the port locally and answers connections from outside the instance.
Verify that the Java process is listening.
console$ sudo ss -tlnp | grep 25565
The output shows the listening socket owned by
java:LISTEN 0 4096 *:25565 *:* users:(("java",pid=26823,fd=129))Test the port from your local machine, replacing
SERVER-IPwith your instance's public IP address.console$ nc -z -w6 SERVER-IP 25565
Open the Minecraft Java Edition client, select Multiplayer, click Add Server, and enter your instance's public IP address in the Server Address field.
The server binds portNote25565only after the log printsDone. A connection attempt during world generation fails even though the service is already active.
Manage the Server
The service exposes standard systemd controls, and the journal retains the full server console history.
Stop the server, allowing it to save all worlds.
console$ sudo systemctl stop paper
Restart the server after changing a configuration file.
console$ sudo systemctl restart paper
Review recent console output.
console$ sudo journalctl -u paper -n 100 -o cat
To issue in-game commands from a terminal, enable RCON by setting enable-rcon=true, rcon.password, and rcon.port in /opt/minecraft/paper/server.properties, then restart the service. Restrict the RCON port to trusted addresses in ufw, because the protocol transmits its password without encryption.
Conclusion
You have successfully deployed Paper on your Ubuntu 20.04 server using the supported Adoptium repository for Java, a checksum-verified build from the PaperMC Fill API, and a systemd service that runs the server under a dedicated account. Adjust gameplay settings in server.properties, tune Paper-specific behavior in config/paper-global.yml, and add plugins to the plugins directory before restarting the service. For more information, visit the official Paper documentation.