Struggling to reverse proxy Keycloak with Traefik

Afternoon y’all,

I’m trying to setup Keycloak via Docker-Compose along side Traefik as my reverse proxy. The issue I’m running into with Keycloak is that i cannot access the dashboard behind the reverse-proxy, it constantly lands on “somethingWentWrong” and asks to refresh the page.

After doing some research i suspect there is some sort of headers issue however, when it comes to headers i know very little about them and when i read about them i typically see it as gibberish and can’t really make sense of them, so apologies if this has been asked about before or seem as ignorant.

Here is a snippet of my docker-compose.yml -

services:
  traefik-kop:
    image: "ghcr.io/jittering/traefik-kop:latest"
    container_name: traefik-kop
    hostname: traefik-kop
    restart: unless-stopped
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - "REDIS_ADDR=192.168.1.14:6379"
      - "BIND_IP=192.168.1.199"
    networks:
      main:
        ipv4_address: 172.18.0.36

  keycloak:
    container_name: keycloak
    hostname: keycloak
    image: quay.io/keycloak/keycloak:26.3.0
    environment:
      KC_PROXY_ADDRESS_FORWARDING: "true"
      KC_HOSTNAME_STRICT: "false"
      KC_HOSTNAME: kc.example.com
      # KC_HOSTNAME_PORT: 443
      KC_PROXY: edge
      KC_HTTP_ENABLED: "true"
      KC_DB: postgres
      KC_DB_URL: jdbc:postgresql://postgresql-kc:5432/$POSTGRES_DB?ssl=allow
      KC_DB_USERNAME: admin
      KC_DB_PASSWORD: password
      KEYCLOAK_ADMIN: admin
      KEYCLOAK_ADMIN_PASSWORD: password
    networks:
      main:
        ipv4_address: 172.18.0.39
    ports:
      - 6732:8080
      #- 8443:8443
    labels:
       - "traefik.enable=true"
       - "traefik.http.routers.keycloak.rule=Host(`kc.example.com`)"
       - "traefik.http.routers.keycloak.entrypoints=https"
       - "traefik.http.routers.keycloak.tls=true"
       - "traefik.http.services.keycloak.loadbalancer.server.port=6732"
       - "traefik.http.routers.keycloak.middlewares=fail2ban@file"
       - "traefik.http.routers.keycloak.middlewares=geoblock@file"
       - "traefik.http.routers.keycloak.tls.certresolver=default"
       - "kop.keycloak.bind.ip=192.168.1.199"
    command:
      - start
    depends_on:
        - postgresql-kc

  postgresql-kc:
    image: postgres
    container_name: postgresql-kc
    hostname: postgresql-kc
    networks:
      main:
        ipv4_address: 172.18.0.40
    restart: unless-stopped
    # set shared memory limit when using docker-compose
    shm_size: 1024mb
    volumes:
      - ./data/1tb-hdd/postgresql-kc:/dev/shm
    environment:
      POSTGRES_USER: admin
      POSTGRES_PASSWORD: password
    ports:
      - '28541:5432'

networks:
  main:
    external: true
    ipam:
     config:
       - subnet: 172.18.0.0/16
         gateway: 172.18.0.1

I host Traefik on a separate machine and the two machines communicate via an application called traefik-kop as you can see in the compose example above. Below you can see the compose file containing my traefik instance.

