Dev

Configure JAVA_HOME on Rocky Linux / RHEL / Fedora

JAVA_HOME is the single environment variable that every Java tool checks first. Tomcat, Maven, Gradle, Elasticsearch, Jenkins, and dozens of other applications use it to locate the JDK. When it is wrong or missing, you get cryptic errors about missing tools or wrong Java versions. When multiple JDK versions are installed on the same system (which is common on build servers), getting JAVA_HOME right becomes even more important.

Original content from computingforgeeks.com - post 14633

This guide covers every method for setting JAVA_HOME on Rocky Linux, AlmaLinux, RHEL 10, and Fedora 42: the alternatives system for switching the system default, /etc/profile.d/ for system-wide persistence, ~/.bashrc for per-user settings, systemd unit overrides for services, and a dynamic approach that follows alternatives automatically. All commands were tested with OpenJDK 21 and 25 on Rocky Linux 10 and Fedora 42.

Verified working: March 2026 on Rocky Linux 10.1 (kernel 6.12), Fedora 42 with OpenJDK 21.0.10, OpenJDK 25.0.2

Prerequisites

  • Rocky Linux 10 / AlmaLinux 10 / RHEL 10 or Fedora 42
  • At least one JDK installed (not just JRE). Install it with:
sudo dnf install -y java-21-openjdk-devel

For a second JDK version (to practice switching):

sudo dnf install -y java-25-openjdk-devel

Verify both are installed:

ls -d /usr/lib/jvm/java-*-openjdk

You should see both JDK directories:

/usr/lib/jvm/java-21-openjdk
/usr/lib/jvm/java-25-openjdk

Find Where Java Is Installed

Before setting JAVA_HOME, you need to know the actual installation path. There are three quick ways to find it.

Follow the symlink chain from the java binary:

readlink -f $(which java)

This resolves all symlinks and returns the real path:

/usr/lib/jvm/java-21-openjdk/bin/java

JAVA_HOME is the directory two levels up from the binary, so in this case: /usr/lib/jvm/java-21-openjdk.

You can also ask Java directly for its home directory:

java -XshowSettings:properties 2>&1 | grep java.home

Output:

    java.home = /usr/lib/jvm/java-21-openjdk

Switch the System Default with alternatives

The alternatives system manages symlinks for commands that have multiple providers. When you install two JDK versions, alternatives controls which one /usr/bin/java points to.

List all installed Java versions:

sudo alternatives --config java

The output lists each installed JDK with a selection number:

There are 2 programs which provide 'java'.

  Selection    Command
-----------------------------------------------
*+ 1           /usr/lib/jvm/java-21-openjdk/bin/java
   2           /usr/lib/jvm/java-25-openjdk/bin/java

Enter to keep the current selection[+], or type selection number:

Type 2 and press Enter to switch to Java 25. The * marks the current default, and + marks the auto-selected option (highest priority).

To switch non-interactively (useful in scripts and automation):

sudo alternatives --set java /usr/lib/jvm/java-25-openjdk/bin/java
sudo alternatives --set javac /usr/lib/jvm/java-25-openjdk/bin/javac

Verify the switch:

java -version

Confirms Java 25 is now active:

openjdk version "25.0.2" 2026-01-20 LTS
OpenJDK Runtime Environment (Red_Hat-25.0.2.0.10-3) (build 25.0.2+10-LTS)
OpenJDK 64-Bit Server VM (Red_Hat-25.0.2.0.10-3) (build 25.0.2+10-LTS, mixed mode, sharing)

Remember to switch both java and javac. They are managed as separate alternatives. If you switch only java, the compiler might still point to the old version.

Set JAVA_HOME System-Wide

The alternatives system only changes which java binary the symlink points to. It does not set the JAVA_HOME environment variable. Many applications (Tomcat, Maven, Gradle) require JAVA_HOME to be explicitly set.

Create a shell profile script that sets JAVA_HOME for all users on the system:

echo 'export JAVA_HOME=/usr/lib/jvm/java-21-openjdk' | sudo tee /etc/profile.d/java.sh
echo 'export PATH=$JAVA_HOME/bin:$PATH' | sudo tee -a /etc/profile.d/java.sh
sudo chmod +x /etc/profile.d/java.sh

Verify the contents:

cat /etc/profile.d/java.sh

The file should contain:

export JAVA_HOME=/usr/lib/jvm/java-21-openjdk
export PATH=$JAVA_HOME/bin:$PATH

Load it in the current session (or log out and back in):

source /etc/profile.d/java.sh
echo $JAVA_HOME

Output:

/usr/lib/jvm/java-21-openjdk

This approach pins JAVA_HOME to a specific version. When you want to switch versions, update both alternatives and the /etc/profile.d/java.sh file.

Dynamic JAVA_HOME That Follows alternatives

If you switch Java versions frequently, maintaining a static path in /etc/profile.d/java.sh gets tedious. A dynamic approach resolves JAVA_HOME from the current alternatives selection every time a shell starts:

echo 'export JAVA_HOME=$(dirname $(dirname $(readlink -f $(which java))))' | sudo tee /etc/profile.d/java.sh
sudo chmod +x /etc/profile.d/java.sh

