Where is cacerts?
- Java 9 and later:
$JAVA_HOME/lib/security/cacerts - Java 8:
$JAVA_HOME/jre/lib/security/cacerts
The default password is changeit. Which file a running application really uses is shown by -Djavax.net.debug=ssl:trustmanager.
Which certificate to import?
Import your company’s root CA (or the issuing intermediate CA), not the server certificate. A server certificate becomes invalid at every change; the CA lasts for years. Get the CA from IT or from the server’s chain. The SSL check shows all certificates and downloads them as PEM.
The keytool command
# Java 9 and later keytool -importcert -cacerts -alias company-root -file company-root.crt -storepass changeit -noprompt # Java 8 keytool -importcert -keystore "$JAVA_HOME/jre/lib/security/cacerts" \ -alias company-root -file company-root.crt -storepass changeit -noprompt # check and remove again keytool -list -cacerts -alias company-root -storepass changeit keytool -delete -cacerts -alias company-root -storepass changeit
The file may be PEM or DER. On Linux and macOS you usually need sudo, because cacerts belongs to the JDK. Restart the application afterwards; Java only reads the truststore at startup.
The lasting way on Linux
A JDK update replaces cacerts and your change is gone. The packages of Debian, Ubuntu, RHEL and Fedora therefore generate cacerts from the system certificate store. Add the CA there and it applies to Java, curl, Python and everything else at once:
# Debian, Ubuntu (extension .crt, PEM format) sudo cp company-root.crt /usr/local/share/ca-certificates/ sudo update-ca-certificates # RHEL, Rocky, Alma, Fedora sudo cp company-root.crt /etc/pki/ca-trust/source/anchors/ sudo update-ca-trust
That works for the distribution’s Java packages. A manually unpacked JDK (e.g. under /opt) brings its own cacerts. Either change that one with keytool, or point to the system store with -Djavax.net.ssl.trustStore=/etc/ssl/certs/java/cacerts (Debian) or /etc/pki/ca-trust/extracted/java/cacerts (RHEL).
In Docker images
The official eclipse-temurin images can pick up CAs at startup. Put the certificates into /certificates and set USE_SYSTEM_CA_CERTS=1:
docker run -e USE_SYSTEM_CA_CERTS=1 -v ./ca:/certificates:ro my-app # or baked into the image FROM eclipse-temurin:21-jre COPY company-root.crt /usr/local/share/ca-certificates/ RUN update-ca-certificates
With other base images, use the keytool command from above in the Dockerfile.
A separate truststore instead of cacerts
If you do not want to touch the JDK, give the application its own truststore. Important: it replaces cacerts, so it contains only what you put in. The easiest way is to copy cacerts and add the CA:
cp "$JAVA_HOME/lib/security/cacerts" truststore.p12 keytool -importcert -keystore truststore.p12 -storepass changeit -alias company-root -file company-root.crt -noprompt java -Djavax.net.ssl.trustStore=truststore.p12 -Djavax.net.ssl.trustStorePassword=changeit -jar app.jar
A truststore with only specific CAs can be built in the Java keystore helper under “PEM & CA reply”: paste the CA certificates, save as truststore, done.
FAQ
Do I have to change the changeit password?
Not necessarily for cacerts. It only protects against modification, not reading, and the contents are public certificates. What matters is that only administrators can write the file.
“Certificate was added to keystore”, but nothing changed?
Usually a different cacerts was changed than the one the application uses, e.g. with several JDKs installed. Check the file with -Djavax.net.debug=ssl:trustmanager.
Does this apply to Tomcat, Jenkins or Maven too?
Yes, they all use the truststore of the Java runtime they are started with. For Maven that is the JVM from JAVA_HOME or MAVEN_OPTS.
Can I use the company CA from the Windows store?
Yes, with -Djavax.net.ssl.trustStoreType=Windows-ROOT Java reads the Windows certificate store. No import needed.