Files
templates/blueprints/zitadel/docker-compose.yml
Mauricio Siu 6786237720 fix(zitadel): wire EXTERNALDOMAIN/PORT/SECURE to the generated domain
Zitadel resolves its instance from the external domain/port/scheme, so the
template's ZITADEL_EXTERNALPORT=8080 made every generated URL (OIDC issuer,
login redirects) point at http://<domain>:8080 instead of the domain served
by Traefik, ending in {"code":5,"message":"Not Found"} (#516).

- Expose ZITADEL_EXTERNALDOMAIN / ZITADEL_EXTERNALPORT / ZITADEL_EXTERNALSECURE
  as template env vars, defaulting to the generated domain over HTTP
  (port 80, secure=false) so the routed domain and Zitadel's external config
  always match; HTTPS users flip them to 443/true in the Env tab.
- Pin image to v4.16.0 (was latest) and keep the built-in login v1 via
  ZITADEL_DEFAULTINSTANCE_FEATURES_LOGINV2_REQUIRED=false so no separate
  login-v2 container is needed.
- Add the official readiness healthcheck, drop the unused /app/data volume,
  bogus SMTP env keys, published port and obsolete compose version key.

Closes #516

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 11:12:30 -06:00

68 lines
2.6 KiB
YAML

services:
zitadel:
restart: 'always'
image: 'ghcr.io/zitadel/zitadel:v4.16.0'
command: 'start-from-init --masterkey "${ZITADEL_MASTERKEY}" --tlsMode disabled'
environment:
# Database Configuration
ZITADEL_DATABASE_POSTGRES_HOST: db
ZITADEL_DATABASE_POSTGRES_PORT: 5432
ZITADEL_DATABASE_POSTGRES_DATABASE: zitadel
ZITADEL_DATABASE_POSTGRES_USER_USERNAME: zitadel
ZITADEL_DATABASE_POSTGRES_USER_PASSWORD: "${POSTGRES_PASSWORD}"
ZITADEL_DATABASE_POSTGRES_USER_SSL_MODE: disable
ZITADEL_DATABASE_POSTGRES_ADMIN_USERNAME: postgres
ZITADEL_DATABASE_POSTGRES_ADMIN_PASSWORD: "${POSTGRES_PASSWORD}"
ZITADEL_DATABASE_POSTGRES_ADMIN_SSL_MODE: disable
# External access configuration. These MUST match the domain configured
# in the Domains tab and the scheme/port it is served on, otherwise
# Zitadel answers {"code":5,"message":"Not Found"}.
# HTTP -> ZITADEL_EXTERNALPORT=80, ZITADEL_EXTERNALSECURE=false
# HTTPS -> ZITADEL_EXTERNALPORT=443, ZITADEL_EXTERNALSECURE=true
ZITADEL_EXTERNALDOMAIN: "${ZITADEL_EXTERNALDOMAIN}"
ZITADEL_EXTERNALPORT: "${ZITADEL_EXTERNALPORT}"
ZITADEL_EXTERNALSECURE: "${ZITADEL_EXTERNALSECURE}"
ZITADEL_TLS_ENABLED: false
# Custom Admin User Configuration
ZITADEL_FIRSTINSTANCE_ORG_HUMAN_USERNAME: "${ZITADEL_FIRSTINSTANCE_ORG_HUMAN_USERNAME}"
ZITADEL_FIRSTINSTANCE_ORG_HUMAN_PASSWORD: "${ZITADEL_FIRSTINSTANCE_ORG_HUMAN_PASSWORD}"
ZITADEL_FIRSTINSTANCE_ORG_HUMAN_EMAIL_ADDRESS: "${ZITADEL_FIRSTINSTANCE_ORG_HUMAN_EMAIL_ADDRESS}"
ZITADEL_FIRSTINSTANCE_ORG_HUMAN_FIRSTNAME: "${ZITADEL_FIRSTINSTANCE_ORG_HUMAN_FIRSTNAME}"
ZITADEL_FIRSTINSTANCE_ORG_HUMAN_LASTNAME: "${ZITADEL_FIRSTINSTANCE_ORG_HUMAN_LASTNAME}"
# Use the login UI built into the API container (no extra login-v2 service needed)
ZITADEL_DEFAULTINSTANCE_FEATURES_LOGINV2_REQUIRED: false
healthcheck:
test: ["CMD", "/app/zitadel", "ready"]
interval: '10s'
timeout: '30s'
retries: 12
start_period: '30s'
depends_on:
db:
condition: 'service_healthy'
expose:
- 8080
db:
restart: 'always'
image: postgres:17-alpine
environment:
PGUSER: postgres
POSTGRES_PASSWORD: "${POSTGRES_PASSWORD}"
POSTGRES_DB: zitadel
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready", "-d", "zitadel", "-U", "postgres"]
interval: '10s'
timeout: '30s'
retries: 5
start_period: '20s'
volumes:
postgres_data: