Zitadel Identity Provider
Zitadel is a modern identity management platform providing OIDC, OAuth2, and SAML authentication. This skill covers Docker deployment with Caddy reverse proxy.
Quick Reference
| Task | Command/Location |
|---|---|
| Console UI | https://auth.example.com/ui/console |
| OIDC Discovery | https://auth.example.com/.well-known/openid-configuration |
| Health check | curl https://auth.example.com/healthz |
| View logs | docker compose logs -f zitadel zitadel-login |
| Restart | docker compose restart zitadel zitadel-login |
Architecture
code
Internet → Caddy (80/443) → Zitadel API (h2c://zitadel:8080)
→ Login UI (http://zitadel-login:3000)
PostgreSQL ← zitadel-init (runs once)
← zitadel (API server)
Three containers:
- •
zitadel-init- Database initialization (runs once, exits) - •
zitadel- API server (gRPC/REST on port 8080) - •
zitadel-login- Login UI (port 3000)
Essential Environment Variables
bash
# Required ZITADEL_MASTERKEY=<32-char-random-string> ZITADEL_DATABASE_POSTGRES_HOST=postgres ZITADEL_DATABASE_POSTGRES_USER_PASSWORD=<password> ZITADEL_EXTERNALDOMAIN=auth.example.com ZITADEL_EXTERNALPORT=443 ZITADEL_EXTERNALSECURE=true ZITADEL_TLS_ENABLED=false # Caddy handles TLS
Generate masterkey: tr -dc A-Za-z0-9 </dev/urandom | head -c 32
Caddy Configuration
Critical: Use h2c:// for HTTP/2 cleartext (required for gRPC):
caddyfile
auth.example.com {
handle /ui/v2/login/* {
reverse_proxy http://zitadel-login:3000
}
handle {
reverse_proxy h2c://zitadel:8080
}
}
Deployment Steps
- •
Start PostgreSQL:
bashdocker compose up -d postgres
- •
Initialize database:
bashdocker compose run zitadel-init
- •
Start services:
bashdocker compose up -d zitadel zitadel-login caddy
- •
Verify health:
bashcurl https://auth.example.com/healthz
- •
Access console:
codehttps://auth.example.com/ui/console
Creating OIDC Applications
- •Console → Organization → Projects → Applications → + New
- •Select application type (Web, Native, API)
- •Configure redirect URIs
- •Save and copy Client ID and Client Secret
Common redirect URIs:
- •Nextcloud:
https://files.example.com/apps/user_oidc/code - •Windmill:
https://windmill.example.com/user/login_callback/zitadel
Service Users (API Access)
- •Console → Users → Service Users → + New
- •Create Personal Access Token (PAT)
- •Assign roles (Org Owner, Project Owner)
- •Use in API calls:
bash
curl -H "Authorization: Bearer <PAT>" \ https://auth.example.com/management/v1/orgs/me
Reference Files
| File | When to Read |
|---|---|
| configuration.md | Environment variables, config file options |
| caddy-integration.md | Reverse proxy setup, h2c configuration |
| oidc-applications.md | Creating apps, Nextcloud integration |
| api-reference.md | REST/gRPC endpoints, authentication |
| troubleshooting.md | Common issues and diagnostics |
Official Documentation
| Topic | URL |
|---|---|
| Self-Hosting | https://zitadel.com/docs/self-hosting/deploy/overview |
| Configuration | https://zitadel.com/docs/self-hosting/manage/configure |
| Caddy Setup | https://zitadel.com/docs/self-hosting/manage/reverseproxy/caddy |
| OIDC Integration | https://zitadel.com/docs/guides/integrate/login/oidc |
| API Reference | https://zitadel.com/docs/apis/introduction |
| Service Users | https://zitadel.com/docs/guides/integrate/service-users/personal-access-token |
Troubleshooting Quick Guide
| Issue | Check |
|---|---|
| Container won't start | docker compose logs zitadel - check masterkey (32 chars) |
| Login page blank | docker compose ps zitadel-login - check Caddy routes |
| gRPC errors | Ensure h2c:// in Caddyfile, not http:// |
| OIDC 404 | curl https://auth.example.com/healthz - check external domain |
| Token invalid | Check issuer URL matches, token not expired |