This docker-compose.yml example creates a setup with Traefik for reverse proxying, PostgreSQL for data storage, and Keycloak for authentication. Here’s a breakdown of the essential parts and configurations.
Example docker-compose.yml
services:
traefik:
image: traefik:v2.11
restart: unless-stopped
command:
- "--certificatesresolvers.{your-resolver-name}.acme.email={your-email}"
- "--certificatesresolvers.{your-resolver-name}.acme.storage=/etc/traefik/acme.json"
- "--certificatesresolvers.{your-resolver-name}.acme.tlschallenge=true"
- "--entrypoints.web.address=:80"
- "--entrypoints.web.http.redirections.entryPoint.permanent=true"
- "--entrypoints.web.http.redirections.entryPoint.scheme=https"
- "--entrypoints.web.http.redirections.entryPoint.to=websecure"
- "--entrypoints.websecure.address=:443"
- "--providers.docker=true"
ports:
- "80:80"
- "443:443"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
- "{your-traefik-directory}:/etc/traefik"
postgres:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_DB: ${KEYCLOAK_DB}
POSTGRES_USER: ${KEYCLOAK_DB_USERNAME}
POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password
volumes:
- postgres_data:/var/lib/postgresql/data
secrets:
- postgres_password
healthcheck:
test: ["CMD-SHELL", "sh -c 'pg_isready -U ${KEYCLOAK_DB_USERNAME} -d ${KEYCLOAK_DB}'"]
interval: 30s
timeout: 10s
retries: 3
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
keycloak:
image: keycloak/keycloak:26.0
restart: unless-stopped
command: start --optimized
environment:
KC_BOOTSTRAP_ADMIN_PASSWORD: ${KC_BOOTSTRAP_ADMIN_PASSWORD}
KC_BOOTSTRAP_ADMIN_USERNAME: ${KC_BOOTSTRAP_ADMIN_USERNAME}
KC_DB_PASSWORD: ${POSTGRES_KC_PASSWORD}
KC_DB_URL: ${KEYCLOAK_DB_URL}
KC_DB_USERNAME: ${KEYCLOAK_DB_USERNAME}
KC_DB: postgres
KC_HOSTNAME_STRICT: "true"
KC_HOSTNAME: "auth.example.com"
KC_HTTP_ENABLED: "true"
KC_PROXY_HEADERS: "xforwarded"
labels:
- "traefik.http.routers.keycloak.rule=Host(\"auth.example.com\")"
- "traefik.http.routers.keycloak.tls=true"
- "traefik.http.routers.keycloak.tls.certresolver={your-resolver-name}"
- "traefik.http.routers.keycloak.tls.domains[0].main=auth.example.com"
- "traefik.http.services.keycloak.loadbalancer.server.port=8080"
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
depends_on:
postgres:
condition: service_healthy
secrets:
postgres_password:
file: ./secrets/postgres_password
volumes:
postgres_data:
Breaking Down the Configuration
Keycloak and Postgres Version
I used the latest version of Keycloak along with the corresponding compatible version of PostgreSQL. Ensuring compatibility is essential for stability, as not all PostgreSQL versions are supported by Keycloak. For the latest supported versions, refer to Keycloak’s Supported Databases page.
Using Docker Secrets
Docker secrets offer a secure way to manage these details, replacing environment variables with references to secret files.
In the configuration:
POSTGRES_PASSWORD_FILEis used to set the password for PostgreSQL by pointing to a secure Docker secret instead of an environment variable.- To set up Docker secrets, create a
postgres_passwordfile in a secure location (./secrets/postgres_password), which Docker Compose will reference directly.
Using secrets this way ensures passwords are isolated and accessible only to the specific services that require them.
Setting Resource Limits
Docker’s default resource allocation can sometimes be insufficient, particularly for resource-intensive applications like databases. PostgreSQL, in this setup, is limited by both CPU and memory usage to prevent resource exhaustion on shared systems.
Example:
resources:
limits:
cpus: '0.5'
memory: 512M
Optimized Keycloak Command for Production
In production, it’s essential to use Keycloak’s start command with the --optimized flag, which is only used after the initial build. For the initial build of Keycloak container, use start.
Keycloak Environment Variables Explained
-
KC_BOOTSTRAP_ADMIN_PASSWORDandKC_BOOTSTRAP_ADMIN_USERNAME: These variables initialize the Keycloak admin user. They’re critical for the first login and should be set to secure values. For added security, consider storing these in Docker secrets. -
KC_HTTP_ENABLED: Since Traefik handles HTTPS connections, Keycloak can communicate over HTTP within the internal Docker network. SettingKC_HTTP_ENABLEDtotrueallows HTTP traffic internally, streamlining communication and performance between services. -
KC_PROXY_HEADERS: This setting, introduced in newer Keycloak versions, replaces the previousKC_PROXYconfiguration (KC_PROXY=edge). It configures Keycloak to respect proxy headers (likeX-Forwarded-For), which is essential when using a reverse proxy like Traefik to forward requests to Keycloak securely.
This setup serves as a foundational example, with room for further improvements—such as completely eliminating environment variables for database passwords to enhance security.