How to run Keycloak with Docker

In this tutorial, we’ll walk you through the step-by-step process of running Keycloak with Docker, enabling you to streamline authentication and authorization for your applications. We will explore the integration of Keycloak within Docker containers, optimizing the process with Docker Compose for efficient deployment and management of authentication and authorization services.

Available Keycloak distributions

The Keycloak Docker Image for is available in this repository:  quay.io/repository/keycloak/keycloak . You can use it in two different flavours:

  • Keycloak built on Quarkus: This is Keycloak which uses Quarkus as Runtime environment. The latest version of Keycloak with Quarkus ( June 2024 ) is 25.0.0
  • Keycloak legacy: This is the legacy distribution of Keycloak which uses WildFly as Runtime engine.

That being said, let’s see how to start Keycloak on Docker in both distributions.

Keycloak with Docker powered by Quarkus

Firstly, it is worth mentioning that you can use either the docker command or podman to achieve the same results. We will use docker in this section.

To pull the latest Docker Image of Keycloak you can run from the Command Line:

$ docker pull  quay.io/keycloak/keycloak:latest

Then, the following command will start a Docker Image of Keycloak in development mode:

docker run --name keycloak_dev -p 8080:8080 \
        -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin \
        quay.io/keycloak/keycloak:latest \
        start-dev

Next, verify the connectivity with the Admin Console which is available at http://localhost:8080

keycloak with docker tutorial

On the other hand, if you want to start Keycloak with Docker on a different server port, include the --http-port parameter:

docker run --name keycloak_dev -p 8180:8180 \
        -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin \
        quay.io/keycloak/keycloak:latest \
        start-dev --http-port=8180

Finally, to start Keycloak in production mode with PostgreSQL as database, use the following example command:

docker run --name keycloak_auto_build -p 8080:8080 \
        -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin \
        quay.io/keycloak/keycloak:latest \
        start \
        --auto-build \
        --db=postgres --features=token-exchange \
        --db-url=jdbc:postgresql://localhost:5432/keycloak --db-username=postgres --db-password=postgres \
        --https-key-store-file=server.keystore --https-key-store-password=secret

Update the Database and Keystore settings accordingly.

Running Keycloak with Docker compose

Docker compose is a valuable tool to orchestrate multiple containers and to provide complex configurations to a Container Image. For example, you can use it to import an existing Realm when using Keycloak Docker Image. To do that, you have to use the –import-realm option at startup. For example, with docker-compose the following file will import the Realm available in the local file /home/keycloak/realm.json:

services:
  auth:
    image: quay.io/keycloak/keycloak
    ports:
      - "8080:8080"
    environment:
      KEYCLOAK_ADMIN: admin 
      KEYCLOAK_ADMIN_PASSWORD: admin
    command: 
      - start-dev 
      - --import-realm
    volumes:
      - /home/keycloak/realm.json:/opt/keycloak/data/import/realm.json

To start Keycloak, simply run:

docker-compose up

Finally, verify that the Realm in realm.json has been imported at start up:

keycloak with docker example

Finally, notice how to use docker-compose exec to run commands on the Keycloak Docker Image. For example, here is how to login and add a new User:

# Login into keycloak with admin credentials
docker-compose exec auth /opt/keycloak/bin/kcadm.sh  config credentials --server http://localhost:8080 --realm master --user admin --password admin

# Add the user test
docker-compose exec auth /opt/keycloak/bin/kcadm.sh create users --realm=master -s username=test -s enabled=true -s [email protected] -s emailVerified=true --server http://localhost:8080 

# Sets the password for the user test
docker-compose exec auth /opt/keycloak/bin/kcadm.sh set-password --realm=master --username test --new-password password --server http://localhost:8080 

Running Keycloak with Docker compose and PostgreSQL

Our Docker compose example uses the built-in H2 Database. In Production, you would need to switch to a solid Database, for example to PostgreSQL. The following sample docker-compose.yml file shows how to kickstart Keycloak with Docker Compose and PostgreSQL by bridging them in the same network:

version: '3'

volumes:
  postgres_data:
    driver: local

