Updating
Move Belune to a new version, safely.
Belune installs are pinned to a version, never :latest, so a routine pull can't move you across a migration boundary. Updating is a deliberate step, and there are two ways to take it: a button on the dashboard, or the update.sh script on the host. Both run the same updater underneath.
The updater takes a backup, fetches the version-matched infra files, moves the image pin, and health-checks the result — with clear rollback instructions if anything goes wrong.
Update from the Dashboard
Belune checks belune.dev once a day for a newer release. When there is one, a dot appears beside the version in the sidebar, admins are notified, and Server → Configuration → Updates shows the release with a link to its notes.
Update now asks for your password — and a second-factor code if you have one enrolled — then takes a full backup and applies the update. Belune restarts itself; the dashboard reconnects on the new version a few seconds later. It runs the exact scripts/update.sh described below, so the dashboard and host paths cannot drift apart.
Some Releases Need the Host
A release that changes docker-compose.yml or a systemd unit can't be applied from inside a container. The Updates card says so instead of offering the button — use update.sh on the host for those, as described next.
Two smaller controls sit on the same card. Check now runs the check immediately rather than waiting for the daily sweep — useful right after you've read release notes. Skip this version silences one release without turning checks off; the next one will still be flagged.
The check is a plain GET of a public manifest and sends nothing about your install. It's on by default; turn it off with the Check automatically switch, or set update_check_enabled to false.
If It Fails
The Updates card reports what went wrong, quoting the updater's own output. Nothing on the host is left half-done: the previous .env and infra files are kept as .env.backup-<version> and .infra-backup-<version>/ in the install directory, and update.sh on the host still works exactly as before.
Reaching 0.1.8
The dashboard updater arrived in 0.1.8, so an install on 0.1.7 or earlier can't use it to get there. That one update is manual — sudo bash scripts/update.sh — and every release after it can be applied from the dashboard.
Update to the Latest Release
From the host, in the install directory:
cd /opt/belune
sudo bash scripts/update.shWith no argument, the script resolves the latest GitHub release and updates to it. If you're already on that version, it says so and exits without touching anything.
Update to a Specific Version
sudo bash scripts/update.sh v0.2.0Pass either form — v0.2.0 or 0.2.0 — the script normalizes it. Useful for pinning to a version you've tested, or for skipping a release you know you want to avoid.
What update.sh Does
In order:
- Resolve the current version (read from
BELUNE_IMAGEin.env) and the target version, and bail out early if they're the same. - Pull the target image first — no point backing up if the new image can't even be fetched.
- Fetch the version-pinned infra set —
docker-compose.yml, the Caddyfile template, BuildKit config,.env.example, the systemd units, andbackup.sh/restore.sh/update.shitself — from that release's git tag, into a staging directory. A failed fetch here aborts before anything on disk changes. - Back up — runs
scripts/backup.sh(Postgres dump + Caddy TLS data) before touching anything live. If the backup fails, it asks before continuing. - Move the pin — rewrites
BELUNE_IMAGEin.envto the target image, keeping a copy of the old.envas.env.backup-<old-version>. - Swap infra files — copies the staged files into place, saving the previous set to
.infra-backup-<old-version>first so a rollback has something to restore. - Reconcile — runs a full
docker compose up -d, not just a restart ofbelune: a changed compose file can touch any service, and only the full reconcile applies that. Compose only recreates what actually changed, so an image-only update still just replaces thebelunecontainer. - Health-gate — polls
/healthzfor up to 90 seconds. If it never comes up, it prints the rollback instructions and exits non-zero rather than leaving you guessing.
Database migrations run automatically when the new belune container boots — this is exactly why step 4 backs up first: migrations are forward-only.
Infra changes during update
Most releases only change the belune image, so the update replaces that
one container while Postgres, Redis, Caddy, and BuildKit keep running
untouched — no interruption to already-routed traffic.
But some releases change docker-compose.yml, the Caddyfile, or BuildKit's
config. Then the updater restarts the whole stack — including Caddy or another
shared service — which can mean a few seconds of interrupted routing for the
dashboard and your apps.
Release notes will call this out explicitly when it applies.
Rolling Back
If the health check fails, or the new version misbehaves once it's up, you can revert to the previous version by running:
cd /opt/belune
sed -i 's|^BELUNE_IMAGE=.*|BELUNE_IMAGE=<previous image>|' .env
cp -a .infra-backup-<old-version>/. .
docker compose up -dThis restores the previous image pin and the exact infra files that shipped with it, then reconciles the stack again. If the new version already ran a migration against your data, restoring the image alone isn't enough — restore the pre-update backup as well; see Configurations.