Zitadel Authentication Server
Zitadel Authentication Server
Section titled “Zitadel Authentication Server”This directory contains the configuration for the Zitadel authentication server used by the Ariane project.
🎯 User-Friendly Error Handling - Added comprehensive error translation and better UX at 2025-09-16 18:00 UTC
Overview
Section titled “Overview”Zitadel provides OIDC/OAuth2 authentication services for:
- User authentication and authorization
- Integration with Cloudflare Access
- Session management
- Multi-factor authentication (when enabled)
User-Friendly Error Handling ✨
Section titled “User-Friendly Error Handling ✨”This deployment includes enhanced error handling to translate cryptic Zitadel error codes into user-friendly messages:
Error Code Translations
Section titled “Error Code Translations”COMMAND-2M0fs→ “No changes detected - please modify at least one field”COMMAND-J8dsk→ “User initialization required - complete setup process”QUERY-d3fas→ “Database connection issue - try again in a moment”
Features
Section titled “Features”- Custom Error Pages: Beautiful, actionable error messages instead of raw HTTP codes
- Contextual Help: Specific suggestions for each error type
- Technical Details: Expandable technical information for debugging
- Smart Error Detection: Automatic pattern matching and translation
error-handler.js- JavaScript error translation librarycustom-error-page.html- Styled error page templateCaddyfile- Enhanced with error interception and custom responses
docker-compose.yml- Docker Compose configuration for Zitadel, PostgreSQL, and Caddyzitadel.yaml- Zitadel server configurationCaddyfile- Caddy reverse proxy configuration with SSL and error handling.env.example- Environment variables template
Current Deployment
Section titled “Current Deployment”Production URL: https://auth.wenzelarifiandi.com
Services:
- Zitadel: Authentication server (port 8080, proxied through Caddy)
- PostgreSQL: Database backend
- Caddy: Reverse proxy with automatic SSL (ZeroSSL) and error translation
Quick Start
Section titled “Quick Start”-
Copy environment template:
Terminal window cp .env.example .env -
Update environment variables in
.env -
Start services:
Terminal window docker-compose up -d -
Initialize Zitadel (first time only):
Terminal window # Initialize databasedocker-compose exec zitadel zitadel init databasedocker-compose exec zitadel zitadel init userdocker-compose exec zitadel zitadel init grant# Setup first instance with projectionsdocker-compose exec zitadel zitadel setup --for-mirror --init-projections --masterkey "YOUR_MASTER_KEY"
Configuration
Section titled “Configuration”Master Key
Section titled “Master Key”The master key is used for encryption. Set it in your environment:
ZITADEL_MASTERKEY="MasterkeyNeedsToHave32Characters"External Domain
Section titled “External Domain”Update the external domain in both docker-compose.yml and zitadel.yaml:
ZITADEL_EXTERNALDOMAIN=auth.yourdomain.comSSL Certificates
Section titled “SSL Certificates”Currently configured to use ZeroSSL via Caddy. To switch providers, update the Caddyfile.
Admin Access
Section titled “Admin Access”Console URL: https://auth.wenzelarifiandi.com/ui/console
First-time Setup:
- Use the admin credentials that were configured during initial setup
- Immediately change the default password after first login
- Enable MFA for additional security
- Create additional admin users and disable the default account
Security Note: Default credentials should never be stored in version control or documentation.
Cloudflare Access Integration
Section titled “Cloudflare Access Integration”To integrate with Cloudflare Access:
-
Create OIDC Application in Zitadel:
- Go to Projects → Create Project
- Add Application → OIDC → Confidential
- Set redirect URI to:
https://yourteam.cloudflareaccess.com/cdn-cgi/access/callback
-
Configure Cloudflare Access:
- Discovery URL:
https://auth.wenzelarifiandi.com/.well-known/openid-configuration - Client ID and Secret from Zitadel application
- Discovery URL:
Backup and Recovery
Section titled “Backup and Recovery”Database Backup
Section titled “Database Backup”docker-compose exec db pg_dump -U postgres zitadel > backup.sqlConfiguration Backup
Section titled “Configuration Backup”All configuration files are version controlled in this repository.
Full Restore
Section titled “Full Restore”- Deploy using docker-compose
- Restore database:
docker-compose exec -T db psql -U postgres zitadel < backup.sql - Restart services:
docker-compose restart
Troubleshooting
Section titled “Troubleshooting”Common Issues
Section titled “Common Issues”-
Email Verification Required
- Admin users may need email verification
- Manually verify in database or configure SMTP
-
WebAuthn/Security Key Errors
- Check login policy settings
- Disable mandatory MFA if not needed
-
Profile Update Errors
- “Profile not changed”: You’re trying to update with the same data - change at least one field
- “User not initialized”: Complete the account setup process or verify email
- Rebuild projections if needed:
docker-compose exec zitadel zitadel setup --init-projections
# View all logsdocker-compose logs
# View Zitadel logs onlydocker-compose logs zitadel
# Follow logsdocker-compose logs -f zitadel
# View error handling logsdocker-compose exec caddy cat /var/log/caddy/zitadel-errors.logSecurity Notes
Section titled “Security Notes”- Change default passwords immediately
- Configure proper SMTP for email verification
- Set up proper backups
- Monitor logs for security events
- Keep Zitadel updated to latest stable version
Version
Section titled “Version”Current Zitadel version: v2.65.1
Critical Runtime Remediation (Docker Compose / Healthcheck / SMTP)
Section titled “Critical Runtime Remediation (Docker Compose / Healthcheck / SMTP)”Recent incident summary (Sept 2025):
zitadelcontainer reportedunhealthydue to a healthcheck usingwget, which is not present in the official image.- Attempts to restart the stack began failing with
KeyError: 'ContainerConfig'– an underlying Docker / docker-compose runtime metadata issue rather than an application misconfiguration. - SMTP block absent in
zitadel.yamlled toErrors.SMTPConfig.NotFoundnoise in logs (non-fatal for core auth unless email flows needed).
Fast Recovery Flow
Section titled “Fast Recovery Flow”# 0. SSH inssh -i ~/.ssh/oracle_key_correct ubuntu@<SERVER_IP>
cd ~/zitadel # directory containing docker-compose.yml
# 1. Collect diagnostics (non-destructive)bash scripts/triage.sh
# 2. Render/validate composedocker compose config
# 3. Stop stack (ignore errors)docker compose down --remove-orphans || true
# 4. Manually remove lingering containers if compose down fails earlydocker ps -a --format '{{.ID}} {{.Names}}' | grep -E 'zitadel|caddy|postgres|db' | awk '{print $1}' | xargs -r docker rm -f
# 5. OPTIONAL: prune unused (SAFE-ish but global)docker system prune -f
# 6. (If still KeyError) restart Docker enginesudo systemctl restart docker
# 7. Bring up only Postgres firstdocker compose up -d dbdocker compose logs -f db | grep -m1 'database system is ready'
# 8. Start Zitadel (after editing healthcheck if needed)docker compose up -d zitadeldocker compose logs --tail=120 zitadel
# 9. Start Caddydocker compose up -d caddyHealthcheck Fix Options
Section titled “Healthcheck Fix Options”Remove existing healthcheck: block OR replace with one that uses a built-in tool. Easiest is removal (Docker will still show running state). If you prefer a check:
healthcheck: test: ["CMD-SHELL", "nc -z 127.0.0.1 8080 || exit 1"] interval: 30s timeout: 5s retries: 5 start_period: 60sThis uses nc (busybox netcat is in most base images). If absent, simply delete the healthcheck.
SMTP Configuration
Section titled “SMTP Configuration”Add minimal block to zitadel.yaml (do NOT commit secrets; use env for password):
DefaultInstance: SMTPConfiguration: Host: smtp.resend.com:465 User: resend Password: ${ZITADEL_SMTP_PASSWORD} From: hello@notify.wenzelarifiandi.com TLS: trueCompose environment (sanitize in real deployment):
services: zitadel: environment: - ZITADEL_MASTERKEY=MasterkeyNeedsToHave32Characters - ZITADEL_SMTP_PASSWORD=REDACTED_SECRETAfter restart, verify:
docker compose logs zitadel | grep -i smtp || echo 'SMTP lines not found'If still missing: ensure the zitadel.yaml path (/config/zitadel.yaml) matches the mount and that the block indentation is correct.
Detecting Compose Binary Issues
Section titled “Detecting Compose Binary Issues”docker compose versionwhich docker-compose || true # legacy symlink?docker-compose version || trueIf both binaries exist and conflict, remove legacy:
sudo rm -f /usr/local/bin/docker-composesudo apt-get update && sudo apt-get install --reinstall docker-compose-pluginLast Resort (Hard Reset Docker Engine)
Section titled “Last Resort (Hard Reset Docker Engine)”Only if metadata corruption persists and data can be lost / already backed up:
sudo systemctl stop dockersudo tar -C /var/lib -czf ~/docker-lib-backup-$(date +%s).tgz dockersudo mv /var/lib/docker /var/lib/docker.broken.$(date +%s)sudo systemctl start dockerdocker compose pulldocker compose up -dPost-Fix Validation Checklist
Section titled “Post-Fix Validation Checklist”-
docker compose psshows all three servicesUp(no(health: starting)loop) -
docker compose logs --tail=50 zitadelcontains startup without repeating crash loops - Access
https://auth.wenzelarifiandi.com/.well-known/openid-configurationreturns JSON - (If SMTP configured) No
Errors.SMTPConfig.NotFoundlines in recent logs - Admin console reachable:
/ui/console - Optional: Send a test email (trigger password reset) and confirm delivery
Automation Aid
Section titled “Automation Aid”Use the added script:
cd zitadelbash scripts/triage.shls -1 triage-* # choose newest folderAttach the produced tarball for further analysis if escalation is needed.
Remote SSH Helper
Section titled “Remote SSH Helper”From repo root (local workstation) you can launch an interactive remediation session with pre-filled guidance:
./scripts/zitadel-remote-session.sh # uses ubuntu@auth.wenzelarifiandi.com and key at ~/.ssh/oracle_key_correct
# Override target or keySSH_KEY_PATH=~/.ssh/alternative_key \ ./scripts/zitadel-remote-session.sh otheruser@yourhost.example.com path/to/zitadelInside the remote shell it prints suggested next commands (triage, healthcheck removal, restart sequence).
Advanced: Minimal Patch to Remove Healthcheck
Section titled “Advanced: Minimal Patch to Remove Healthcheck”Diff concept (do manually if editing live server):
services: zitadel: image: ghcr.io/zitadel/zitadel:v2.65.1@@ healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/debug/healthz"] interval: 30s timeout: 10s retries: 3 start_period: 60sApply, then:
docker compose up -d --force-recreate zitadelFuture Hardening Ideas
Section titled “Future Hardening Ideas”- Build a tiny sidecar health probe (alpine + curl) if deeper layer 7 checks required.
- Add watchtower or CI pipeline step for controlled image upgrades.
- Implement automated nightly
pg_dumpto off-host storage. - Add structured log shipping (e.g., Vector + OpenSearch) for audit trails.
Troubleshooting & Status Checking
Section titled “Troubleshooting & Status Checking”Quick Status Check
Section titled “Quick Status Check”Use the comprehensive status checker from the repository root:
./scripts/deployment-status.shThis script will:
- ✅ Check service health and endpoints
- 📍 Show current deployment version
- 💡 Provide specific troubleshooting guidance
- 🛠️ Suggest immediate actions based on the issue
Common Issues & Solutions
Section titled “Common Issues & Solutions”Service Not Responding (HTTP 000/timeout)
Section titled “Service Not Responding (HTTP 000/timeout)”Possible Causes:
- Deployment in progress (wait 2-3 minutes)
- Oracle Cloud instance issues
- Docker services failed to start
- Network connectivity problems
Quick Fixes:
- Check GitHub Actions for failed deployments
- Wait a few minutes if deployment just triggered
- For immediate access: SSH to server and check
docker-compose ps
Browser Shows Old Error Messages
Section titled “Browser Shows Old Error Messages”After a successful deployment fix:
- Hard refresh: Ctrl+Shift+R (Windows) / Cmd+Shift+R (Mac)
- Chrome/Edge: DevTools (F12) → right-click refresh → “Empty Cache and Hard Reload”
- Try incognito/private browsing window
- Clear browser cache for auth.wenzelarifiandi.com
Version Verification
Section titled “Version Verification”Check what’s deployed on server:
ssh ubuntu@auth.wenzelarifiandi.com 'cat /home/ubuntu/zitadel/.deployment_state'Compare with current repository:
git rev-parse HEADForce deployment if out of sync:
gh workflow run "Deploy Zitadel to Oracle Cloud" --field force=trueManual Server Commands
Section titled “Manual Server Commands”Check service status:
ssh ubuntu@auth.wenzelarifiandi.com 'cd zitadel && docker-compose ps'View recent logs:
ssh ubuntu@auth.wenzelarifiandi.com 'cd zitadel && docker-compose logs --tail=50'Restart all services:
ssh ubuntu@auth.wenzelarifiandi.com 'cd zitadel && docker-compose restart'Check Caddy logs specifically:
ssh ubuntu@auth.wenzelarifiandi.com 'cd zitadel && docker-compose logs caddy --tail=20'Support
Section titled “Support”For issues related to:
- Zitadel configuration: Check Zitadel Documentation
- Cloudflare integration: See
ops/zitadel-cloudflare-access-troubleshooting.md - Deployment issues: Use
./scripts/deployment-status.shand check GitHub Actions - Error handling: Check
error-handler.jsfor supported error codes - Initializing users properly (avoiding DB flips): See
../ops/zitadel-user-initialization.md