services:
  postgres:
    image: postgres:latest
    volumes:
      - postgres_data:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: keycloak
      POSTGRES_USER: keycloak
      POSTGRES_PASSWORD: 123456
    healthcheck:
      test: "exit 0"
    ports:
      - 5432:5432
    networks:
      - keycloak_demo

  keycloak:
    image: quay.io/keycloak/keycloak
    command: start-dev
    environment:
      KC_DB: postgres
      KC_DB_URL_HOST: postgres
      KC_DB_URL_DATABASE: keycloak
      KC_DB_PASSWORD: 123456
      KC_DB_USERNAME: keycloak
      KC_DB_SCHEMA: public
      KEYCLOAK_ADMIN: admin
      KEYCLOAK_ADMIN_PASSWORD: password
    ports:
      - 8081:8080
    depends_on:
      postgres:
        condition: service_healthy
    networks:
      - keycloak_demo
networks:
  keycloak_demo:
    driver: bridge

Legacy Keycloak (WildFly) with Docker

To run the legacy distribution, which uses WildFly as runtime engine, you need to refer to the quay.io/keycloak/keycloak:legacy Image. Please notice the legacy tag that indicates to use the WildFly distribution. Here is how to start it, adding an Admin user:

docker run --rm --name keycloak -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin  -p 8080:8080  -it quay.io/keycloak/keycloak:legacy

To use a different port, such as port 8180, you can use the following command:

docker run --rm --name keycloak -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin  -p 8180:8180  -it quay.io/keycloak/keycloak:legacy  -b 0.0.0.0  -Djboss.http.port=8180

You will see that Keycloak starts in foreground and binds to port 8180 (by default port 8080 will be used but it can clash with other services, like WildFly, running on that port):

