How to use Docker and Nginx to get started with self-hosting single sign-on with Keycloak.
Joey Miller • Last updated May 14, 2023
This guide is the first part in a multi-part series of guides:
There are plenty of great services to self-host, including Nextcloud, and Tandoor Recipes. If you've ever tried self-hosting more than a few services you'll understand the frustration of remembering many different passwords and continuously having to log in. After doing some research, I realized my homelab needed "single sign-on" (SSO). SSO is an authentication method (typically viewed as an enterprise feature) that allows secure authentication with many services using "just one set of credentials". Using SSO I would be able to achieve my dream of needing only a single-login event to access all of my services.
There are many tools that we can use for SSO, such as Authelia, Authentik, or Keycloak.
Although some of the aforementioned SSO tools may be easier to set up, I decided to go with Keycloak. Keycloak is an enterprise-level tool that is supported by Redhat. Using Keycloak will give us a lot of flexibility, and ticks the boxes for acceptable memory usage, theme-ability, and multi-factor authentication support.
This guide assumes you are using Docker + Nginx Proxy Manager (NPM) as the reverse proxy. This guide will be easy to adapt to bare Nginx.
Within Nginx Proxy Manager (NPM), I will be assuming you have set up SSL and are enforcing HTTPS for each proxy host. Otherwise, additional setup may be required - especially when dealing with OAuth2 Proxy in part 2 of this guide series.
To get started with Keycloak, add the following to the
services: section of your
npm: image: 'jc21/nginx-proxy-manager:latest' ports: - '80:80' - '81:81' - '443:443' volumes: - ./data/nginx_proxy_manager/data:/data - ./data/nginx_proxy_manager/letsencrypt:/etc/letsencrypt restart: unless-stopped keycloak: # internal: keycloak on port 8080 image: quay.io/keycloak/keycloak:latest command: start environment: KC_HEALTH_ENABLED: 'true' KC_HOSTNAME_STRICT: 'false' KC_HOSTNAME_STRICT_HTTPS: 'false' KC_PROXY: 'edge' KEYCLOAK_ADMIN: 'admin' KEYCLOAK_ADMIN_PASSWORD: 'admin' volumes: - ./data/keycloak:/opt/keycloak/data healthcheck: test: ["CMD", "curl", "-k", "-f", "http://keycloak:8080/health"] interval: 10s timeout: 1s retries: 15 restart: unless-stopped
Note: The above example will have Keycloak running with the built-in H2 database. It is recommended in production to use an external database (i.e. MySQL, PostgreSQL, etc).
Then, let's configure Keycloak on a subdomain in the NPM web interface. We will host Keycloak at
https://auth.example.com/auth and the OAuth proxy (explained later in this guide) at
example.com with your domain name.
Info: The default NPM username is
[email protected], and the password is
changeme. Make sure to change these.
From the NPM dashboard, click
Add Proxy Host
Forward Hostname / IP, and
Lets hide the default dashboard, and redirect the root path to the administrative console. In the
Custom locations tab, add a location.
Forward Hostname / IP, and
return 301 /admin;
Custom Nginx Configurationfield to:
proxy_buffer_size 128k; proxy_buffers 4 256k; proxy_busy_buffers_size 256k;
We don't always want every user to be able to access every service. For example, you may want to give a friend access to your recipe application but not to the Pihole admin console.
If you have a compliant OIDC Client Application, setting
Client authentication and
ON will be enough to access the
Authorization tab for the client. Then you will be able to create a
Group-based policy from the
Unfortunately, this isn't always suitable - such as if the client uses SAML for authentication/authorization. In this case, another way to handle this in Keycloak (without needing any extensions) is to duplicate the default browser flow and add a condition that denies access if the user doesn't have the required role.
Note: This method requires a separate browser flow for each unique set of roles you would like to mandate for users of clients/services.
For more details see the answers by @Stuck and @heilerich on StackOverflow.
To increase the security of your authentication process, Keycloak allows enabling two-factor authentication (2FA) for users. This requires users to provide a valid one-time-pass (OTP) from an authenticator app on their smartphone.
Go to the
Keycloak Administration Console
Authentication > Required actions and for
Configure OTP toggle
Set as default action to
Go to the
Users page. By clicking on each existing user, add
Configure OTP to
Required user actions from the
User details > Details tab.
After these steps - on the next login users will be required to set up their authenticator for 2FA.
We've successfully set up a basic SSO implementation with Keycloak.
If all the services you are using are capable of authentication via OAuth, SAML, or Keycloak - the journey ends here for you. This implementation will be sufficient.
If you have other services that expect HTTP Header Auth or manage their own login flow (i.e. via LDAP) - continue reading. This guide continues in:
If you found this post helpful, please share it around: