DocsSelf HostingUpgrades
Back to Self-Hosting

Upgrades & Rollbacks

How releases are versioned, how to upgrade a self-hosted instance safely, and how to roll back if something goes wrong.

1. How Versions Work

OpenPay follows semantic versioning. Every release is a git tag of the form vMAJOR.MINOR.PATCH:

BumpExampleWhen it happens
Majorv1.4.2 → v2.0.0Breaking changes: schema migrations, config/API incompatibility, different deployment layout
Minorv1.4.2 → v1.5.0New features, additive changes (new endpoints, new services, optional config)
Patchv1.4.2 → v1.4.3Bug fixes, security patches, no behavior/API change

A patch is always a drop-in upgrade — pull and restart, no other action. A minor may add features behind optional config. A major can require migrations and manual steps, so the release notes always spell them out before the upgrade instructions.

Before every upgrade: check the release notes (see the Changelog) for the version you're targeting. Major versions in particular may document manual steps the upgrade script cannot automate.

2. What an Upgrade Does

The upgrade tooling is semi-automated: it never touches containers on its own and always keeps a way back. The flow is:

  1. 1
    Pre-flightChecks Docker, the git repo, and that the current stack is healthy.
  2. 2
    BackupSnapshots PostgreSQL (logical dump) plus the postgres/redis/nats named volumes into .backups/.
  3. 3
    CheckoutSwitches the repo to the target release tag and validates the new docker-compose.yml.
  4. 4
    Migration guardRuns Hyperswitch DB migrations automatically — but only when the router image version changed.
  5. 5
    ApplyPulls images and starts the stack.
  6. 6
    VerifyWaits for core services to report healthy.
  7. 7
    Auto-rollbackIf anything fails after the backup point, restores the previous version and data automatically.

You are never left mid-upgrade: the previous version and its data snapshot are recorded in .openpay-state/state before the switch, so a rollback is always one command away.

3. Run an Upgrade

upgrade to the latest release
make upgrade
# or pin a specific version:
make upgrade TARGET=v1.5.0

# the scripts are also callable directly:
./scripts/upgrade.sh            # latest
./scripts/upgrade.sh v1.5.0     # pinned
./scripts/upgrade.sh --dry-run  # print the plan, change nothing

Flags

FlagMeaning
--skip-backupSkip the backup step. Not recommended for major/minor upgrades.
--skip-migrationsDo not run the migration guard, even if the router image changed.
--skip-rollbackNever auto-rollback; on failure the script stops and you roll back manually.
--dry-runPrint the full plan (from/to, backup, migrations, rollback) and exit.

4. Backups

Backups live in .backups/<version>-<timestamp>/ (override the root with OPENPAY_BACKUP_DIR). Each backup contains:

  • postgres-dumpall.sql — a portable logical dump of every database.
  • postgres-data.tgz, redis-data.tgz, nats-data.tgz — exact named-volume snapshots used for restore.
  • MANIFEST.txt — version, timestamp, and file listing.
back up manually, anytime
make backup
./scripts/backup.sh --label before-v2.0.0

Off-box copies: backups are plain files, so copy the directory somewhere outside the server before upgrading — the upgrade will not touch them, but a disk failure would.

5. Rollback

Rollback stops the stack, checks out the previous release, restores the volume snapshots from the pre-upgrade backup, and starts again. Schedule a short maintenance window — the stack is down during the restore.

restore the previous release + data
make rollback
./scripts/rollback.sh                     # uses the recorded state
./scripts/rollback.sh --to v1.4.2 --backup .backups/v1.4.2-20260726-140000 --yes
# flags: --to <version> --backup <dir> --yes (skip confirmation)

If the stack is unhealthy right now (e.g. a failed upgrade left it broken), run the rollback first — it does not require a healthy stack, only the Postgres volume present.

6. Health Checks

The upgrade script gates on service health before and after the switch. Run the check standalone to diagnose a deployment:

verify all core services
./scripts/health-check.sh          # immediate
./scripts/health-check.sh --wait   # wait up to 120s for health

Core services (postgres, redis, nats, hyperswitch, killbill) must be healthy. Profile-gated services (proxy, control center, Tazama, monitoring) warn but never block an upgrade.

Production Deploy

Hardening guide for live environments

Monitoring & Grafana

Dashboards, logs, and alerts