name: zitadel services: zitadel-api: image: ghcr.io/zitadel/zitadel:${ZITADEL_VERSION} restart: unless-stopped user: "0" command: start-from-init --masterkey "${ZITADEL_MASTERKEY}" environment: ZITADEL_PORT: 8080 ZITADEL_EXTERNALDOMAIN: ${ZITADEL_DOMAIN} ZITADEL_EXTERNALPORT: ${ZITADEL_EXTERNALPORT} ZITADEL_EXTERNALSECURE: ${ZITADEL_EXTERNALSECURE} ZITADEL_TLS_ENABLED: false ZITADEL_DATABASE_POSTGRES_DSN: ${ZITADEL_DATABASE_POSTGRES_DSN} ZITADEL_FIRSTINSTANCE_ORG_HUMAN_PASSWORDCHANGEREQUIRED: false ZITADEL_FIRSTINSTANCE_LOGINCLIENTPATPATH: /zitadel/bootstrap/login-client.pat ZITADEL_FIRSTINSTANCE_ORG_LOGINCLIENT_MACHINE_USERNAME: login-client ZITADEL_FIRSTINSTANCE_ORG_LOGINCLIENT_MACHINE_NAME: Automatically Initialized IAM_LOGIN_CLIENT ZITADEL_FIRSTINSTANCE_ORG_LOGINCLIENT_PAT_EXPIRATIONDATE: ${LOGIN_CLIENT_PAT_EXPIRATION} ZITADEL_DEFAULTINSTANCE_FEATURES_LOGINV2_REQUIRED: true ZITADEL_DEFAULTINSTANCE_FEATURES_LOGINV2_BASEURI: ${ZITADEL_PUBLIC_SCHEME}://${ZITADEL_DOMAIN}/ui/v2/login/ ZITADEL_OIDC_DEFAULTLOGINURLV2: ${ZITADEL_PUBLIC_SCHEME}://${ZITADEL_DOMAIN}/ui/v2/login/login?authRequest= ZITADEL_OIDC_DEFAULTLOGOUTURLV2: ${ZITADEL_PUBLIC_SCHEME}://${ZITADEL_DOMAIN}/ui/v2/login/logout?post_logout_redirect= ZITADEL_SAML_DEFAULTLOGINURLV2: ${ZITADEL_PUBLIC_SCHEME}://${ZITADEL_DOMAIN}/ui/v2/login/login?samlRequest= ZITADEL_LOGSTORE_ACCESS_STDOUT_ENABLED: ${ZITADEL_ACCESS_LOG_STDOUT_ENABLED} ZITADEL_INSTRUMENTATION_TRACE_EXPORTER_TYPE: ${ZITADEL_INSTRUMENTATION_TRACE_EXPORTER_TYPE:-otlp} ZITADEL_INSTRUMENTATION_TRACE_EXPORTER_ENDPOINT: ${ZITADEL_INSTRUMENTATION_TRACE_EXPORTER_ENDPOINT:-http://lgtm:4318} ZITADEL_INSTRUMENTATION_TRACE_EXPORTER_INSECURE: ${ZITADEL_INSTRUMENTATION_TRACE_EXPORTER_INSECURE:-true} ZITADEL_INSTRUMENTATION_SERVICENAME: ${ZITADEL_INSTRUMENTATION_SERVICENAME:-zitadel} ZITADEL_CACHES_CONNECTORS_REDIS_ENABLED: ${ZITADEL_CACHES_CONNECTORS_REDIS_ENABLED} ZITADEL_CACHES_CONNECTORS_REDIS_URL: ${ZITADEL_CACHES_CONNECTORS_REDIS_URL} ZITADEL_CACHES_INSTANCE_CONNECTOR: ${ZITADEL_CACHES_INSTANCE_CONNECTOR} ZITADEL_CACHES_MILESTONES_CONNECTOR: ${ZITADEL_CACHES_MILESTONES_CONNECTOR} ZITADEL_CACHES_ORGANIZATION_CONNECTOR: ${ZITADEL_CACHES_ORGANIZATION_CONNECTOR} healthcheck: test: - CMD - /app/zitadel - ready interval: 10s timeout: 30s retries: 12 start_period: 20s volumes: - zitadel-bootstrap:/zitadel/bootstrap:rw networks: zitadel: {} swag: aliases: - zitadel-api pipeline: aliases: - zitadel-api depends_on: postgres: condition: service_healthy zitadel-login: image: ghcr.io/zitadel/zitadel-login:${ZITADEL_VERSION} restart: unless-stopped user: "0" environment: ZITADEL_API_URL: http://zitadel-api:8080 NEXT_PUBLIC_BASE_PATH: /ui/v2/login ZITADEL_SERVICE_USER_TOKEN_FILE: /zitadel/bootstrap/login-client.pat CUSTOM_REQUEST_HEADERS: Host:${ZITADEL_DOMAIN},X-Forwarded-Proto:${ZITADEL_PUBLIC_SCHEME} # OpenTelemetry — export traces to the otel-lgtm pipeline OTEL_SERVICE_NAME: ${OTEL_SERVICE_NAME:-zitadel-login} OTEL_EXPORTER_OTLP_ENDPOINT: ${OTEL_EXPORTER_OTLP_ENDPOINT:-http://lgtm:4318} OTEL_EXPORTER_OTLP_PROTOCOL: ${OTEL_EXPORTER_OTLP_PROTOCOL:-http/protobuf} healthcheck: test: - CMD - /bin/sh - -c - node /app/healthcheck.mjs http://localhost:3000/ui/v2/login/healthy interval: 10s timeout: 30s retries: 12 start_period: 20s volumes: - zitadel-bootstrap:/zitadel/bootstrap:ro networks: zitadel: {} swag: aliases: - zitadel-login pipeline: aliases: - zitadel-login depends_on: zitadel-api: condition: service_healthy postgres: image: ${POSTGRES_IMAGE} restart: unless-stopped environment: POSTGRES_PASSWORD: ${POSTGRES_ADMIN_PASSWORD} POSTGRES_USER: ${POSTGRES_ADMIN_USER} POSTGRES_DB: ${POSTGRES_DB} healthcheck: test: - CMD-SHELL - pg_isready -d ${POSTGRES_DB} -U ${POSTGRES_ADMIN_USER} interval: 10s timeout: 30s retries: 10 start_period: 20s volumes: - postgres-data:/var/lib/postgresql/data:rw networks: zitadel: {} swag: aliases: - zitadel-login redis: image: ${REDIS_IMAGE} restart: unless-stopped profiles: - cache command: - --save - "" - --appendonly - "no" networks: - zitadel otel-collector: image: ${OTEL_COLLECTOR_IMAGE} restart: unless-stopped profiles: - observability command: - --config=/etc/otelcol/config.yaml volumes: - ./otel-collector-config.yaml:/etc/otelcol/config.yaml:ro networks: - zitadel networks: # Internal network — postgres, redis, otel-collector not exposed to SWAG. zitadel: name: zitadel # External network created by SWAG. Both zitadel-api and zitadel-login join it # so SWAG's nginx can reach them by container name without publishing host ports. swag: name: ${SWAG_NETWORK} external: true pipeline: name: pipeline external: true volumes: postgres-data: zitadel-bootstrap: