Table of Contents
Keycloak is quite a nice tool to handle user authentication and authorization. Both Keycloak and HAProxy are free so you can easily setup an authenication & authorization server very quickly and free (hosting is not free though :)).
With the help of Docker, it will take a few minutes (less than 10) for you to successfully setup a single sign on server(SSO).
Setting up Keycloak
Keycloak has built in database to store users. However, it also allows you specify an external database if you want to do so. I prefer the second option since it seems easier to backup. Let’s first setup a mariadb server. Here is the docker-compose part of MariaDB:
keycloak_db:
container_name: keycloak_db
image: mariadb:10.3.26
restart: always
volumes:
- keycloak_db_volume:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: YOUR_ROOT_PASSWORDNotice that I’m using MYSQL_ROOT_PASSWORD here for demo purposes. You should create a non root user and also user Docker secrets to manage the password instead.
You can also notice that this service (keycloak_db) uses an external volume keycloak_db_volume. We will create that at the end of the docker-compose.yml file.
Now, let’s write the YAML content for Keycloak itself:
keycloak:
container_name: keycloak
image: quay.io/keycloak/keycloak:12.0.4
restart: always
env_file: ./kc.envAs you can see, instead using environment block, we now use an *.env file. Here is the content:
DB_VENDOR=mariadb DB_ADDR=keycloak_db:3306 DB_DATABASE=keycloak_1 DB_USER=root DB_PASSWORD=MYSQL_PASSWORD KEYCLOAK_USER=kc_user KEYCLOAK_PASSWORDD=keycloak_password PROXY_ADDRESS_FORWARDING=true
That’s all we need to do with Keycloak. Let’s create and configure HAproxy.
Setting up HAproxy
If you want to have SSL enabled, make sure to install certbot to generate a free Let’s Encrypt certificate. Certbot is awesome since you can set up it to automatically renew the certificate for you.
There is a awesome tutorial here to help you generate standalone certificate for your domain:
After generating the certificate, combine the fullchain.pem and privkey.pem to generate a single .pem file. HAproxy will use this single file.
DOMAIN='your_domain_name' sudo -E bash -c 'cat /etc/letsencrypt/live/$DOMAIN/fullchain.pem /etc/letsencrypt/live/$DOMAIN/privkey.pem > /etc/haproxy/certs/$DOMAIN.pem'
Now, let’s create a service for HAproxy in our docker-compose.yml file:
haproxy:
container_name: haproxy
image: haproxy:2.4.0
restart: always
ports:
- 80:80
- 443:443
volumes:
- /etc/haproxy/certs/your_domain_name.pem:/usr/local/etc/haproxy/certs/your_domain_name.pem
- ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfgAs you can see, we’ve mounted the SSL certificate to /usr/local/etc/haproxy/certs/. We also create and mount a haproxy.cfg file. Let’s see its content:
global
stats timeout 30s
defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5000
timeout client 50000
timeout server 50000
option forwardfor
option http-server-close
frontend sso
bind :80
bind :443 ssl crt /usr/local/etc/haproxy/certs/your_domain_name.pem
http-request redirect scheme https unless { ssl_fc }
default_backend keycloak_backend
http-request set-header X-Forwarded-Proto https if { ssl_fc }
http-request set-header X-Forwarded-Proto http if !{ ssl_fc }
backend keycloak_backend
http-request redirect scheme https unless { ssl_fc }
server www-1 keycloak:8080 checkBy default, Keycloak starts on port 8080. This is HAproxy settings, we forward traffic on port 80, 443 to Keycloak backend.
Here is the whole docker-compose file:
version: '3'
services:
haproxy:
container_name: haproxy
image: haproxy:2.4.0
restart: always
ports:
- 80:80
- 443:443
volumes:
- /etc/haproxy/certs/sso.openexl.com.pem:/usr/local/etc/haproxy/certs/sso.openexl.com.pem
- ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg
keycloak:
container_name: keycloak
image: quay.io/keycloak/keycloak:12.0.4
restart: always
env_file: ./kc.env
keycloak_db:
container_name: keycloak_db
image: mariadb:10.3.26
restart: always
volumes:
- keycloak_db_volume:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: mysql_root_password
volumes:
keycloak_db_volume:If you have the certificate correctly setup, simply run docker-compose up -d, you can access your site after a few minutes.
Some caveats:
I’ve tried this setup on a DigitalOcean droplet with just 1GB of RAM and single CPU ($5/month) and Keycloak crashed every single time. The reason is at start up, Keycloak uses a lot of resources. Afte upgrading to the next tier, I could start without any problem.

I build softwares that solve problems. I also love writing/documenting things I learn/want to learn.
Have you done this with the never versions of Keycloak, say version 18?
I haven’t. Did you do it and found some errors?
This is in “dev” mode, im trying to apply this to a prod environment, adding tls certs to keycloak and passing through client certs in haproxy folowing like is proposed in keycloak docs. Any experience in this?
You can try Caddy and you will have SSL done automatically for you
Great stuff, thank you for this