services:
  traefik:
    image: traefik:v3.2
    container_name: traefik
    hostname: traefik
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    networks:
      main:
        ipv4_address: 172.18.0.3
    ports:
      # Listen on port 80, default for HTTP, necessary to redirect to HTTPS
      - target: 80
        published: 55262
        mode: host
      # Listen on port 443, default for HTTPS
      - target: 443
        published: 57442
        mode: host
    environment:
      CF_DNS_API_TOKEN_FILE: /run/secrets/cf_api_token # note using _FILE for docker secrets
      # CF_DNS_API_TOKEN: ${CF_DNS_API_TOKEN} # if using .env
      TRAEFIK_DASHBOARD_CREDENTIALS: ${TRAEFIK_DASHBOARD_CREDENTIALS}
    secrets:
      - cf_api_token
    env_file: .env # use .env
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./config/traefik/traefik.yml:/traefik.yml:ro
      - ./config/traefik/acme.json:/acme.json
      - ./config/traefik/custom-yml:/custom
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.traefik.entrypoints=http"
      - "traefik.http.routers.traefik.rule=Host(`traefik.example.com`)"
      - "traefik.http.middlewares.traefik-ipallowlist.ipallowlist.sourcerange=127.0.0.1/32, 192.168.1.0/24, 208.118.140.130, 172.18.0.0/16"
      - "traefik.http.middlewares.traefik-auth.basicauth.users=${TRAEFIK_DASHBOARD_CREDENTIALS}"
      - "traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=https"
      - "traefik.http.middlewares.sslheader.headers.customrequestheaders.X-Forwarded-Proto=https"
      - "traefik.http.routers.traefik.middlewares=traefik-https-redirect"
      - "traefik.http.routers.traefik-secure.entrypoints=https"
      - "traefik.http.routers.traefik-secure.rule=Host(`traefik.example.com`)"
      - "traefik.http.routers.traefik-secure.middlewares=traefik-auth"
      - "traefik.http.routers.traefik-secure.tls=true"
      - "traefik.http.routers.traefik-secure.tls.certresolver=cloudflare"
      - "traefik.http.routers.traefik-secure.tls.domains[0].main=example.com"
      - "traefik.http.routers.traefik-secure.tls.domains[0].sans=*.example.com"
      - "traefik.http.routers.traefik-secure.service=api@internal"
      - "traefik.http.routers.traefik.middlewares=fail2ban@file"
      - "traefik.http.routers.traefik.middlewares=geoblock@file"
      - "traefik.http.routers.traefik-secure.middlewares=fail2ban@file"
      - "traefik.http.routers.traefik-secure.middlewares=geoblock@file"
      - "traefik.http.routers.traefik-https-redirect.middlewares=fail2ban@file"
      - "traefik.http.routers.traefik-https-redirect.middlewares=geoblock@file"

  redis:
    image: redis
    container_name: redis
    hostname: redis
    networks:
      main:
        ipv4_address: 172.18.0.4
    volumes:
      - ./config/redis:/data
    ports:
      - '6379:6379'
    restart: unless-stopped

networks:
  main:
    external: true
    ipam:
     config:
       - subnet: 172.18.0.0/16
         gateway: 172.18.0.1

I hope someone can help me out here as it would be very much appreciated.

Thank you!

Edit: The tail of my Keycloak log shows this:

WARNING: Hostname v1 options [proxy] are still in use, please review your configuration
WARNING: With HTTPS not enabled, `proxy-headers` unset, and `hostname-strict=false`, the server is running in an insecure context. Secure contexts are required for full functionality, including cross-origin cookies. Also if you are using a proxy, requests from the proxy to the server will fail CORS checks with 403s because the wrong origin will be determined. Make sure `proxy-headers` are configured properly.

Which furthers my theory that the headers are incorrect.

From the things you posted, it seems that you copied theses things from somewhere on the internet, but didn’t read the manual…
Here is everything you’ll need: Configuring a reverse proxy - Keycloak (the “what”)
Ask a traefik expert on how to configure traefik properly (the “how”).

Additionally:
KC_PROXY_ADDRESS_FORWARDING This is no and has never bin a valid config option.
KC_HOSTNAME_STRICT: "false" Why? As you set KC_HOSTNAME, you also should set strict to true (or just don’t configure it, as true is default)
KC_PROXY: edge This is no more valid, see the linked guide for proper configuration!
KEYCLOAK_ADMIN / KEYCLOAK_ADMIN_PASSWORD This is no more valid, for proper config, see Bootstrapping and recovering an admin account - Keycloak