Keycloak - Domain mode - Management console behing Nginx - Error WFLYHC0001

Hi everyone,

I’m trying to achieve a simple objective: to build a Keycloak cluster (domain mode for the moment) with 2 nodes.

Details of what I’m doing:

  • node 1:

    • domain controller (port 9990)
    • host controller
    • keycloak server (port 8180)
    • nginx for the SSL offloading (self-signed certificate for my test)
  • node 2:

    • domain controller (port 9990)
    • host controller
    • keycloak server (port 8180)

On Nginx side I created a first virtual host dedicated to Keycloak (so to answer on the /auth requests):

map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

upstream keycloak-sg-01 {
    server 127.0.0.1:8180      weight=10    max_fails=3    fail_timeout=15s;
    server 192.168.1.2:8180    weight=5     max_fails=3    fail_timeout=15s    backup;
}

## HTTPS ##
server {
    server_name keycloak-test.local.net;

    access_log /var/log/nginx/access-keycloak-server.log;
    error_log /var/log/nginx/error-keycloak-server.log;

    listen 443 ssl;
    include snippets/self-signed.conf;

    location / {
        rewrite ^ /auth;
    }

    location /auth {
        add_header Front-End-Https off;
        add_header Cache-Control no-cache;

        proxy_redirect off;

        proxy_set_header    Authorization      $http_authorization;
        proxy_set_header    Host               $host;
        proxy_set_header    Origin             http://$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-Host   $host;
        proxy_set_header    X-Forwarded-Server $host;
        proxy_set_header    X-Forwarded-Port   $server_port;
        proxy_set_header    X-Forwarded-Proto  $scheme;

        proxy_pass http://keycloak-sg-01/auth;
    }
}
## /HTTPS ##

This part works:

  • I can reach Keycloak
  • the SSL offloading is managed by Nginx (not perfect because the communication Nginx <-> 192.168.1.2:8180 is not crypted)

Now I tried to hide the console behind Nginx…

I created a second virtual host dedicated to the console:

map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

## HTTPS ##
server {
    server_name keycloak-console-test.local.net;

    access_log /var/log/nginx/access-keycloak-domain.log;
    error_log /var/log/nginx/error-keycloak-domain.log debug;

    listen 443 ssl;
    include snippets/self-signed.conf;

    location / {
        add_header Cache-Control 'no-store, no-cache';

        proxy_http_version 1.1;
        proxy_redirect off;

        proxy_set_header    Authorization      $http_authorization;
        proxy_set_header    Host               $host;
        proxy_set_header    Origin             http://$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-Host   $host;
        proxy_set_header    X-Forwarded-Server $host;
        proxy_set_header    X-Forwarded-Port   $server_port;
        proxy_set_header    X-Forwarded-Proto  $scheme;

        proxy_pass http://127.0.0.1:9990;
    }

    location /console {
        add_header Cache-Control no-cache;

        proxy_http_version 1.1;
        proxy_redirect off;

        proxy_set_header    Authorization      $http_authorization;
        proxy_set_header    Host               $host;
        proxy_set_header    Origin             http://$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-Host   $host;
        proxy_set_header    X-Forwarded-Server $host;
        proxy_set_header    X-Forwarded-Port   $server_port;
        proxy_set_header    X-Forwarded-Proto  $scheme;

        proxy_pass http://127.0.0.1:9990/console;
    }

    location /management {
        add_header Cache-Control no-cache;

        proxy_http_version 1.1;
        proxy_redirect off;

        proxy_set_header    Authorization      $http_authorization;
        proxy_set_header    Host               $host;
        proxy_set_header    Origin             http://$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-Host   $host;
        proxy_set_header    X-Forwarded-Server $host;
        proxy_set_header    X-Forwarded-Port   $server_port;
        proxy_set_header    X-Forwarded-Proto  $scheme;

        proxy_pass http://127.0.0.1:9990/management;
    }
}
## /HTTPS ##

I can reach the HAL Management console with my browser on https://keycloak-console-test.local.net/console/ (I have an entry in my /etc/hosts file).

If I configure my host.xml with:

    <domain-controller>
        <remote username="myusername" authentication-context="hcAuthContext">
            <discovery-options>
                <static-discovery name="primary" protocol="${jboss.domain.master.protocol:remote+http}" host="${jboss.domain.master.address}" port="${jboss.domain.master.port:9990}" />
            </discovery-options>
        </remote>
    </domain-controller>

It works when I start with this command:

/opt/keycloak/bin/domain.sh -c host.xml -Djboss.bind.address=0.0.0.0 -Djboss.bind.address.management=0.0.0.0 -Djboss.bind.address.private=127.0.0.1 -Djboss.tx.node.id=tx-srv-local-02 -Djboss.domain.master.address=keycloak-test.local.net -Djboss.domain.master.port=9990 -Djboss.management.http.port=9990

→ it works when I reach directly the console bypassing the Nginx server (so on the port 9990)

Now same configuration but I try to reach through Nginx:

