Keycloak with Traefik boiler plate/ Introduction

I would like to run keycloak with traefik as a reverse proxy on my server.

Is there a kind of boilerplate for this project. Many instructions are very old.

Do I need traefik forward auth or is there another way? The goal is that a SPA logs in to keycloak via redirect and OIDC. The services in the backend validate the access token and need access to the public key. Everything works locally so far.

Only when I tried to start the whole thing via docker-compose with a reverse proxy did I fail.

Answer

I have now managed it.
Traefik runs with Keycloak, the TSL encryption is done via traefik and not via keycoak, therefore keycloak must only be accessible via port 8080, it does not require a keypair for keycloak.

I have added another host auth.stack_host in /etc/hosts (under Windows System32/drivers/hosts), which is now reachable under https:auth.stack_host and leads to keycloak.

Here is a boilerplate YML file for keycloak, traefik and a vue SPA. The vue application is listening on https://stack_host:443
Set stack_host to the name of your computer or add another host in the file from above.

version: "3"

services:
  traefik:
    image: traefik:v2.9
    command:
      - --api.insecure=true
      - --providers.file.directory=/configuration/
      - --providers.file.watch=true
      - --accesslog
      - --providers.docker.exposedbydefault=false
      - --providers.docker
      - --entryPoints.websecure.address=:443
      - --entrypoints.web.address=:80
    ports:
      - "172.17.108.255:8080:8080"
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /traefik:/configuration/
    networks:
      - external-network
    mem_limit: 200m
    mem_reservation: 100m

  frontend:
    build: gui
    container_name: ${STACK_NAME}-frontend
    restart: always
    networks:
      - external-network
    command: --brotli --port 8083
    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=${STACK_NAME}-external"
      
      - "traefik.http.routers.frontend.rule=Host(`${STACK_HOST}`)"
      - "traefik.http.routers.frontend.entrypoints=websecure"
      - "traefik.http.routers.frontend.tls=true"
      - "traefik.http.routers.frontend.middlewares=cors_header"
      - "traefik.http.middlewares.cors_header.headers.accesscontrolallowmethods=GET,OPTIONS,PUT,POST,DELETE,PATCH"
      - "traefik.http.middlewares.cors_header.headers.accesscontrolallowheaders=*"
      - "traefik.http.middlewares.cors_header.headers.accesscontrolalloworiginlist=https://${STACK_HOST}"
      - "traefik.http.middlewares.cors_header.headers.accesscontrolmaxage=100"
      - "traefik.http.middlewares.cors_header.headers.addvaryheader=true"
      - "traefik.http.services.frontend.loadbalancer.server.port=8083"
      - "traefik.http.services.frontend.loadbalancer.server.scheme=http"


  keycloak:
    container_name: keycloak
    build: KeycloakContainer
    restart: always
    command: start
    environment:
      KC_PROXY_ADDRESS_FORWARDING: "true"
      KC_HOSTNAME_STRICT: "false"
      KC_HOSTNAME_STRICT_HTTPS: "false"
      KC_HOSTNAME: auth.${STACK_HOST}
      KC_HTTP_ENABLED: "true"
      KC_PROXY_HEADERS: xforwarded
      KEYCLOAK_ADMIN: admin
      KEYCLOAK_ADMIN_PASSWORD: password
      KC_HEALTH_ENABLED: "true"
    labels:
      - "traefik.docker.network=${STACK_NAME}-external"
      - "traefik.enable=true"
      - "traefik.http.routers.keycloak.rule=Host(`auth.${STACK_HOST}`)"
      - "traefik.http.routers.keycloak.tls=true"
      - "traefik.http.services.keycloak.loadbalancer.server.port=8080"
    networks:
      - external-network
      - internal-network
    healthcheck:
      test:
        [
          "CMD-SHELL",
          "exec 3<>/dev/tcp/localhost/8080 && echo -e 'GET /health/ready HTTP/1.1\\r\\nHost: localhost\\r\\nConnection: close\\r\\n\\r\\n' >&3 && cat <&3 | grep -q '200 OK'"
        ]
      interval: 30s
      timeout: 5s
      retries: 20

networks:
  internal-network:
    name: ${STACK_NAME}-internal
    internal: true
  external-network:
    name: ${STACK_NAME}-external
    driver: bridge

Keycloak Dockerfile/ or just use the image if you dont want to import smth.

FROM quay.io/keycloak/keycloak:24.0.1 as builder
WORKDIR /opt/keycloak

RUN /opt/keycloak/bin/kc.sh build

FROM quay.io/keycloak/keycloak:24.0.1

COPY --from=builder /opt/keycloak/ /opt/keycloak/

// load custom theme
COPY ./marvins-theme/ /opt/keycloak/themes/marvins-theme

// import realm
COPY ./realm-config/realm.json /opt/keycloak_import/

RUN /opt/keycloak/bin/kc.sh import --file /opt/keycloak_import/realm.json
ENTRYPOINT ["/opt/keycloak/bin/kc.sh"]

Couple of questions for you…

I don’t see a route to the vuew spa in your config. Where is that done? Maybe a file provider?

Is anything being protected by keycloak forward auth in this config?