Keycloak with different urls per realm, behind apache reverse proxy

Hey there all,

We have two organizations in the dayjob – corporate and operations, which have differing realm requirements, plus a third “master” realm which we’re using only for admin purposes. We are keeping Keycloak behind an apache reverse proxy, which terminates SSL and then makes another connection to keycloak’s 8443 connection internally, thusly:

  <Location "/">
    Require all granted
    DirectoryIndex disabled
          ProxyPass https://localhost:8443/ retry=0 timeout=30
    ProxyPassReverse https://localhost:8443/
        </Location>

  <LocationMatch "(/realms/|/resources/|/robots.txt)$">
    Require all granted
  </LocationMatch>

# SSL Proxy directives
  SSLProxyEngine On
  SSLProxyVerify none
  SSLProxyCheckPeerCN     off
  SSLProxyCheckPeerName   off
  SSLProxyCheckPeerExpire   off
  ProxyPreserveHost On

  ## Server aliases
  ServerAlias sso.engineering.our.org

  ## SSL directives
  SSLEngine on


I’m starting keycloak with proxy=edge proxy-headers=xforwarded and hostname-backchannel-dynamic=false

If I try to visit my admin server directly (https://int.sso.our.org/admin/master/console), things work and I’m redirected to /realms/master.

However, If I try to go directly to the URL I’ve set for one of the other realms, it tries to redirect me to /admin/master/console and I get an error that says “Something Went Wrong” with the helpful text “SomethingWentWrongDescription”…

So, here are my questions:

  1. What should the behavior be when I just go to the “bareword” host in the URL? Is this not a valid way to test if it’s working, or am I forced to start configuring clients that read the various XML files.

  2. Is there a way to make it such that the user can log in to manage their SSO settings for that realm or something, or must that be done by an external link? (Or mod_rewrite?) I would like to somehow make it the default behavior if I go to the bare page, and this feels like an option that should exist within Keycloak.

  3. What’s the actual format of the Frontend URL in realm settings? Clearly, it needs to have a protocol like https:// (I get errors without it), but should there be a trailing slash? Should there be a pointer deeper at the url realm? Could the tool tips for this setting maybe mention this? Or the manual?

  4. Am I missing anything obvious here? The manual pages for two different hostname providers, two different ways to set Forwarded headers, two different Frontend and Backend settings, plus the requirements to set/not-set some options when hostnames are/are not set is throwing me for a loop. Help?

Hello, what version of Keycloak are you using ? Keycloak starting options have evolved between v24 and v26.
v24 - Deprecated proxy option
v25 - New hostname options - hostname v2 feature
v26 - Removed deprecated proxy option

Did you see this part of the documentation about Using a reverse proxy ? It says :

If the TLS connection is terminated at the reverse proxy (edge termination), enabling HTTP through the http-enabled setting is required.

If you get “Something Went Wrong” error in your browser, try to look at the network tab of your browser developer console, you’ll have more detail about which request failed. Also check your keycloak logs if a request failed with a 500 error code.

Hope that will help.

I’m running 26.0.7 My relevant configurations are currently:

hostname=https://sso.my.org
hostname-admin=https://int.sso.my.org
http-enabled=true
hostname-strict=false
proxy-headers=xforwarded
hostname-backchannel-dynamic=false

Our internal engineering group uses an entirely different hostname, which I guess I have to set via the admin UI for that realm. I’m trying to see if I can get these to load cleanly without setting up a full SAML client, but so far no joy, neither by going to just https://sso.my.org (that just redirects me to the admin console) or to https://sso.my.org/realms/test/account (that doesn’t load). A normal saml2 flow does work.

I had not noticed the requirement to set http-enabled, but I’m switching over to that now, just to be consistent with best recommendations. That said, I feel like that assumes that you’re not configuring apache to speak https to the internal proxy, which I’m doing, and it works for the most part. Do you know if there’s more detail as to why the docs say this is required?

That doc also points at a bad url: " You only need to proxy port 8443 (or 8080 ) even when you use different host names for frontend/backend and administration as described at {links_server_configure-production_name}"

At any rate, when I try to go to https://sso.my.org/realms/test/account, I get a “spinner” and the web console says:

Failed to load resource: the server responded with a status of 403 (Forbidden)

Where the url it’s trying to load is:

https://sso.my.org/realms/test/protocol/openid-connect/login-status-iframe.html/init?client_id=account-console&origin=https%3A%2F%2Fsso.my.org

I believe I have also set the Frontend URL properly to https://sso.my.org in the “test” realm.

Hello, the broken link in the doc should be this one Configuring Keycloak for production - Keycloak .

Regarding the option http-enabled, as the doc says, it is only required when TLS is terminated at the reverse proxy (edge termination), not when the proxy has a passthrough or reencrypt behaviour. If I get it right, your case is the passthrough or reencrypt behaviour (so you shouldn’t need to enable http).

The last part of this documentation Configuring the hostname (v2) - Keycloak gives a way to troubleshoot the hostname configuration. Maybe that could help. At least make sure to have read this doc about configuring the hostname, there are some important details in it.

When running Keycloak with various URLs, the most important guide is, like from @skydrinker-tox already mentioned, the Configuring the hostname guide. In this guide, the chapter “Fully dynamic URLs” https://www.keycloak.org/server/hostname#_fully_dynamic_urls is relevant.
However, for security reasons, in this case you have to check proper sent Host header values in the requests from users in your reverse proxy, otherwise an attacker might inject invalid host names.

After you configured the above properly, you have to set the proper Frontend URL in each realm, so that Keycloak knows, which realm is available under which URL.

1 Like

I think the documentation is badly worded. With reencrypt, the TLS connection is in fact terminated at the edge (as in, the certificate that the world sees is only on the proxy), but the proxy speaks HTTPS to keycloak. So saying “if it’s terminated at the edge, http is required” is sort of inconsistent. It’s terminated in at the edge in both cases, but I’d prefer to speak HTTPS between my apache and keycloak as the end goal is having keycloak and the proxy being on different boxes and doing load-balancing. We’re not there yet.

At any rate, as a debug, I’ve ripped out the encryption and am speaking plain vanilla http to keycloak now, because I want to have my setup be as consistent with the recommendations as possible, if I’m asking for help. I hope that makes sense.

There’s no sample apache proxy config supplied with Keycloak, just a bunch of “if you’re doing this, then you should do this”. I’d really love to see that fixed.

===

Given that, I am now trying to use “Fully Dynamic Hostnames”, but that still leaves my questions.

  1. How then, does keycloak know which hostname is used for the “Admin” server, as you cannot set hostname-admin without setting hostname, so I’ve gone ahead and set at least one hostname so I can set the admin one.

  2. SAML auth works with my two realms, but when I try to browse to them to access /realms/test/account, I get a 403 and a spinner. (I no longer get the SomethingWentWrong page). Keycloak (not the proxy) seems to be handing out a 403, and I don’t know why. (The logs don’t say why a 403 is sent. But it’s Java, I don’t expect useful logs).

  3. What should the behavior be, if you try to go to a bareword url? Right now it’s a spinner that keeps spinning while an iframe gets a 403. It’s clearly trying to launch a login page, but can’t, for an unknown reason. That doesn’t seem helpful to anyone. Either get me there, or show something in the browser window without having to dig at developer mode.

  4. Should it be possible for a user (not an admin) to directly log in to a given realm and do things like reset their 2fa tokens, or is this not part of the design. If so, does keycloak provide a url that should be used that’s not the “admin url”, that can only act on a single realm, or do I need to create a form somewhere in my infrastructure that points the user there?

As pasted above, ProxyPreserveHost is set in my apache config, which causes the correct host headers to be sent.

As asked in my other discussion, if I go “fully dynamic”, how do I indicate which hostname is the “admin” server, since I cannot set hostname-admin without setting hostname?

I am guessing that (according to Server Administration Guide) it is because the “master” realm is somehow uniquely magic, and thus, whatever frontend url I set for that realm, will gain that privilege, but it really would be neat if it said that in the url you referenced above, as well).

