This guide runs ZITADEL in containers using Docker Compose. ZITADEL requires a PostgreSQL database as its backend and supports multiple deployment configurations.
For a quick evaluation setup:
# Pull the latest ZITADEL image
docker pull ghcr.io/zitadel/zitadel:latest
# Run with minimal configuration (for evaluation only)
docker run -p 8080:8080 -e "ZITADEL_DATABASE_POSTGRES_HOST=" --rm ghcr.io/zitadel/zitadel:latest start-from-init --masterkey "test" --tlsMode disabled
Create a docker-compose.yml file for a production-ready setup with PostgreSQL:
version: '3.8'
services:
zitadel-db:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_DB: zitadel
POSTGRES_USER: zitadel
POSTGRES_PASSWORD: ${ZITADEL_DB_PASSWORD}
volumes:
- zitadel_postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U zitadel"]
interval: 30s
timeout: 10s
retries: 5
networks:
- zitadel-network
zitadel:
image: ghcr.io/zitadel/zitadel:4.10.1
restart: unless-stopped
depends_on:
zitadel-db:
condition: service_healthy
environment:
# Database configuration
ZITADEL_DATABASE_POSTGRES_HOST: zitadel-db
ZITADEL_DATABASE_POSTGRES_PORT: 5432
ZITADEL_DATABASE_POSTGRES_DATABASE: zitadel
ZITADEL_DATABASE_POSTGRES_USER_USERNAME: zitadel
ZITADEL_DATABASE_POSTGRES_USER_PASSWORD: ${ZITADEL_DB_PASSWORD}
# External configuration
ZITADEL_EXTERNAL_ISSUER: https://${ZITADEL_HOSTNAME} # Replace with your domain
# TLS configuration (disable for HTTP proxy setup)
ZITADEL_TLS_MODE: disabled # Set to 'custom' for SSL termination inside container
# CORS configuration
ZITADEL_CORS_ALLOWEDORIGINS_0: https://${ZITADEL_HOSTNAME}
# Master key for encryption
ZITADEL_KEYS_CRYPTOGRAPHY_0_KEY: ${ZITADEL_MASTERKEY}
# Feature flags
ZITADEL_FEATURES_UNIQUEORGID: "true"
ports:
- "8080:8080" # HTTP
- "8081:8081" # gRPC
command: [
"start-from-init",
"--masterkey=${ZITADEL_MASTERKEY}",
"--organization.name=Main Organization",
"--human.username=admin",
"--human.email=admin@${ZITADEL_HOSTNAME}",
"--human.password=${ZITADEL_ADMIN_PASSWORD}"
]
networks:
- zitadel-network
healthcheck:
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:8080/healthz"]
interval: 30s
timeout: 10s
retries: 5
volumes:
zitadel_postgres_data:
networks:
zitadel-network:
driver: bridge
Create a .env file in the same directory as your docker-compose.yml:
# Database password
ZITADEL_DB_PASSWORD=your_secure_database_password
# Master key for encryption (generate a secure random key)
ZITADEL_MASTERKEY=your_secure_master_key_here
# Admin password
ZITADEL_ADMIN_PASSWORD=your_secure_admin_password
# Your domain name
ZITADEL_HOSTNAME=your-domain.com
Generate secure values:
# Generate a secure master key
openssl rand -hex 32
# Generate a secure password
openssl rand -base64 32
Deploy the stack:
# Navigate to the directory containing docker-compose.yml
cd /path/to/zitadel-docker
# Start the services
docker compose up -d
# Follow logs to monitor initialization
docker compose logs -f
If you prefer to use an external PostgreSQL database:
version: '3.8'
services:
zitadel:
image: ghcr.io/zitadel/zitadel:4.10.1
restart: unless-stopped
environment:
ZITADEL_DATABASE_POSTGRES_HOST: your-postgres-host
ZITADEL_DATABASE_POSTGRES_PORT: 5432
ZITADEL_DATABASE_POSTGRES_DATABASE: zitadel
ZITADEL_DATABASE_POSTGRES_USER_USERNAME: zitadel
ZITADEL_DATABASE_POSTGRES_USER_PASSWORD: ${ZITADEL_DB_PASSWORD}
ZITADEL_EXTERNAL_ISSUER: https://${ZITADEL_HOSTNAME}
ZITADEL_TLS_MODE: disabled
ZITADEL_CORS_ALLOWEDORIGINS_0: https://${ZITADEL_HOSTNAME}
ZITADEL_KEYS_CRYPTOGRAPHY_0_KEY: ${ZITADEL_MASTERKEY}
ports:
- "8080:8080"
- "8081:8081"
command: [
"start-from-init",
"--masterkey=${ZITADEL_MASTERKEY}",
"--organization.name=Main Organization",
"--human.username=admin",
"--human.email=admin@${ZITADEL_HOSTNAME}",
"--human.password=${ZITADEL_ADMIN_PASSWORD}"
]
For production use with SSL, configure a reverse proxy like nginx:
server {
listen 443 ssl http2;
server_name your-domain.com;
ssl_certificate /path/to/certificate.crt;
ssl_certificate_key /path/to/private.key;
location / {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Useful Docker Compose commands:
# View logs
docker compose logs -f
# Restart services
docker compose restart
# Update to newer version
docker compose pull
docker compose up -d
# Stop services
docker compose down
# Backup database
docker exec -t zitadel_zitadel-db_1 pg_dump -U zitadel zitadel > backup.sql
https://your-domain.com/ui/consoleDeploying ZITADEL in containers for production? Our consulting covers:
Get expert help: office@linux-server-admin.com | Contact Page