/opt/keycloak/bin/domain.sh -c host.xml -Djboss.bind.address=0.0.0.0 -Djboss.bind.address.management=0.0.0.0 -Djboss.bind.address.private=127.0.0.1 -Djboss.tx.node.id=tx-srv-local-02 -Djboss.domain.master.address=keycloak-test.local.net -Djboss.domain.master.port=443 -Djboss.management.http.port=9990

If failed with this error:

[Host Controller] 15:05:19,012 WARN  [org.jboss.as.host.controller] (Controller Boot Thread) WFLYHC0001: Could not connect to remote domain controller remote+http://keycloak-test.local.net:443: java.net.ConnectException: WFLYPRT0053: Could not connect to remote+http://keycloak-test.local.net:443. The connection failed
[Host Controller] 	at org.jboss.as.protocol.ProtocolConnectionUtils.checkFuture(ProtocolConnectionUtils.java:142)
[Host Controller] 	at org.jboss.as.protocol.ProtocolConnectionUtils.connectSync(ProtocolConnectionUtils.java:122)
[Host Controller] 	at org.jboss.as.host.controller.RemoteDomainConnection.lambda$openConnection$0(RemoteDomainConnection.java:211)
[Host Controller] 	at org.wildfly.common.context.Contextual.runExceptionAction(Contextual.java:108)
[Host Controller] 	at org.wildfly.security.auth.client.AuthenticationContext.run(AuthenticationContext.java:273)
[Host Controller] 	at org.jboss.as.host.controller.RemoteDomainConnection.openConnection(RemoteDomainConnection.java:211)
[Host Controller] 	at org.jboss.as.host.controller.RemoteDomainConnection$InitialConnectTask.connect(RemoteDomainConnection.java:582)
[Host Controller] 	at org.jboss.as.protocol.ProtocolConnectionManager.connect(ProtocolConnectionManager.java:70)
[Host Controller] 	at org.jboss.as.host.controller.RemoteDomainConnection.connect(RemoteDomainConnection.java:141)
[Host Controller] 	at org.jboss.as.host.controller.RemoteDomainConnectionService.register(RemoteDomainConnectionService.java:282)
[Host Controller] 	at org.jboss.as.host.controller.DomainModelControllerService.connectToDomainMaster(DomainModelControllerService.java:1008)
[Host Controller] 	at org.jboss.as.host.controller.DomainModelControllerService.boot(DomainModelControllerService.java:720)
[Host Controller] 	at org.jboss.as.controller.AbstractControllerService$1.run(AbstractControllerService.java:424)
[Host Controller] 	at java.lang.Thread.run(Thread.java:748)
[Host Controller] Caused by: org.xnio.http.UpgradeFailedException: Invalid response code 400
[Host Controller] 	at org.xnio.http.HttpUpgrade$HttpUpgradeState$UpgradeResultListener.handleEvent(HttpUpgrade.java:471)
[Host Controller] 	at org.xnio.http.HttpUpgrade$HttpUpgradeState.flushUpgradeChannel(HttpUpgrade.java:369)
[Host Controller] 	at org.xnio.http.HttpUpgrade$HttpUpgradeState.access$900(HttpUpgrade.java:165)
[Host Controller] 	at org.xnio.http.HttpUpgrade$HttpUpgradeState$ConnectionOpenListener.handleEvent(HttpUpgrade.java:340)
[Host Controller] 	at org.xnio.http.HttpUpgrade$HttpUpgradeState$ConnectionOpenListener.handleEvent(HttpUpgrade.java:320)
[Host Controller] 	at org.xnio.http.HttpUpgrade$HttpUpgradeState.upgradeExistingConnection(HttpUpgrade.java:315)
[Host Controller] 	at org.xnio.http.HttpUpgrade.performUpgrade(HttpUpgrade.java:144)
[Host Controller] 	at org.jboss.remoting3.remote.HttpUpgradeConnectionProvider$UpgradeListener.handleEvent(HttpUpgradeConnectionProvider.java:174)
[Host Controller] 	at org.jboss.remoting3.remote.HttpUpgradeConnectionProvider$UpgradeListener.handleEvent(HttpUpgradeConnectionProvider.java:153)
[Host Controller] 	at org.xnio.ChannelListeners.invokeChannelListener(ChannelListeners.java:92)
[Host Controller] 	at org.xnio.nio.WorkerThread$ConnectHandle.handleReady(WorkerThread.java:333)
[Host Controller] 	at org.xnio.nio.WorkerThread.run(WorkerThread.java:591)
[Host Controller] 	at ...asynchronous invocation...(Unknown Source)
[Host Controller] 	at org.jboss.remoting3.EndpointImpl.connect(EndpointImpl.java:599)
[Host Controller] 	at org.jboss.remoting3.EndpointImpl.connect(EndpointImpl.java:561)
[Host Controller] 	at org.jboss.remoting3.EndpointImpl.connect(EndpointImpl.java:549)
[Host Controller] 	at org.jboss.as.protocol.ProtocolConnectionUtils.connect(ProtocolConnectionUtils.java:224)
[Host Controller] 	at org.jboss.as.protocol.ProtocolConnectionUtils.connectSync(ProtocolConnectionUtils.java:118)
[Host Controller] 	... 12 more

