Many server applications need Java: Minecraft servers, Jenkins, Elasticsearch/OpenSearch, Spring Boot apps, Tomcat, Kafka and more. Ubuntu and Debian package OpenJDK, the open-source reference implementation, in several versions.

Which version?

Use a long-term support (LTS) release unless your software says otherwise:

Version Status
Java 17 LTS, widely supported
Java 21 LTS, current default for many apps (Minecraft 1.20.5+, Jenkins)
Java 25 Newest LTS (released September 2025)

Check your application’s documentation — running an app on an unsupported Java version is a common source of startup errors.

JRE or JDK?

  • JRE (runtime) — enough to run Java applications. Use the -headless variant on servers (no GUI libraries).
  • JDK (development kit) — compiler and tools (javac, jcmd, jstack); needed to build Java software, and handy for diagnostics.

Install

sudo apt update
apt search openjdk | grep -E '^openjdk-[0-9]+-jre-headless'    # what's available
sudo apt install -y openjdk-21-jre-headless                      # runtime only
# or
sudo apt install -y openjdk-21-jdk-headless                      # full JDK
java -version

default-jre-headless / default-jdk-headless install whatever version your distribution considers default.

If your release doesn’t package the version you need, use Eclipse Temurin (Adoptium) packages, which provide an apt repository for all LTS versions:

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 $(. /etc/os-release && echo $VERSION_CODENAME) main" | sudo tee /etc/apt/sources.list.d/adoptium.list
sudo apt update
sudo apt install -y temurin-21-jre

Several versions side by side

Install multiple versions and choose the default:

sudo update-alternatives --config java
sudo update-alternatives --config javac

Or point a specific app at a specific Java with its full path, e.g. /usr/lib/jvm/java-17-openjdk-amd64/bin/java — safer than changing the system default when apps need different versions.

JAVA_HOME

Some tools (Maven, Gradle, Tomcat scripts) need JAVA_HOME:

readlink -f "$(which java)" | sed 's:/bin/java::'
# /usr/lib/jvm/java-21-openjdk-amd64

Set it system-wide in /etc/environment or a file in /etc/profile.d/:

echo 'JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64' | sudo tee -a /etc/environment

Log out and back in. For services, set it in the systemd unit instead — see environment variables.

Run a Java app as a service

# /etc/systemd/system/myapp.service
[Unit]
Description=My Java app
After=network.target

[Service]
User=myapp
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/java -Xms512m -Xmx1g -jar /opt/myapp/app.jar
SuccessExitStatus=143
Restart=on-failure

[Install]
WantedBy=multi-user.target

SuccessExitStatus=143 treats the normal SIGTERM exit as success. See deploying a Spring Boot JAR.

Memory settings

The JVM reserves heap according to -Xmx (maximum) and -Xms (initial). On a VPS:

  • Leave room for the OS and the JVM’s non-heap memory (metaspace, threads, buffers) — heap around 50–75% of what you give the app.
  • In containers, modern JVMs respect memory limits; tune with -XX:MaxRAMPercentage=75.

If the OOM killer stops your Java process, the heap plus overhead exceeded available RAM — lower -Xmx or add memory.

Troubleshooting

  • UnsupportedClassVersionError — the app was compiled for a newer Java than you’re running (class file version 65 = Java 21, 61 = Java 17). Install the newer version.
  • java: command not found after installing a JDK from a tarball — add its bin to PATH, or use packages instead.
  • Wrong version used — check update-alternatives and the app’s start script (it may hard-code a path).

Related: Minecraft server on Linux and installing Jenkins.

  • Java
  • Ubuntu
  • OpenJDK