Upgrade and Rollback
This guide covers upgrading Control Zero Self-Managed to a new version and rolling back if issues arise.
Pre-Upgrade Checklist
Before starting an upgrade, verify:
- Current installation is healthy (
czctl postflightpasses) - The new version is available (check with
czctl upgrade --check) - The release notes for the new version have been reviewed
- Maintenance window has been communicated to users (if applicable)
Version Upgrade Procedure
1. Run the upgrade
czctl upgrade
The upgrade command automatically:
- Creates a pre-upgrade backup (your rollback point)
- Runs preflight checks for the new version
- Pulls new container images
- Stops current services
- Migrates configuration (preserving your customizations)
- Runs any required database migrations
- Starts services with the new version
- Runs postflight checks
The automatic pre-upgrade backup is saved to /opt/controlzero/backups/ with a timestamp. This backup is used by the restore command if you need to roll back.
Upgrading to a specific version
By default, czctl upgrade upgrades to the latest available version. To upgrade to a specific version:
czctl upgrade --version 1.3.0
Dry run
Preview what the upgrade will do without making changes:
czctl upgrade --dry-run
2. Verify the upgrade
czctl postflight
All checks should pass. Additionally, verify:
- Dashboard is accessible and shows the new version number
- Gateway is accepting and processing requests
- Audit logs are being written
- Policy enforcement is working (test with a known-blocked action)
Rollback Procedure
If the upgrade fails or postflight checks do not pass, restore from the pre-upgrade backup.
1. Restore from backup
czctl restore --from /opt/controlzero/backups/cz-backup-<timestamp>.tar.gz
The restore command will:
- Stop all current services
- Restore configuration and data from the backup
- Revert any database migrations applied during the upgrade
- Start services with the previous version
2. Verify rollback
czctl postflight
All checks should pass. Confirm the dashboard shows the previous version number.
Listing available backups
To see all available backup files:
czctl restore --list
Database Migration Handling
Some upgrades include database schema changes for the audit database or internal state. The upgrade command handles these automatically:
- Forward migrations run during
czctl upgrade. Each migration is applied in order and logged. - Backward migrations are included in the rollback path. When you restore from a pre-upgrade backup, the database schema reverts to the previous version.
- Migration state is tracked in the database. Running
czctl upgradeis idempotent and safe to retry if it fails partway through.
If a migration fails, the upgrade stops and reports the error. Do not manually modify the database schema. Instead, roll back and contact support with the error details.
Zero-Downtime Upgrade Considerations
The standard upgrade procedure involves a brief downtime window (typically 2-5 minutes) while services are stopped and restarted.
For environments that require continuous availability:
Blue-green deployment
- Deploy the new version on a separate host (or separate Docker Compose project on the same host with different ports)
- Run postflight checks on the new deployment
- Switch traffic from the old deployment to the new one (DNS update or load balancer change)
- Decommission the old deployment after confirming the new one is stable
Rolling update within Docker Compose
If you run multiple gateway replicas behind a load balancer:
# Scale up with new version
docker compose up -d --no-deps --scale gateway=2 gateway
# Verify the new container is healthy
docker compose ps
# Remove the old container
docker compose up -d --no-deps --scale gateway=1 gateway
This approach requires a load balancer in front of the gateway service and works best for the gateway and API services. The audit database should be upgraded during a maintenance window.
Upgrade History
Track upgrades in your operational log. Each upgrade is also recorded in the audit database:
curl -s https://localhost:8080/api/v1/system/upgrades \
-H "Authorization: Bearer <admin-token>" | jq
{
"upgrades": [
{
"from_version": "1.2.0",
"to_version": "1.3.0",
"timestamp": "2026-04-03T08:00:00Z",
"status": "success",
"migrations_applied": 2
}
]
}