Skip to content

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

License

Notifications You must be signed in to change notification settings

axcode07/zitadel_deployment

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 

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

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published