Keycloak SSL Certificate Errors: Complete Fix Guide
Last updated: March 2026
SSL certificate errors are among the most frustrating issues to debug in Keycloak deployments. The errors range from cryptic Java exceptions to silent connection failures, and the root cause can be in Keycloak’s configuration, the reverse proxy, the Java truststore, or the certificate itself. This guide covers every common SSL error scenario with concrete fixes.
Common SSL Error Messages
Before diving into solutions, here are the error messages you will encounter and what they mean:
| Error Message | Likely Cause |
|---|---|
PKIX path building failed |
Certificate not in Java truststore |
unable to find valid certification path |
Self-signed cert or missing intermediate CA |
SSL peer shut down incorrectly |
Protocol mismatch or proxy misconfiguration |
hostname in certificate didn't match |
Certificate CN/SAN does not match the hostname |
HTTPS required |
Keycloak expects HTTPS but received HTTP |
Mixed content blocked |
Frontend loaded over HTTPS but API calls go to HTTP |
Scenario 1: Self-Signed Certificate in Development
When running Keycloak locally with a self-signed certificate, other services that connect to Keycloak (identity brokering, backchannel calls) will reject the certificate because it is not issued by a trusted CA.
Fix: Add the Self-Signed Cert to Keycloak’s Truststore
Generate a self-signed certificate (if you do not have one):
# Generate a self-signed certificate
openssl req -x509 -newkey rsa:2048
-keyout keycloak-key.pem
-out keycloak-cert.pem
-days 365 -nodes
-subj "/CN=keycloak.local"
Create a PKCS12 keystore for Keycloak:
# Create a PKCS12 keystore
openssl pkcs12 -export
-in keycloak-cert.pem
-inkey keycloak-key.pem
-out keycloak-keystore.p12
-name keycloak
-password pass:changeit
Configure Keycloak to use it:
# Keycloak start command with TLS
bin/kc.sh start
--https-certificate-file=/path/to/keycloak-cert.pem
--https-certificate-key-file=/path/to/keycloak-key.pem
--hostname=keycloak.local
For Docker deployments, mount the certificates as volumes:
# docker-compose.yml
services:
keycloak:
image: quay.io/keycloak/keycloak:latest
command: start-dev --https-certificate-file=/opt/keycloak/certs/cert.pem --https-certificate-key-file=/opt/keycloak/certs/key.pem
volumes:
- ./certs/keycloak-cert.pem:/opt/keycloak/certs/cert.pem:ro
- ./certs/keycloak-key.pem:/opt/keycloak/certs/key.pem:ro
ports:
- "8443:8443"
environment:
KC_BOOTSTRAP_ADMIN_USERNAME: admin
KC_BOOTSTRAP_ADMIN_PASSWORD: admin
To quickly generate a Docker Compose file with SSL configuration, use the Keycloak Docker Compose Generator.
Scenario 2: PKIX Path Building Failed (Truststore Issues)
This is the most common SSL error in Keycloak. It occurs when Keycloak needs to make outbound HTTPS connections (identity brokering, LDAPS, SMTP over TLS) and the target server’s certificate is not in Keycloak’s truststore.
Fix: Import the Certificate into Keycloak’s Truststore
First, download the certificate from the remote server:
# Download the certificate chain
openssl s_client -connect idp.example.com:443 -showcerts </dev/null 2>/dev/null
| openssl x509 -outform PEM > idp-cert.pem
# Verify you got the right certificate
openssl x509 -in idp-cert.pem -text -noout | head -20
For Keycloak 17+ (Quarkus-based), configure the truststore using the SPI truststore:
# Create a truststore and import the certificate
keytool -importcert
-alias idp-example
-file idp-cert.pem
-keystore /opt/keycloak/conf/truststore.p12
-storetype PKCS12
-storepass changeit
-noprompt
Then configure Keycloak to use it:
bin/kc.sh start
--spi-truststore-file-file=/opt/keycloak/conf/truststore.p12
--spi-truststore-file-password=changeit
--spi-truststore-file-type=pkcs12
Alternatively, since Keycloak 24, you can use the simplified truststore configuration:
bin/kc.sh start
--truststore-paths=/opt/keycloak/conf/truststore.p12
For Docker, mount the truststore:
services:
keycloak:
image: quay.io/keycloak/keycloak:latest
command: >
start
--truststore-paths=/opt/keycloak/conf/truststore.p12
volumes:
- ./truststore.p12:/opt/keycloak/conf/truststore.p12:ro
environment:
KC_BOOTSTRAP_ADMIN_USERNAME: admin
KC_BOOTSTRAP_ADMIN_PASSWORD: admin
This issue often comes up when configuring identity providers in Keycloak. If you are brokering with an external IdP that uses a private CA, you must import that CA’s certificate.
For detailed identity brokering setup, see our guides on attribute mapping during OIDC identity brokering and setting up Entra ID SAML in Keycloak.
Scenario 3: Reverse Proxy SSL Termination
In production, Keycloak typically sits behind a reverse proxy (Nginx, HAProxy, AWS ALB) that terminates SSL. The proxy communicates with Keycloak over HTTP. This causes Keycloak to generate HTTP URLs in its metadata, breaking OIDC discovery. The Keycloak reverse proxy guide explains the supported configurations.
Fix: Configure Keycloak for Proxy Mode
For Keycloak 17+ (Quarkus):
bin/kc.sh start
--proxy-headers=xforwarded
--hostname=auth.example.com
--http-enabled=true
The --proxy-headers=xforwarded option tells Keycloak to trust X-Forwarded-* headers from the proxy.
Nginx configuration for SSL termination:
server {
listen 443 ssl;
server_name auth.example.com;
ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
# Modern TLS configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off;
# HSTS
add_header Strict-Transport-Security "max-age=63072000" always;
location / {
proxy_pass http://keycloak:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
# WebSocket support for Keycloak admin console
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
For more on running Keycloak behind proxies, see our dedicated guide on how to run Keycloak behind a reverse proxy.
Scenario 4: Let’s Encrypt Certificate Setup
Let’s Encrypt provides free, automated SSL certificates. Here is how to set it up with Keycloak.
Using Certbot with Nginx Proxy
# Install Certbot
sudo apt install certbot python3-certbot-nginx
# Obtain the certificate
sudo certbot --nginx -d auth.example.com
# Verify auto-renewal
sudo certbot renew --dry-run
Certbot will automatically update your Nginx configuration. The certificates are stored in /etc/letsencrypt/live/auth.example.com/.
Using Let’s Encrypt Directly with Keycloak
If you are running Keycloak without a reverse proxy, you can use the Let’s Encrypt certificates directly:
bin/kc.sh start
--https-certificate-file=/etc/letsencrypt/live/auth.example.com/fullchain.pem
--https-certificate-key-file=/etc/letsencrypt/live/auth.example.com/privkey.pem
--hostname=auth.example.com
Set up automatic renewal with a post-hook to restart Keycloak:
# /etc/letsencrypt/renewal-hooks/post/restart-keycloak.sh
#!/bin/bash
systemctl restart keycloak
Scenario 5: Java Cacerts Truststore
Some Keycloak deployments inherit the Java default truststore (cacerts). When you need to add custom CA certificates to the JVM-level truststore:
# Find the cacerts file
find / -name "cacerts" 2>/dev/null
# Typical location in Keycloak's embedded Java
CACERTS=/opt/keycloak/lib/lib/main/org.keycloak.keycloak-crypto-default-*.jar
# For the JVM bundled with Keycloak
CACERTS=$JAVA_HOME/lib/security/cacerts
# Import a certificate
keytool -importcert
-alias my-custom-ca
-file /path/to/ca-cert.pem
-keystore $JAVA_HOME/lib/security/cacerts
-storepass changeit
-noprompt
# List certificates in the truststore
keytool -list -keystore $JAVA_HOME/lib/security/cacerts -storepass changeit
In Docker, you can add certificates during image build:
FROM quay.io/keycloak/keycloak:latest AS builder
# Copy custom CA certificates
COPY certs/my-ca.pem /tmp/my-ca.pem
# Import into the Java truststore
USER root
RUN keytool -importcert
-alias my-custom-ca
-file /tmp/my-ca.pem
-keystore /opt/keycloak/lib/lib/main/org.keycloak.keycloak-crypto-default-*.jar
-storepass changeit
-noprompt 2>/dev/null || true
# Or use the simpler truststore-paths approach
COPY certs/truststore.p12 /opt/keycloak/conf/truststore.p12
USER keycloak
ENTRYPOINT ["/opt/keycloak/bin/kc.sh"]
Scenario 6: Hostname Mismatch
Error: hostname in certificate didn't match: <keycloak.local> != <localhost>
This occurs when the certificate’s Common Name (CN) or Subject Alternative Names (SANs) do not match the hostname used to access Keycloak.
Fix: Generate a Certificate with Correct SANs
# Create a config file with SANs
cat > san.cnf << 'EOF'
[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req
[req_distinguished_name]
CN = auth.example.com
[v3_req]
subjectAltName = @alt_names
[alt_names]
DNS.1 = auth.example.com
DNS.2 = keycloak.local
DNS.3 = localhost
IP.1 = 127.0.0.1
EOF
# Generate the certificate with SANs
openssl req -x509 -newkey rsa:2048
-keyout key.pem -out cert.pem
-days 365 -nodes
-config san.cnf
-extensions v3_req
Scenario 7: HTTPS Required Error
Error: HTTPS required when accessing the admin console or token endpoint.
This happens when Keycloak is configured to require SSL but receives an HTTP request. In development mode (start-dev), SSL is not required by default. In production mode (start), SSL is required.
Fix: Configure SSL Requirement per Realm
For development, you can lower the SSL requirement:
# Using the Admin CLI
bin/kcadm.sh update realms/my-realm -s sslRequired=NONE
--server http://localhost:8080
--realm master
--user admin
--password admin
Do not disable SSL in production. Instead, ensure your proxy is correctly forwarding HTTPS headers as shown in Scenario 3.
For a checklist of security configurations for production Keycloak, see our post on 8 default configurations to adjust on your Keycloak cluster and the Skycloak security overview.
Debugging SSL Issues
When you are stuck on an SSL error, these diagnostic commands help:
# Test SSL connection and show the certificate chain
openssl s_client -connect auth.example.com:443 -showcerts
# Verify a certificate file
openssl x509 -in cert.pem -text -noout
# Check certificate expiry
openssl x509 -in cert.pem -noout -dates
# Test specific TLS version
openssl s_client -connect auth.example.com:443 -tls1_2
# Check what certificates Java trusts
keytool -list -keystore $JAVA_HOME/lib/security/cacerts -storepass changeit | grep -i "alias"
# Verify Keycloak's OIDC discovery endpoint works over HTTPS
curl -v "https://auth.example.com/realms/my-realm/.well-known/openid-configuration"
Enable detailed SSL debugging in Keycloak by setting the Java system property:
# Add to JAVA_OPTS or KC_OPTS
export JAVA_OPTS="-Djavax.net.debug=ssl,handshake"
bin/kc.sh start
This produces verbose output showing exactly where the SSL handshake fails.
Certificate Renewal Monitoring
Expired certificates are the most common cause of production SSL outages. Set up monitoring:
#!/bin/bash
# check-cert-expiry.sh
DOMAIN="auth.example.com"
DAYS_WARNING=30
EXPIRY=$(echo | openssl s_client -connect "$DOMAIN:443" 2>/dev/null
| openssl x509 -noout -enddate 2>/dev/null
| cut -d= -f2)
EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s 2>/dev/null || date -j -f "%b %d %T %Y %Z" "$EXPIRY" +%s)
NOW_EPOCH=$(date +%s)
DAYS_LEFT=$(( (EXPIRY_EPOCH - NOW_EPOCH) / 86400 ))
if [ "$DAYS_LEFT" -lt "$DAYS_WARNING" ]; then
echo "WARNING: Certificate for $DOMAIN expires in $DAYS_LEFT days ($EXPIRY)"
exit 1
fi
echo "OK: Certificate for $DOMAIN expires in $DAYS_LEFT days"
For production deployments, integrate this with your monitoring system. Skycloak’s managed hosting includes automatic certificate management and renewal monitoring, so you never have to worry about certificate expiry.
SSL Configuration Checklist
| Item | Status |
|---|---|
| TLS 1.2+ only (disable TLS 1.0, 1.1) | Required |
| Strong cipher suites (ECDHE, AES-GCM) | Required |
| HSTS header enabled | Recommended |
| Certificate chain complete (includes intermediates) | Required |
| SANs match all hostnames used | Required |
| Auto-renewal configured (Let’s Encrypt or similar) | Recommended |
| Truststore updated for identity provider certs | As needed |
Proxy headers configured (X-Forwarded-Proto) |
If behind proxy |
For SAML-specific SSL considerations, including signing and encryption certificates, use our SAML Decoder to inspect SAML assertions and verify certificate configurations.
Wrapping Up
SSL certificate errors in Keycloak almost always come down to one of three issues: a missing certificate in the truststore, incorrect proxy configuration, or a hostname mismatch. The diagnostic commands in this guide will help you identify the root cause quickly.
For production deployments, always use certificates from a trusted CA, configure proper reverse proxy headers, and set up certificate expiry monitoring. If you want to avoid managing SSL certificates and truststore configuration entirely, Skycloak handles all of this automatically with managed Keycloak hosting, including automatic TLS certificate provisioning and renewal via our hosting infrastructure.
Ready to simplify your authentication?
Deploy production-ready Keycloak in minutes. Unlimited users, flat pricing, no SSO tax.