This command reads the java symlink, resolves it to the real path, strips /bin/java from the end, and exports the result. When you switch alternatives, JAVA_HOME follows automatically in new shell sessions.

Verify it works after switching alternatives:

sudo alternatives --set java /usr/lib/jvm/java-25-openjdk/bin/java
source /etc/profile.d/java.sh
echo $JAVA_HOME

JAVA_HOME now points to Java 25 without editing any files:

/usr/lib/jvm/java-25-openjdk

Per-User JAVA_HOME

If different users on the same system need different Java versions (common on shared build servers), set JAVA_HOME in the user’s ~/.bashrc:

echo 'export JAVA_HOME=/usr/lib/jvm/java-25-openjdk' >> ~/.bashrc
echo 'export PATH=$JAVA_HOME/bin:$PATH' >> ~/.bashrc
source ~/.bashrc

This overrides the system-wide setting from /etc/profile.d/java.sh for that specific user. The per-user PATH takes precedence, so even if alternatives points to Java 21, this user runs Java 25.

Set JAVA_HOME for systemd Services

Services managed by systemd (like Tomcat, Elasticsearch, Jenkins) do not read shell profiles. They run in an isolated environment where /etc/profile.d/ scripts have no effect. You must set JAVA_HOME directly in the service unit file.

The cleanest approach is a drop-in override that survives package updates:

sudo systemctl edit tomcat

Add the following between the comment markers:

[Service]
Environment="JAVA_HOME=/usr/lib/jvm/java-21-openjdk"

Save and close. Then reload and restart the service:

sudo systemctl daemon-reload
sudo systemctl restart tomcat

This creates a file at /etc/systemd/system/tomcat.service.d/override.conf that persists across package updates. If you edit the main unit file directly, your changes get overwritten when the package updates.

You can also set the environment in a dedicated file referenced by the unit:

echo "JAVA_HOME=/usr/lib/jvm/java-21-openjdk" | sudo tee /etc/sysconfig/tomcat

Then reference it in the service unit with EnvironmentFile=/etc/sysconfig/tomcat. Many RHEL-family packages already use /etc/sysconfig/ for this purpose.

Which Applications Need JAVA_HOME?

Not every Java application requires JAVA_HOME, but these do:

ApplicationHow it uses JAVA_HOME
Apache MavenChecks $JAVA_HOME first, falls back to $(which java)
GradleUses $JAVA_HOME or org.gradle.java.home in properties
Apache TomcatReads $JAVA_HOME in catalina.sh or systemd environment
ElasticsearchUses $JAVA_HOME if set, otherwise its bundled JDK
JenkinsNeeds $JAVA_HOME in systemd unit or /etc/sysconfig/jenkins
Hadoop / SparkRequires $JAVA_HOME in hadoop-env.sh / spark-env.sh
Android SDKUses $JAVA_HOME for sdkmanager and build tools

Common Mistakes

A few traps that catch people regularly:

  • Setting JAVA_HOME to the bin directory: JAVA_HOME=/usr/lib/jvm/java-21-openjdk/bin is wrong. Tools append /bin/java to JAVA_HOME, so they end up looking for /bin/bin/java. The correct value has no trailing /bin
  • Switching alternatives but not JAVA_HOME: if you switch alternatives to Java 25 but JAVA_HOME still points to java-21-openjdk, Maven and Tomcat will use Java 21 while the command line uses Java 25. Use the dynamic approach or update both together
  • Setting CLASSPATH with jre/lib: older guides show export CLASSPATH=$JAVA_HOME/jre/lib. The jre/ subdirectory was removed in JDK 9. Modern JDKs (17, 21, 25) do not have it. Setting CLASSPATH is rarely needed anyway
  • Forgetting javac alternatives: alternatives --config java only switches the runtime. Run alternatives --config javac separately or use --set for both
  • Expecting systemd to read shell profiles: services started by systemd do not source /etc/profile.d/ or ~/.bashrc. Use Environment= in the unit file instead

Quick Reference

TaskCommand
Find JAVA_HOMEdirname $(dirname $(readlink -f $(which java)))
List installed JDKsls -d /usr/lib/jvm/java-*-openjdk
Switch system defaultsudo alternatives --config java
Switch non-interactivelysudo alternatives --set java /usr/lib/jvm/java-25-openjdk/bin/java
Set system-wideecho 'export JAVA_HOME=...' | sudo tee /etc/profile.d/java.sh
Set per-userAdd export JAVA_HOME=... to ~/.bashrc
Set for systemd servicesudo systemctl edit servicenameEnvironment="JAVA_HOME=..."
Verifyecho $JAVA_HOME && java -version

Related Articles

AlmaLinux Configure SELinux Context for Podman Storage on Rocky Linux 10 / AlmaLinux 10 CentOS Install Node.js 22 LTS on Fedora 42/41/40 AlmaLinux Run Kubernetes on Rocky Linux 10 / AlmaLinux 10 with Minikube RHEl LPIC 101 – Managing Software Packages on Linux

1 thought on “Configure JAVA_HOME on Rocky Linux / RHEL / Fedora”

Leave a Comment

Press ESC to close