Belune

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.sh

With 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.0

Pass 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:

  1. Resolve the current version (read from BELUNE_IMAGE in .env) and the target version, and bail out early if they're the same.
  2. Pull the target image first — no point backing up if the new image can't even be fetched.
  3. Fetch the version-pinned infra set — docker-compose.yml, the Caddyfile template, BuildKit config, .env.example, the systemd units, and backup.sh/restore.sh/update.sh itself — from that release's git tag, into a staging directory. A failed fetch here aborts before anything on disk changes.
  4. Back up — runs scripts/backup.sh (Postgres dump + Caddy TLS data) before touching anything live. If the backup fails, it asks before continuing.
  5. Move the pin — rewrites BELUNE_IMAGE in .env to the target image, keeping a copy of the old .env as .env.backup-<old-version>.
  6. 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.
  7. Reconcile — runs a full docker compose up -d, not just a restart of belune: 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 the belune container.
  8. Health-gate — polls /healthz for 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 -d

This 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.

On this page