So I tried to change my host.xml like this:

<static-discovery name="primary" protocol="${jboss.domain.master.protocol:remote+https}" host="${jboss.domain.master.address}" port="${jboss.domain.master.port:9990}" />

→ remote-https instead of remote-http

Now it failed with this message:

[Host Controller] 15:07:56,807 WARN  [org.jboss.as.host.controller] (Controller Boot Thread) WFLYHC0001: Could not connect to remote domain controller remote+https://keycloak-test.local.net:443: java.net.ConnectException: WFLYPRT0053: Could not connect to remote+https://keycloak-test.local.net:443. The connection failed
[Host Controller] 	at org.jboss.as.protocol.ProtocolConnectionUtils.checkFuture(ProtocolConnectionUtils.java:142)
[Host Controller] 	at org.jboss.as.protocol.ProtocolConnectionUtils.connectSync(ProtocolConnectionUtils.java:122)
[Host Controller] 	at org.jboss.as.host.controller.RemoteDomainConnection.lambda$openConnection$0(RemoteDomainConnection.java:211)
[Host Controller] 	at org.wildfly.common.context.Contextual.runExceptionAction(Contextual.java:108)
[Host Controller] 	at org.wildfly.security.auth.client.AuthenticationContext.run(AuthenticationContext.java:273)
[Host Controller] 	at org.jboss.as.host.controller.RemoteDomainConnection.openConnection(RemoteDomainConnection.java:211)
[Host Controller] 	at org.jboss.as.host.controller.RemoteDomainConnection$InitialConnectTask.connect(RemoteDomainConnection.java:582)
[Host Controller] 	at org.jboss.as.protocol.ProtocolConnectionManager.connect(ProtocolConnectionManager.java:70)
[Host Controller] 	at org.jboss.as.host.controller.RemoteDomainConnection.connect(RemoteDomainConnection.java:141)
[Host Controller] 	at org.jboss.as.host.controller.RemoteDomainConnectionService.register(RemoteDomainConnectionService.java:282)
[Host Controller] 	at org.jboss.as.host.controller.DomainModelControllerService.connectToDomainMaster(DomainModelControllerService.java:1008)
[Host Controller] 	at org.jboss.as.host.controller.DomainModelControllerService.boot(DomainModelControllerService.java:720)
[Host Controller] 	at org.jboss.as.controller.AbstractControllerService$1.run(AbstractControllerService.java:424)
[Host Controller] 	at java.lang.Thread.run(Thread.java:748)
[Host Controller] Caused by: org.xnio.http.RedirectException: XNIO000816: Redirect encountered establishing connection
[Host Controller] 	at org.xnio.http.HttpUpgrade$HttpUpgradeState.handleRedirect(HttpUpgrade.java:513)
[Host Controller] 	at org.xnio.http.HttpUpgrade$HttpUpgradeState.access$1300(HttpUpgrade.java:165)
[Host Controller] 	at org.xnio.http.HttpUpgrade$HttpUpgradeState$UpgradeResultListener.handleEvent(HttpUpgrade.java:468)
[Host Controller] 	at org.xnio.http.HttpUpgrade$HttpUpgradeState$UpgradeResultListener.handleEvent(HttpUpgrade.java:400)
[Host Controller] 	at org.xnio.ChannelListeners.invokeChannelListener(ChannelListeners.java:92)
[Host Controller] 	at org.xnio.conduits.ReadReadyHandler$ChannelListenerHandler.readReady(ReadReadyHandler.java:66)
[Host Controller] 	at org.xnio.nio.NioSocketConduit.handleReady(NioSocketConduit.java:89)
[Host Controller] 	at org.xnio.nio.WorkerThread.run(WorkerThread.java:591)
[Host Controller] 	at ...asynchronous invocation...(Unknown Source)
[Host Controller] 	at org.jboss.remoting3.EndpointImpl.connect(EndpointImpl.java:599)
[Host Controller] 	at org.jboss.remoting3.EndpointImpl.connect(EndpointImpl.java:561)
[Host Controller] 	at org.jboss.remoting3.EndpointImpl.connect(EndpointImpl.java:549)
[Host Controller] 	at org.jboss.as.protocol.ProtocolConnectionUtils.connect(ProtocolConnectionUtils.java:224)
[Host Controller] 	at org.jboss.as.protocol.ProtocolConnectionUtils.connectSync(ProtocolConnectionUtils.java:118)
[Host Controller] 	... 12 more

I tried a lot of things but I can’t find the solution…
I tested several Origin header like:

 proxy_set_header    Origin             $host;
 proxy_set_header    Origin             http://$host;
 proxy_set_header    Origin             http://$host:9990;
 proxy_set_header    Origin             https://$host;
 proxy_set_header    Origin             https://$host:9990;

→ same error

I tried to add http-upgrade-enabled=“true” on node 1 side : same error

Is anyone has an idea please :slight_smile: ?