Search code examples
dockernginxkeycloaktraefik

Keycloak in Docker with proxy such as nginx using non-standard ports


This is sort of a follow up question to this question.

Originally, I tried to get Keycloak to work in Docker and needed TLS, so I used nginx with docker compose. But I got an infinite spinner like people in the question, which I found via Google when trying to solve my problem. So I read in answers that people in the question said not to KC_HOSTNAME_PORT. So I tried this and indeed, it worked with port 443.

That is fine and good, but I want to get Keycloak to work in my setup with different ports such as 8443. Can someone explain how to do this based on the setup offered in the original question I referred to? Or post a complete example with a docker-compose.yml of how to do it with nginx or traefik?

EDIT: If it helps, here is my docker-compose.yml:

version: '3'

services:
  keycloak:
    image: quay.io/keycloak/keycloak:19.0.2
    container_name: keycloak
    environment:
      KEYCLOAK_ADMIN: admin
      KEYCLOAK_ADMIN_PASSWORD: admin
      PROXY_ADDRESS_FORWARDING: 'true'
      KC_HOSTNAME_STRICT: 'false'
      KC_HTTP_ENABLED: 'true'
      KC_PROXY: 'edge'
      # more
      KC_PROXY_ADDRESS_FORWARDING: "true"
      KC_HOSTNAME: kvm1.home
      #KC_HOSTNAME_PORT: 4443
    ports:
      - "8080:8080"
    command:
      - start-dev
      - "--proxy=edge"
      - "--hostname-strict-https=false"
  nginx:
    image: nginx:1.23.1
    container_name: nginx
    volumes:
      - ./templates:/etc/nginx/templates
    ports:
      #- "8000:80"
      #- "4443:443"
      - "80:80"
      - "443:443"
    environment:
      - NGINX_HOST=localhost
      - NGINX_PORT=80
    volumes:
      - ./ssl:/etc/nginx/ssl
      - ./sites-enabled:/etc/nginx/sites-enabled
      - ./nginx.conf:/etc/nginx/nginx.conf:rw
server {
    listen 80;
    listen [::]:80;
    listen 443 ssl;
    listen [::]:443 ssl;
    # include snippets/snakeoil.conf;
    ssl_certificate /etc/nginx/ssl/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/privkey.pem;

    root /var/www/html;
    index index.html index.htm index.nginx-debian.html;
    server_name kvm1.home;
    location / {
        proxy_pass http://kvm1.home:8080/;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_protocol_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

If I used the uncommented KC_HOSTNAME_PORT and the uncommented different ports in nginx.environment, I get the infinite spinner.


Solution

  • If you want keycloak to expose keycloak on a different port, you need to make two changes:

    • Change the port on which you're publishing web-secure endpoint from Traefik
    • Set KC_HOSTNAME_PORT to match the new port

    So that gets us:

    version: "3"
    
    services:
      traefik:
        image: docker.io/traefik
        command:
          - --api.insecure=true
          - --providers.docker
          - --entrypoints.web.address=:80
          - --entrypoints.web-secure.address=:443
        ports:
          - "127.0.0.1:8080:8080"
          - "80:80"
          - "8443:443"
        volumes:
          - /var/run/docker.sock:/var/run/docker.sock
    
      keycloak:
        image: quay.io/keycloak/keycloak
        restart: always
        command: start
        environment:
          KC_PROXY_ADDRESS_FORWARDING: "true"
          KC_HOSTNAME_STRICT: "false"
          KC_HOSTNAME: auth.example.com
          KC_HOSTNAME_PORT: 8443
          KC_PROXY: edge
          KC_HTTP_ENABLED: "true"
          KC_DB: postgres
          KC_DB_URL: jdbc:postgresql://postgres:5432/$POSTGRES_DB?ssl=allow
          KC_DB_USERNAME: $POSTGRES_USER
          KC_DB_PASSWORD: $POSTGRES_PASSWORD
          KEYCLOAK_ADMIN: admin
          KEYCLOAK_ADMIN_PASSWORD: password
        labels:
          - "traefik.http.routers.cloud-network-keycloak.rule=Host(`auth.example.com`)"
          - "traefik.http.routers.cloud-network-keycloak.tls=true"
          - "traefik.http.services.cloud-network-keycloak.loadbalancer.server.port=8080"
    
      postgres:
        image: docker.io/postgres:14
        environment:
          POSTGRES_USER: $POSTGRES_USER
          POSTGRES_PASSWORD: $POSTGRES_PASSWORD
          POSTGRES_DB: $POSTGRES_DB
    

    With this configuration, and an appropriate entry in my local /etc/hosts, file, I can access keycloak at https://auth.example.com:8443.