09:16:07,923 INFO  [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: Keycloak 15.0.2 (WildFly Core 15.0.1.Final) started in 22594ms - Started 692 of 977 services (686 services are lazy, passive or on-demand)
09:16:07,925 INFO  [org.jboss.as] (Controller Boot Thread) WFLYSRV0060: Http management interface listening on http://127.0.0.1:9990/management
09:16:07,925 INFO  [org.jboss.as] (Controller Boot Thread) WFLYSRV0051: Admin console listening on http://127.0.0.1:9990

Adding other Keycloak users

The legacy image of Keycloak ships with the script add-user-keycloak script available in the /opt/jboss/keycloak/bin folder. You can use it to add some extra users.

Firstly, collect the container id:

$ docker ps

CONTAINER ID        IMAGE                        
31a5c280ecdf        quay.io/keycloak/keycloak

Next, run the following command:

docker exec 31a5c280ecdf /opt/jboss/keycloak/bin/add-user-keycloak.sh -u frank -p foo

Then, you will see the following log:

Added 'frank' to '/opt/jboss/keycloak/standalone/configuration/keycloak-add-user.json', restart server to load user

Finally, restart the container with:

docker restart 31a5c280ecdf

Changing Keycloak Log Level

You can set Keycloak log level through the following environment variables:

  • KEYCLOAK_LOGLEVEL: Specifies the log level for Keycloak (default is INFO)
  • ROOT_LOGLEVEL: Specifies the log level for underlying container (default is INFO)

Example usage:

docker run --rm --name keycloak -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin -p 8180:8180 -it quay.io/keycloak/keycloak:legacy -b 0.0.0.0 -e KEYCLOAK_LOGLEVEL=TRACE

Managing Keycloak Realms running on Docker

You can approach Keycloak management on docker in at least two ways. One option is using the Web Console as we have seen in the previous section. Another option is to use the Keycloak CLI which you can trigger with a docker exec command.

Let’s see it in action. Firstly, we need to login to Keycloak server:

docker exec 31a5c280ecdf /opt/jboss/keycloak/bin/kcadm.sh config credentials --server http://localhost:8180/auth --realm master --user admin --password admin

We have now logged with the admin user. Let’s use this session to add another realm:

docker exec 31a5c280ecdf /opt/jboss/keycloak/bin/kcadm.sh create realms -s realm=wildfly-realm -s enabled=true -o

If you want a quickstart example of Keycloak CLI you can check this tutorial: Keycloak quickstart example using CLI

Importing a Keycloak legacy Realm at start up

Just in case you want to boot Keycloak and have your Realm imported, you can add the KEYCLOAK_IMPORT Environment variable and the Volume argument (-v) to specify the path where the JSON Realm file will be picked up:

docker run --rm \ 
--name keycloak \ 
-e KEYCLOAK_USER=admin \ 
-e KEYCLOAK_PASSWORD=admin \ 
-e KEYCLOAK_IMPORT=/tmp/realm.json -v /tmp/realm.json:/tmp/realm.json \ 
-p 8180:8180 \ 
-it quay.io/keycloak/keycloak:legacy \ 
-b 0.0.0.0 \ 
-Djboss.http.port=8180 \ 
-Dkeycloak.profile.feature.upload_scripts=enabled

Exporting a Keycloak legacy Realm

If you want to export a realm that you have created you’ll need to ensure the container running Keycloak has a volume mapped. For example you can start Keycloak setting the volume (‘v’) option to the /tmp folder:

docker run -d -p 8180:8080 -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin -v $(pwd):/tmp --name keycloak quay.io/keycloak/keycloak:legacy

Then, you can then get the export from this instance by running:

docker exec -it keycloak keycloak/bin/standalone.sh \ 
-Djboss.socket.binding.port-offset=100 -Dkeycloak.migration.action=export \ 
-Dkeycloak.migration.provider=singleFile \ 
-Dkeycloak.migration.realmName=my_realm \ 
-Dkeycloak.migration.usersExportStrategy=REALM_FILE \ 
-Dkeycloak.migration.file=/tmp/my_realm.json

(notice we use -Djboss.socket.binding.port-offset=100 so that the export runs on a different port than Keycloak itself).

Configuring a Database for Keycloak Image

Keycloak image supports multiple database as backend. You can specify the DB vendor directly with the DB_VENDOR environment variable. Supported values are:

  • h2 for the embedded H2 database,
  • postgres for the Postgres database,
  • mysql for the MySql database.
  • mariadb for the MariaDB database.
  • oracle for the Oracle database.
  • mssql for the Microsoft SQL Server database.

Environment variable names can be used to configure any of the above Database type:

  • DB_ADDR: This is the hostname of the database (optional).
  • DB_PORT: This is the port of the database (optional, default is DB vendor default port)
  • DB_DATABASE: Specify name of the database to use (optional, default is keycloak).
  • DB_SCHEMA: Specify name of the schema to use for DB that support schemas.
  • DB_USER: This is the user to authenticate against the database (optional, default is “).
  • DB_USER_FILE: This is the user to authenticate to the database via file input (alternative to DB_USER).
  • DB_PASSWORD: Specify user’s password to use to authenticate to the database (optional, default is “).
  • DB_PASSWORD_FILE: Specify user’s password to use to authenticate to the database via file input (alternative to DB_PASSWORD).

PostgreSQL example

Firstly, start a PostgreSQL instance:

docker run -d --name postgres --net keycloak-network -e POSTGRES_DB=keycloak -e POSTGRES_USER=keycloak -e POSTGRES_PASSWORD=password postgres

Next, launch the Keycloak server:

docker run --name keycloak --net keycloak-network quay.io/keycloak/keycloak  -e DB_USER=keycloak -e DB_PASSWORD=password

How to use docker-compose to start Keycloak

Finally, when using Keycloak with an external Database, it is common to use the docker-compose tool to configure all services in a single file. For example, this is a Docker compose example to bind Keycloak with PostgreSQL database:

version: '3'

volumes:
  postgres_data:
      driver: local

services:
  postgres:
      image: postgres
      volumes:
        - postgres_data:/var/lib/postgresql/data
      environment:
        POSTGRES_DB: keycloak
        POSTGRES_USER: keycloak
        POSTGRES_PASSWORD: password
  keycloak:
      image: quay.io/keycloak/keycloak:legacy
      environment:
        DB_VENDOR: POSTGRES
        DB_ADDR: postgres
        DB_DATABASE: keycloak
        DB_USER: keycloak
        DB_SCHEMA: public
        DB_PASSWORD: password
        KEYCLOAK_USER: admin
        KEYCLOAK_PASSWORD: Pa55w0rd
        # Uncomment the line below if you want to specify JDBC parameters. The parameter below is just an example, and it shouldn't be used in production without knowledge. It is highly recommended that you read the PostgreSQL JDBC driver documentation in order to use it.
        #JDBC_PARAMS: "ssl=true"
      ports:
        - 8080:8080
      depends_on:
        - postgres

To run it, execute:

 docker-compose up

Conclusion

This tutorial was a step-by-step guide covering how to run Keycloak as Docker Image showing how to use the Docker Compose tool to simplify and orchestrate the Identity manafer settings.

More example of Keycloak and Docker compose are available here: https://github.com/keycloak/keycloak-containers/tree/main/docker-compose-examples