Keycloak’s admin console is not just a configuration interface; it’s a full-fledged client application that itself needs to be secured by Keycloak.
Let’s say you’ve got Keycloak humming along, and you’re trying to set up Nginx as a reverse proxy to expose it to the outside world. You’ve followed some guide, and now you’re hitting a wall.
server {
listen 80;
server_name keycloak.example.com;
location / {
proxy_pass http://localhost:8080; # Assuming Keycloak is running on port 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;
}
}
You restart Nginx, try to access http://keycloak.example.com, and… it works. You see the Keycloak login page. Great! You log in as your admin user. Then you try to navigate to the "Clients" section, or maybe even the "Realm settings," and suddenly you’re back at the login page. Or worse, you get a 502 Bad Gateway error, or a redirect loop. This is a classic symptom of Keycloak and its reverse proxy setup not playing nice.
The core issue is that Keycloak needs to know its public URL to generate correct redirects and build absolute URLs for its resources. When you’re behind a proxy, Keycloak, running on localhost:8080, might think its public URL is http://localhost:8080 if not told otherwise. Nginx, on the other hand, is presenting it as http://keycloak.example.com. This mismatch causes problems, especially with redirects and when Keycloak tries to serve static assets or generate links.
Here are the most common culprits and how to fix them:
-
Keycloak’s
proxy-address-forwardingsetting: By default, Keycloak doesn’t trust headers that indicate it’s behind a proxy. You need to explicitly enable this.- Diagnosis: Check your Keycloak startup arguments or
standalone.xml/standalone-ha.xmlconfiguration file. - Fix: When starting Keycloak, add the following argument:
If you’re using the XML configuration, find the./standalone.sh -Dkeycloak.http.proxy-address-forwarding=trueinterfacessection and add theproxy-address-forwarding="true"attribute to thehttporhttpsinterface.<interfaces> <interface name="management"> <http-interface security-realm="management-ssl"/> </interface> <interface name="public"> <http-interface> <proxy-address-forwarding value="true"/> </http-interface> </interface> <interface name="private"> <http-interface/> </interface> </interfaces> - Why it works: This tells Keycloak to trust the
X-Forwarded-Proto,X-Forwarded-For, andHostheaders that Nginx is sending, allowing it to reconstruct the correct public URL.
- Diagnosis: Check your Keycloak startup arguments or
-
Incorrect
Hostheader in Nginx: Keycloak uses theHostheader to determine its public hostname. If Nginx isn’t passing it correctly, Keycloak will use the wrong one.- Diagnosis: Use
tcpdumpor Nginx’s access logs to inspect theHostheader received by Keycloak (if it’s accessible directly) or by Nginx itself. - Fix: Ensure your Nginx
locationblock includes:
This passes the originalproxy_set_header Host $host;Hostheader from the client’s request to Keycloak. - Why it works: This ensures Keycloak sees
keycloak.example.comas the requested host, notlocalhostor the server’s internal IP.
- Diagnosis: Use
-
Missing
X-Forwarded-Protoheader: If your Keycloak is accessible via HTTPS externally but Nginx is handling the SSL termination (HTTP internally to Keycloak), Keycloak needs to know the original protocol was HTTPS.- Diagnosis: Check Keycloak’s logs for redirect loops or errors related to insecure connections.
- Fix: Add the following to your Nginx
locationblock:proxy_set_header X-Forwarded-Proto $scheme; - Why it works:
$schemewill behttporhttpsbased on how the client connected to Nginx. Keycloak uses this to correctly generate absolute URLs, ensuring links point to the right protocol (e.g.,https://keycloak.example.com).
-
Keycloak’s
frontendUrlnot set (especially for HTTPS): This is a crucial setting within Keycloak itself, overriding proxy headers in certain scenarios or when you want explicit control.- Diagnosis: Look for redirect loops or broken links within Keycloak’s UI, especially after logging in.
- Fix: Configure the
frontendUrlin Keycloak’sstandalone.xmlor via command-line arguments. If Nginx is terminating SSL, yourfrontendUrlshould behttps://keycloak.example.com.- Command-line:
./standalone.sh -Dkeycloak.frontendUrl=https://keycloak.example.com - XML (
standalone.xml): Add this system property to thesystem-propertiessection:<system-properties> <property name="keycloak.frontendUrl" value="https://keycloak.example.com"/> </system-properties>
- Command-line:
- Why it works: This explicitly tells Keycloak its public-facing URL, ensuring all generated links and redirects use this correct address, regardless of what headers it might otherwise infer.
-
Nginx not correctly proxying WebSocket connections: Keycloak uses WebSockets for real-time features (like notifications in the admin console). If Nginx doesn’t handle these correctly, parts of the UI might break or fail to load.
- Diagnosis: Check your browser’s developer console for WebSocket connection errors or failed requests. Keycloak logs might also show issues.
- Fix: Add these headers to your Nginx
locationblock:proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; - Why it works:
UpgradeandConnection: upgradeheaders signal to the upstream server (Keycloak) that the client wants to switch protocols to WebSocket.proxy_http_version 1.1is necessary for theUpgradeheader to be properly handled.
-
Keycloak’s internal
HostandPortmismatch: Even with proxy forwarding, if Keycloak is configured to listen on specific interfaces or ports that Nginx isn’t mapping correctly, you can get routing issues.- Diagnosis: Keycloak logs will often show "could not find interface" or binding errors if it can’t start correctly. Check if Keycloak is trying to bind to
localhost:8080but Nginx is only exposing it onkeycloak.example.com. - Fix: Ensure Keycloak is listening on an interface accessible by Nginx (often
0.0.0.0for all interfaces, or a specific internal IP) and that the port matches what Nginx is proxying to. If you’re usingstandalone.xml, theinterfacessection is key. For simplicity, oftenlocalhostor127.0.0.1works if Nginx is on the same machine.
Or via command line:<interfaces> <interface name="public"> <http-interface hostname="localhost" port="8080"> <proxy-address-forwarding value="true"/> </http-interface> </interface> </interfaces>./standalone.sh -b=localhost -bport=8080. - Why it works: This ensures Keycloak is listening on an address and port that Nginx can successfully connect to and forward requests from.
- Diagnosis: Keycloak logs will often show "could not find interface" or binding errors if it can’t start correctly. Check if Keycloak is trying to bind to
After applying these fixes, remember to restart both Nginx and Keycloak. The next error you’ll likely encounter if you haven’t configured HTTPS is a "Your connection is not private" warning, prompting you to set up SSL termination in Nginx.