Keycloak SSL Certificate Errors: Complete Fix Guide

Guilliano Molaire Guilliano Molaire Updated April 17, 2026 8 min read

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.

Guilliano Molaire
Written by Guilliano Molaire Founder

Guilliano is the founder of Skycloak and a cloud infrastructure specialist with deep expertise in product development and scaling SaaS products. He discovered Keycloak while consulting on enterprise IAM and built Skycloak to make managed Keycloak accessible to teams of every size.

Ready to simplify your authentication?

Deploy production-ready Keycloak in minutes. Unlimited users, flat pricing, no SSO tax.

© 2026 Skycloak. All Rights Reserved. Design by Yasser Soliman