Skip to content

Upgrading MFConsole

How to move to a newer version, back up first, and roll back if something goes wrong. The exact steps differ by deployment type — check which one you're running before you start.

Before you upgrade: take a backup

If Cloud Backup (S3) is configured (Settings → Cloud Backup), the console already backs up its own database and configuration every night. Don't rely on one that might be up to a day stale for an upgrade you're about to do on purpose — trigger a fresh one first from Settings, and confirm it shows verified before continuing.

If Cloud Backup isn't configured yet, set it up before upgrading — see the Backup & Restore how-to. An upgrade without a backup in place has no safety net if it goes wrong.

Schema changes only ever add

MFConsole's database migrations only add columns and tables, never remove or rename them. That's what makes rolling back safe by default: older code simply ignores columns it doesn't know about, so you don't need to restore the database just to undo a code upgrade — only if the upgrade itself somehow behaved badly and you also want to discard data it wrote in between.

Single-host deployments

The default (Free-edition) install runs one console host with no HA components. This is the common case, and it's the simplest to upgrade.

Option A — the in-console "Update Now" button (Settings → System → Updates). This pulls the new image and restarts app/worker/beat automatically — you'll see a brief interruption while they restart, and the page reloads once it's back. This only works on a registry-pull install (the default); it's not available if you built the image from source yourself.

Option B — re-run the installer from the directory you installed into:

cd mfconsole   # the directory install.sh created
./install.sh <new-version>

Never re-extract into a new directory to update

Re-running the "deploy from scratch" steps in a second directory reuses the same database volume (Compose names it after the directory, always mfconsole) while generating a new database password — Postgres only applies a password at volume creation, so the app crash-loops on password authentication failed forever. Always cd into your existing install directory and re-run install.sh there.

Update Now needs Docker

The button works through the watchtower container, which talks to the Docker socket. A Podman host has no /var/run/docker.sock unless the podman-docker package and podman.socket are set up, so there watchtower restarts over and over and Update Now does nothing. Use Option B on Podman.

Rolling back a single-host deployment

Roll back the same way you upgrade: re-run the installer from your existing install directory with the version you want to go back to.

cd mfconsole   # the directory install.sh created
./install.sh <previous-version>

It keeps your .env secrets, pulls that version and recreates the containers. It also writes the version into .env as MFCONSOLE_IMAGE, which is what makes the rollback stick.

Don't roll back with a one-off export

export MFCONSOLE_IMAGE=… followed by compose up -d does roll back, but only for that shell. .env still names the newer version, so the next compose up from anywhere else (a reboot script, someone recreating a container) quietly moves you forward again. If you have already rolled back that way, run ./install.sh <previous-version> as above, or set MFCONSOLE_IMAGE in .env by hand.

Check that it took: the version badge in the console's top bar, and grep ^MFCONSOLE_IMAGE= .env. Per the note above, this is safe without touching the database unless the version you're rolling back from did something non-additive to the schema. Check that release's changelog entry if you're unsure.

Measured on a single host (4 vCPU, 8 GB, Podman, 2026-10-04): an upgrade or a rollback takes about 80 seconds until app, worker and beat are healthy again. The console answers for all but about 15 to 20 seconds of that. Going back from 1.3.0-rc5.5 to 1.2.0-rc5.1, across 7 new tables and 72 new columns, worked with no database changes, and every account, MFA enrollment and setting was still there.

HA (3-node) deployments

There is no automated "Update Now" for an HA cluster yet — each host's app-N/worker/beat needs pulling and recreating individually, leaving the host currently holding the VIP for last so the console only takes one brief interruption instead of two:

# on each non-VIP-holding host first, then the VIP holder last:
export MFCONSOLE_IMAGE=docker.io/mfconsole/kvm-manager:<new-version>
docker compose -f docker-compose.yml -f compose.prod.yml --profile ha pull
docker compose -f docker-compose.yml -f compose.prod.yml --profile ha up -d --no-deps --force-recreate app-N worker beat

(substitute app-1/app-2/app-3 for the host you're on). Verify each host is healthy before moving to the next:

docker compose ps                                              # every service Up/healthy
curl -sk https://127.0.0.1/ -o /dev/null -w '%{http_code}\n'    # 200

Rolling back an HA deployment follows the same per-host procedure with the previous version's MFCONSOLE_IMAGE.

Compute nodes after an upgrade

Some fixes only reach already-enrolled hypervisor nodes after a Repair Worker pass (Hosts → a node → Repair Worker) — the console doesn't yet detect on its own whether a node needs one. Check that release's changelog entry for an explicit call-out, and when in doubt, running Repair Worker after any upgrade is harmless even if it wasn't strictly needed.