Configuring Keycloak in 2022

May 23, 2022

Guide

1. Set up docker-compose.yml

version: "3"

volumes:
  postgres_data:
    driver: local

services:
  postgres:
    image: postgres:latest
    networks:
      - db
    volumes:
      - postgres_data:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: keycloak
      POSTGRES_USER: keycloak
      POSTGRES_PASSWORD: <postgres_password>
  keycloak:
    image: jboss/keycloak:latest
    deploy:
      restart_policy:
        condition: always
        delay: 5s
        window: 120s
    networks:
      - web
      - db
    environment:
      DB_VENDOR: POSTGRES
      DB_ADDR: postgres
      DB_DATABASE: keycloak
      DB_USER: keycloak
      DB_SCHEMA: public
      DB_PASSWORD: <postgres_password>
      KEYCLOAK_USER: admin
      KEYCLOAK_PASSWORD: <keycloak_password>
      KC_HOSTNAME: <idp-hostname>
      PROXY_ADDRESS_FORWARDING: true
      KEYCLOAK_FRONTEND_URL: https://<idp-hostname>/auth
    depends_on:
      - postgres
  web:
    image: nginx
    networks:
      - web
    depends_on:
      - keycloak
    volumes:
      - ./web/nginx.conf:/etc/nginx/nginx.conf
      - ./certbot/www:/var/www/certbot/:ro
      - ./certbot/conf/:/etc/nginx/ssl/:ro
    ports:
      - "80:80"
      - "443:443"
    environment:
      - NGINX_PORT=80
  certbot:
    image: certbot/certbot:latest
    volumes:
      - ./certbot/www/:/var/www/certbot/:rw
      - ./certbot/conf/:/etc/letsencrypt/:rw

networks:
  web: {}
  db: {}

Replace <idp-hostname>, <keycloak-password> and <postgres_password>. Preferably store them securely.

2. Run initial nginx server

This step is needed in order to generate Let's encrypt certificate with certbot before running actual Keycloak server.

Place this file in web/nginx.conf (relative to your docker-compose.yml file).

worker_processes  5;  ## Default: 1
worker_rlimit_nofile 8192;

events {
  worker_connections  4096;  ## Default: 1024
}

http {
  index    index.html index.htm index.php;
  default_type application/octet-stream;
  log_format   main '$remote_addr - $remote_user [$time_local]  $status '
    '"$request" $body_bytes_sent "$http_referer" '
    '"$http_user_agent" "$http_x_forwarded_for"';
  sendfile     on;
  tcp_nopush   on;
  server_names_hash_bucket_size 128; # this seems to be required for some vhosts

  server { # Required for certbot
    server_name idp;
    listen       80;

    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

  }
}

3. Run certbot

docker-compose up -d web
docker-compose run --rm  certbot certonly --webroot --webroot-path /var/www/certbot/ -d <idp-hostname>

4. Configure Nginx

Now add Keycloak behind Nginx. Add this to your web/nginx.conf file. Again, replace <idp-hostname> with your own.

...

server {
    listen 443 default_server ssl http2;
    listen [::]:443 ssl http2;

    server_name <idp-hostname>;

    ssl_certificate /etc/nginx/ssl/live/<idp-hostname>/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/live/<idp-hostname>/privkey.pem;
    location /auth/admin/ {
      allow 127.0.0.1; # Only allow localhost to access admin, or change this to your IP-address
      deny all;
      proxy_pass      http://keycloak:8080/auth/admin/;
      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
    }
    location /auth/js/ {
      proxy_pass      http://keycloak:8080/auth/js/;
      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
    }
    location /auth/realms/ {
      proxy_pass      http://keycloak:8080/auth/realms/;
      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_buffer_size          128k;
      proxy_buffers              4 256k;
      proxy_busy_buffers_size    256k;
    }
    location /auth/resources/ {
      proxy_pass      http://keycloak:8080/auth/resources/;
      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
    }
    location /auth/robots.txt {
      proxy_pass      http://keycloak:8080/auth/robots.txt;
      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
    }
}

5. Start everything

docker-compose restart web
docker-compose up -d postgres keycloak

Now you should be able to access Keycloak at https://<idp-hostname>/auth