Proxying Zitadel with Traefik Service Discovery

Introduction⌗
I don’t need to elaborate on the benefits of using Traefik as a proxy, so let’s go straight to the orchestration configuration.
Service Orchestration⌗
For other Zitadel settings, you can refer to the official default steps.yaml, as well as the default global configuration file defaults.yaml.
The docker-compose.yaml
file configuration is as follows:
services:
zitadel:
image: ghcr.io/zitadel/zitadel:latest
labels:
- traefik.enable=true
- traefik.http.middlewares.gzip.compress=true
- traefik.http.middlewares.cors.headers.accesscontrolallowmethods=GET,OPTIONS,PUT,POST
- traefik.http.middlewares.cors.headers.accesscontrolallowheaders=*
- traefik.http.middlewares.cors.headers.accesscontrolalloworiginlist=*
- traefik.http.middlewares.cors.headers.accesscontrolmaxage=100
- traefik.http.middlewares.cors.headers.addvaryheader=true
- traefik.http.routers.zitadel.rule=Host(`zitadel.local`)
- traefik.http.routers.zitadel.service=zitadel
- traefik.http.routers.zitadel.entrypoints=http
- traefik.http.routers.zitadel.middlewares=redir-https@docker
- traefik.http.services.zitadel.loadbalancer.server.port=8080
- traefik.http.services.zitadel.loadbalancer.server.scheme=h2c
- traefik.http.routers.zitadel-secure.tls=true
- traefik.http.routers.zitadel-secure.rule=Host(`zitadel.local`)
- traefik.http.routers.zitadel-secure.service=zitadel
- traefik.http.routers.zitadel-secure.entrypoints=https
- traefik.http.routers.zitadel-secure.middlewares=gzip@docker
- traefik.http.routers.zitadel-secure.middlewares=cors@docker
restart: always
networks:
- traefik
command: start-from-init --masterkeyFromEnv --tlsMode external
hostname: zitadel
container_name: zitadel
environment:
- ZITADEL_LOG_LEVEL=info
- ZITADEL_MASTERKEY=ZQ0rISokQb0o05LvTwWYyt4z32n82wVv
- ZITADEL_EXTERNALPORT=443
- ZITADEL_EXTERNALSECURE=true
- ZITADEL_EXTERNALDOMAIN=zitadel.local
- ZITADEL_FIRSTINSTANCE_ORG_NAME=BETTERDE
- ZITADEL_FIRSTINSTANCE_ORG_HUMAN_USERNAME=developer
- ZITADEL_FIRSTINSTANCE_ORG_HUMAN_PASSWORD=Developer@2023
- ZITADEL_DEFAULTINSTANCE_ORG_NAME=ZITADEL
- ZITADEL_DEFAULTINSTANCE_INSTANCENAME=ZITADEL
- ZITADEL_OIDC_DEFAULTIDTOKENLIFETIME=24h
- ZITADEL_OIDC_DEFAULTACCESSTOKENLIFETIME=24h
- ZITADEL_DATABASE_COCKROACH_HOST=cockroachdb
- ZITADEL_DATABASE_COCKROACH_USER_SSL_MODE=verify-full
- ZITADEL_DATABASE_COCKROACH_USER_SSL_KEY=/certs/client.zitadel.key
- ZITADEL_DATABASE_COCKROACH_USER_SSL_CERT=/certs/client.zitadel.crt
- ZITADEL_DATABASE_COCKROACH_USER_SSL_ROOTCERT=/certs/ca.crt
- ZITADEL_DATABASE_COCKROACH_USER_USERNAME=zitadel
- ZITADEL_DATABASE_COCKROACH_USER_PASSWORD=u1mXuweLhw4tHvMZtoOtzy0kSqYdJUea
- ZITADEL_DATABASE_COCKROACH_ADMIN_SSL_MODE=verify-full
- ZITADEL_DATABASE_COCKROACH_ADMIN_SSL_KEY=/certs/client.root.key
- ZITADEL_DATABASE_COCKROACH_ADMIN_SSL_CERT=/certs/client.root.crt
- ZITADEL_DATABASE_COCKROACH_ADMIN_SSL_ROOTCERT=/certs/ca.crt
- ZITADEL_DATABASE_COCKROACH_ADMIN_USERNAME=root
- ZITADEL_DATABASE_COCKROACH_ADMIN_PASSWORD=75bdUlVrVFcNQhmSaLhnYfIatU2dsXL9
- ZITADEL_DEFAULTINSTANCE_DOMAINPOLICY_SMTPSENDERADDRESSMATCHESINSTANCEDOMAIN=false
- ZITADEL_DEFAULTINSTANCE_OIDCSETTINGS_IDTOKENLIFETIME=24h
- ZITADEL_DEFAULTINSTANCE_OIDCSETTINGS_ACCESSTOKENLIFETIME=24h
volumes:
- cockroachdb-certs:/certs:ro
depends_on:
cockroachdb:
condition: service_healthy
cockroachdb:
image: cockroachdb/cockroach:latest
labels:
- traefik.enable=true
- traefik.http.middlewares.gzip.compress=true
- traefik.http.routers.cockroachdb.rule=Host(`cockroachdb.service.local`)
- traefik.http.routers.cockroachdb.service=cockroachdb
- traefik.http.routers.cockroachdb.entrypoints=http
- traefik.http.routers.cockroachdb.middlewares=redir-https@docker
- traefik.http.services.cockroachdb.loadbalancer.server.port=8080
- traefik.http.services.cockroachdb.loadbalancer.server.scheme=https
- traefik.http.services.cockroachdb.loadbalancer.passhostheader=true
- traefik.http.routers.cockroachdb-secure.tls=true
- traefik.http.routers.cockroachdb-secure.rule=Host(`cockroachdb.service.local`)
- traefik.http.routers.cockroachdb-secure.service=cockroachdb
- traefik.http.routers.cockroachdb-secure.entrypoints=https
- traefik.http.routers.cockroachdb-secure.middlewares=gzip@docker
restart: always
networks:
- traefik
command: start-single-node --advertise-addr cockroachdb
hostname: cockroachdb
container_name: cockroachdb
volumes:
- cockroachdb-data:/cockroach/cockroach-data:rw
- cockroachdb-certs:/cockroach/certs:rw
environment:
- COCKROACH_USER=zitadel
- COCKROACH_PASSWORD=u1mXuweLhw4tHvMZtoOtzy0kSqYdJUea
- COCKROACH_DATABASE=zitadel
healthcheck:
test: ["CMD", "curl", "-k", "-f", "https://localhost:8080/health?ready=1"]
interval: '10s'
timeout: '30s'
retries: 5
start_period: '20s'
volumes:
cockroachdb-data:
external: true
cockroachdb-certs:
external: true
networks:
traefik:
external: true
Configuration explanation:
- Lines 7-11: Mainly to allow cross-origin requests, so if some services need to use Zitadel’s Logo as an identifier on the login page, there won’t be cross-origin issues;
- Lines 13-16: Set up HTTP routing and redirect to HTTP middleware;
- Lines 18-19: Configure traffic forwarding port and protocol used, since Zitadel supports gRPC, the protocol is set to h2c here;
- Lines 21-26: Set up HTTPS routing
- Line 30: –masterkeyFromEnv gets the master key from environment variables, –tlsMode external is only used when using a proxy and enabling HTTPS
- Line 35: master key
- Lines 37-39: Set external access port and domain name
- Lines 41-43: Set the organization name and username/password for the first instance
- Lines 51-63: Set up cockroachdb database connection, I’m using SSL here
- Lines 81-84: Set up HTTP routing for the cockroachdb admin backend and redirect to HTTPS
- Lines 86-88: Specify upstream port and protocol
- Lines 90-94: Set up HTTPS routing for the cockroachdb admin backend
- Lines 121-123: Use external Traefik network
Start Service⌗
docker compose up -d
The final result is as follows:
I hope this is helpful, Happy hacking…