Skip to main content

Load Balancing Example

With this example configuration, you create a near production environment for ZITADEL with Docker Compose.

The stack consists of three long-running containers:

  • A Traefik reverse proxy with upstream HTTP/2 enabled, issuing a self-signed TLS certificate.
  • A secure ZITADEL container configured for a custom domain. As we terminate TLS with Traefik, we configure ZITADEL for --tlsMode external.
  • A secure CockroachDB.

The setup is tested against Docker version 20.10.17 and Docker Compose version v2.2.3

By executing the commands below, you will download the following files:

docker-compose.yaml
version: '3.8'
services:

traefik:
networks:
- 'zitadel'
image: "traefik:v2.7"
ports:
- "80:80"
- "443:443"
volumes:
- "./example-traefik.yaml:/etc/traefik/traefik.yaml"

zitadel:
restart: 'always'
networks:
- 'zitadel'
image: 'ghcr.io/zitadel/zitadel:stable'
command: 'start-from-init --config /example-zitadel-config.yaml --config /example-zitadel-secrets.yaml --steps /example-zitadel-init-steps.yaml --masterkey "${ZITADEL_MASTERKEY}" --tlsMode external'
depends_on:
certs:
condition: 'service_completed_successfully'

volumes:
- './example-zitadel-config.yaml:/example-zitadel-config.yaml:ro'
- './example-zitadel-secrets.yaml:/example-zitadel-secrets.yaml:ro'
- './example-zitadel-init-steps.yaml:/example-zitadel-init-steps.yaml:ro'
- 'zitadel-certs:/crdb-certs:ro'

certs:
image: 'cockroachdb/cockroach:v22.2.2'
entrypoint: [ '/bin/bash', '-c' ]
command: [ 'cp /certs/* /zitadel-certs/ && cockroach cert create-client --overwrite --certs-dir /zitadel-certs/ --ca-key /zitadel-certs/ca.key zitadel_user && chown 1000:1000 /zitadel-certs/*' ]
volumes:
- 'certs:/certs:ro'
- 'zitadel-certs:/zitadel-certs:rw'
depends_on:
my-cockroach-db:
condition: 'service_healthy'

my-cockroach-db:
restart: 'always'
networks:
- 'zitadel'
image: 'cockroachdb/cockroach:v22.2.2'
command: 'start-single-node --advertise-addr my-cockroach-db'
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health?ready=1"]
interval: '10s'
timeout: '30s'
retries: 5
start_period: '20s'
ports:
- '9090:8080'
- '26257:26257'
volumes:
- 'certs:/cockroach/certs:rw'
- 'data:/cockroach/cockroach-data:rw'

networks:
zitadel:

volumes:
certs:
zitadel-certs:
data:
example-traefik.yaml
entrypoints:
web:
address: ":80"

websecure:
address: ":443"

tls:
stores:
default:
# generates self-signed certificates
defaultCertificate:

providers:
file:
filename: /etc/traefik/traefik.yaml

http:

middlewares:
zitadel:
headers:
isDevelopment: false
allowedHosts:
- 'my.domain'
customRequestHeaders:
:authority: 'my.domain'
redirect-to-https:
redirectScheme:
scheme: https
port: 443
permanent: true

routers:
# Redirect HTTP to HTTPS
router0:
entryPoints:
- web
middlewares:
- redirect-to-https
rule: 'HostRegexp(`my.domain`, `{subdomain:[a-z]+}.my.domain`)'
service: zitadel
# The actual ZITADEL router
router1:
entryPoints:
- websecure
service: zitadel
middlewares:
- zitadel
rule: 'HostRegexp(`my.domain`, `{subdomain:[a-z]+}.my.domain`)'
tls:
domains:
- main: "my.domain"
sans:
- "*.my.domain"
- "my.domain"

# Add the service
services:
zitadel:
loadBalancer:
servers:
# h2c is the scheme for unencrypted HTTP/2
- url: h2c://zitadel:8080
passHostHeader: true
example-zitadel-config.yaml
# All possible options and their defaults: https://github.com/zitadel/zitadel/blob/main/cmd/defaults.yaml
Log:
Level: 'info'

# Make ZITADEL accessible over HTTP, not HTTPS
ExternalSecure: true
ExternalDomain: my.domain
ExternalPort: 443

# If not using the docker compose example, adjust these values for connecting ZITADEL to your CockroachDB
Database:
cockroach:
Host: 'my-cockroach-db'
User:
SSL:
Mode: 'verify-full'
RootCert: "/crdb-certs/ca.crt"
Cert: "/crdb-certs/client.zitadel_user.crt"
Key: "/crdb-certs/client.zitadel_user.key"
Admin:
SSL:
Mode: 'verify-full'
RootCert: "/crdb-certs/ca.crt"
Cert: "/crdb-certs/client.root.crt"
Key: "/crdb-certs/client.root.key"
example-zitadel-secrets.yaml
# All possible options and their defaults: https://github.com/zitadel/zitadel/blob/main/cmd/defaults.yaml

# If not using the docker compose example, adjust these values for connecting ZITADEL to your CockroachDB
Database:
cockroach:
User:
# If the user doesn't exist already, it is created
Username: 'zitadel_user'
Admin:
Username: 'root'
example-zitadel-init-steps.yaml
# All possible options and their defaults: https://github.com/zitadel/zitadel/blob/main/cmd/setup/steps.yaml
FirstInstance:
Org:
Name: 'My Org'
Human:
# use the loginname root@my-org.my.domain
Username: 'root'
Password: 'RootPassword1!'
# Download the docker compose example configuration.
wget https://raw.githubusercontent.com/zitadel/zitadel/main/docs/docs/self-hosting/deploy/loadbalancing-example/docker-compose.yaml

# Download the Traefik example configuration.
wget https://raw.githubusercontent.com/zitadel/zitadel/main/docs/docs/self-hosting/deploy/loadbalancing-example/example-traefik.yaml

# Download and adjust the example configuration file containing standard configuration.
wget https://raw.githubusercontent.com/zitadel/zitadel/main/docs/docs/self-hosting/deploy/loadbalancing-example/example-zitadel-config.yaml

# Download and adjust the example configuration file containing secret configuration.
wget https://raw.githubusercontent.com/zitadel/zitadel/main/docs/docs/self-hosting/deploy/loadbalancing-example/example-zitadel-secrets.yaml

# Download and adjust the example configuration file containing database initialization configuration.
wget https://raw.githubusercontent.com/zitadel/zitadel/main/docs/docs/self-hosting/deploy/loadbalancing-example/example-zitadel-init-steps.yaml

# A single ZITADEL instance always needs the same 32 characters long masterkey
# If you haven't done so already, you can generate a new one.
# For example:
export ZITADEL_MASTERKEY="$(tr -dc A-Za-z0-9 </dev/urandom | head -c 32)"

# Run the database and application containers
docker compose up --detach

Make 127.0.0.1 available at my.domain. For example, this can be achived with an entry 127.0.1.1 my.domain in the /etc/hosts file.

Open your favorite internet browser at https://my.domain/ui/console/. You can safely proceed, if your browser warns you about the insecure self-signed TLS certificate. This is the IAM admin users login according to your configuration in the example-zitadel-init-steps.yaml:

  • username: root@my-org.my.domain
  • password: RootPassword1!

Read more about the login process.