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
-headlessvariant 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 foundafter installing a JDK from a tarball — add itsbintoPATH, or use packages instead.- Wrong version used — check
update-alternativesand the app’s start script (it may hard-code a path).
Related: Minecraft server on Linux and installing Jenkins.