That said, my admin realm’s url still gets baked into my other realms as the ${authBaseUrl} for their existing services. I’m guessing this is at realm creation time and is not expected to auto-update when I change the hostname.

Is this an incorrect assumption?

Hello, you’re not wrong when you say :

But the difference between edge and, reencrypt or passthrough, behaviours is that with edge behaviour, the proxied route is plain http behind the proxy, that is why this case requires http-enabled option on Keycloak (which is false by default). But if you have a reencrypt behaviour, enabling http on keycloak is not needed (and never recommanded in the docs).
Just to be sure we have the same vocabulary, here is a description of the different behaviours.

Regarding your question:

  1. I don’t know the magic behind the " Fully dynamic URLs" mode. Documentation only says it relies on the “forwarded” http header set by the RP.
  2. the 403 can happen for different reasons. It depends which request gets the 403. One recent case I remember was caused by the “step1.html” request trying to frame a domain that wasn’t allowed by the CSP configured in the realm (error was visible in the browser console, not in the network tab). Have you tryied to use the hostname debug mode I previously mentioned ?
  3. The behaviour if you go to a bareword url should be the display of the Kecloak welcome page or the admin console login page (depends on your keycloak version and setup). It shouldn’t be an infinite spinner.
  4. Yes it is possible for users to manage their 2FA tokens. It’s one of the features of the account page (here the url for a realm called “my-realm” with a local keycloak : http://localhost:8080/realms/my-realm/account/ ). Users must have the “manage-account” role (do not remember if it’s by default).

Following up on this!

The 403 for fully went away when I added a value to my “Web Origins” entry for the “account” client. This value seems to default to blank for all clients, and also doesn’t seem to automatically inherit a value from the “Frontend URL” value of the realm.

For the moment, for testing, I added “*”,

The online help for the “web origin” field says something like:

“Allowed CORS origins. To permit all origins of Valid Redirect URIs, add ‘+’. This does not include the ‘’ wildcard though. To permit all origins, explicitly add '’.”

Which isn’t super helpful. I would figure that this would have been mentioned in the hostname documentation, where if you allow multiple hostnames, this is one of the things you need to configure.

I also would have loved to find a log entry in keycloak that says something like “returning a 403 for (foo.js) because (url) is not listed as a valid web origin.”

I would have never found this, if not for this serverfault post