Skip to content

About

Deploy Zitadel on your own domain using traefik proxy and benefit of everything it can do for your business!

Resources

Stars

2 stars

Watchers

0 watching

Forks

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 

Repository files navigation

Deploy ZITADEL on Your Own Domain (Docker Compose + Traefik)

A production-ready Docker Compose setup to run ZITADEL on your own domain, with:

  • PostgreSQL 17 as the backend database
  • Traefik as reverse proxy with automatic HTTPS via ACME
  • ZITADEL Login v2 served from a dedicated container and path (/ui/v2/login)
  • Clear separation between API traffic and Login traffic

✨ This repo gives you a full working compose that you can drop into a server with Docker + Traefik and be up quickly. You only need to change a handful of values (domain, secrets, passwords).


Prerequisites

  • A working domain pointing to your server’s public IP. You can use a subdomain (e.g., auth.yourdomain.com).

  • Docker Engine and docker-compose installed.

  • A Traefik instance already running on the same Docker host, with:

    • An external Docker network that Traefik and ZITADEL will share (e.g., traefik-network).
    • A certresolver configured (e.g., resolver) for Let’s Encrypt or your chosen CA.

The compose below expects an external Docker network named traefik-network. If you use a different name, update it accordingly.


What You’ll Get (Architecture)

Internet → Traefik (TLS termination)
             ├─ route /ui/v2/login → zitadel-login (Next.js app, port 3000)
             └─ route everything else → zitadel (HTTP/2 cleartext on 8080)

zitadel ↔ postgres (17-alpine)
  • TLS is terminated at Traefik; ZITADEL runs in --tlsMode external and speaks h2c (HTTP/2 cleartext) internally.
  • Login v2 is a separate container that consumes a Service User token (PAT) written during first-run bootstrap.

Quick Start

  1. Clone this repository and cd into it.

  2. Edit environment placeholders in the compose:

    • Domain everywhere (your.domain.com) and external domain variable value.
    • Strong secrets: Master key, DB passwords, initial admin password, etc.
  3. Ensure Traefik is up and exposing the expected entrypoints (web, websecure) and has a certresolver (e.g., resolver).

  4. Create the shared Docker network if it doesn’t exist yet:

    docker network create traefik-network
  5. Launch ZITADEL stack:

    docker compose up -d
  6. Watch logs until healthy:

    docker compose logs -f zitadel
    docker compose logs -f login
  7. Visit https://your.domain.com and log in with the first admin credentials you configured.


The Compose (as provided) ---> see docker-compose.yml

Note: Compose will create the pgdata_docs volume automatically on first run. You can also predeclare it under volumes: at top-level if you prefer.


Configuration Checklist

  • Domain consistency: Use the same domain in all places (ZITADEL_EXTERNALDOMAIN, Traefik router rules, Login envs, and the *_DEFAULTLOGINURLV2/*_DEFAULTLOGOUTURLV2).
  • Master key: --masterkey must be exactly 32 characters.
  • Strong passwords: Replace all placeholder passwords with strong secrets.
  • Traefik certresolver: Ensure the label value matches your traefik.yml configuration (e.g., resolver).
  • Shared network: The compose must join the exact external Traefik network name.

DNS & TLS

  • Create an A/AAAA record for your.domain.com to your server.
  • Traefik terminates TLS, obtains/renews certificates, and forwards h2c to ZITADEL on port 8080.
  • The compose defines an HTTP router for redirect and a secure router for the API. The Login router has a higher priority (30) to win for /ui/v2/login.

If your Traefik version does not support rule negation (!PathPrefix(...)), the priority alone will still route /ui/v2/login to the login service.


Persistence & Backup

  • Postgres data: stored in the pgdata_docs Docker volume.
  • Service token (PAT): written to ./login-client.pat on the host by the ZITADEL container at first init. Keep this safe.

Backup tips:

# Stop app traffic briefly (optional) and dump DB
PGPASSWORD=yourpostgrespassword \
pg_dump -h 127.0.0.1 -U postgres -d zitadel_docs > zitadel_backup_$(date +%F).sql

# Or snapshot the named Docker volume using your preferred tooling

Upgrades

  • ZITADEL: update the image tag (ideally pin by digest), read the release notes, and docker compose pull && docker compose up -d.
  • Login: update ghcr.io/zitadel/zitadel-login:latest or pin to a specific version.
  • Postgres: upgrade only after confirming compatibility and having a valid backup.

Security Notes

  • Prefer Docker secrets or an .env file with tight permissions for sensitive values (master key, passwords). Avoid committing secrets.
  • Restrict access to the host directory that contains login-client.pat.
  • Consider adding basic resource limits (CPU/memory) per service.

Troubleshooting

  • 404 on /ui/v2/login: Check router priority and that the login container is healthy and on the traefik-network.
  • TLS not issued: Verify your DNS, Traefik entrypoints (web/websecure), and that the certresolver name matches your Traefik config.
  • Login PAT missing: Ensure the ZITADEL_FIRSTINSTANCE_LOGINCLIENTPATPATH path is bind-mounted and writable by the ZITADEL container.
  • 403/redirect loops: Re-check domain consistency across ZITADEL_EXTERNALDOMAIN and all *_DEFAULT*URLV2 variables.

Uninstall / Cleanup

docker compose down
# Remove persistent data (⚠️ irreversible)
docker volume rm <your_project>_pgdata_docs
rm -f ./login-client.pat

License

MIT


Made with ❤️ by AXCODE

About

Deploy Zitadel on your own domain using traefik proxy and benefit of everything it can do for your business!

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors