Updates
Restow ships as Docker images, one build per release, with database migrations applied automatically. There are two ways to update:
- By hand, with
docker compose. This is the default and always works. The next sections start there. - From the web interface, under Settings → Updates. Restow tells you when a newer version exists and, if you opt in to the updater service, installs it for you: a countdown for everyone who is signed in, a database backup first, and an automatic rollback when the new version does not start.
Nothing on this page happens unless you switch it on. A fresh installation does not look for updates, does not contact any server for that purpose, and does not run the updater.
Before every update
Section titled “Before every update”-
Read the release notes of every version between yours and the new one, especially Breaking changes and Update effort. Each release states its update effort (see the three kinds below), with the expected downtime and how to roll back.
-
Back up the database. It holds metadata, the job queue and the audit log. Backed-up content lives in the chunk store and is not touched by an update.
Terminal window docker compose exec -T postgres pg_dump -U restow -Fc restow > restow-$(date +%F).dumpThe updater does this itself (see below).
-
Check that
RESTOW_MASTER_KEYis backed up offline. An update never changes it, but without it no backup can be read. See Backing up Restow itself.
The three kinds of update
Section titled “The three kinds of update”1. Configuration only
Section titled “1. Configuration only”Only values in .env change (a new optional variable, a changed setting).
docker compose up -dup -d recreates the containers whose configuration changed. docker compose restart is not an update: it restarts the running containers with their old image and their old environment, and never picks up a new image or a changed .env.
2. New image, with automatic migrations
Section titled “2. New image, with automatic migrations”The usual case. Restow applies database migrations itself: the api container runs them as the database owner (DATABASE_MIGRATION_URL) before it serves any request, and refuses to start if one fails. The release notes say whether there are migrations and roughly how long they take.
Release stack (the published images, deploy/release/docker-compose.yml). Name the version in .env and pull:
RESTOW_IMAGE=ghcr.io/restow-backup/restow:X.Y.ZRESTOW_WEB_IMAGE=ghcr.io/restow-backup/restow-web:X.Y.Zdocker compose pulldocker compose up -dIf the updater ever wrote RESTOW_IMAGE and RESTOW_WEB_IMAGE into .env, those two lines decide which images the services run. Change them, or remove them to go back to building from a source checkout.
Source checkout (the repository’s own docker-compose.yml, which builds from source):
git fetch --tagsgit checkout vX.Y.Zdocker compose up -d --buildThen watch the migrations and the start:
docker compose logs -f apiThe log shows restow: applying database migrations, then restow: starting role 'api'.
3. Manual steps
Section titled “3. Manual steps”A release that needs anything beyond the commands above (a new required variable, a changed Compose file, a one-off command) lists every step, in order, under Update effort and Breaking changes. Do them in that order, before or after docker compose up -d exactly as written. The updater cannot know about such steps: it applies the image and restarts the services. Read the notes first, and update by hand when they list anything else.
After the update
Section titled “After the update”curl -fsS http://127.0.0.1:3000/healthzcurl -fsS http://127.0.0.1:3000/readyzdocker compose psThen check the version in the sidebar footer of the web interface, and run Verify now for one tenant: a restore check that passes proves the new version can still read what the old one wrote.
Settings → Updates
Section titled “Settings → Updates”The tab is visible to every provider administrator. It shows the running version, the release channel, the newest version with its tag and release date, a link to the release notes (and the notes themselves, rendered safely and collapsed), the status of the last check, and whether an update is available.
Who may change it. Changing any setting, Check now, announcing, cancelling and dismissing an update need the Owner role of the provider team. The administrator created by the setup wizard is an owner. Everyone else sees the status only. See Team and roles.
Turning the check on
Section titled “Turning the check on”The check is off by default. When an owner turns it on (Check for updates once a day), Restow reads the release list of the update source once a day and whenever you press Check now. After a failed check it tries again after an hour at the earliest.
What is read. Only the release list of the source. No request carries any data about your installation, and the result is cached. As with any web request, the source sees the address your server connects from. If a check fails, the tab says why and keeps showing the last good result:
| Reason | Meaning |
|---|---|
| Rate limited | The source refused more requests for now. The tab shows when it lifts. |
| Token rejected | The access token is wrong, expired or revoked. |
| Not found | The repository does not exist, or it is private and no token is stored. |
| Access forbidden | The token may not read the releases of that repository. |
| Source error, no answer | The source answered with a server error, timed out or could not be reached. |
| Not a release list | The address answered, but not with releases. |
| No release published | The source has no release for this channel yet. |
| Redirect refused | The source redirected to another host. Restow does not follow it, enter the final address of the repository instead. |
Source, channel and token
Section titled “Source, channel and token”- Source. The default is the public releases of
https://github.com/restow-backup/restow. You can point it at your own repository: a GitHub repository, or a Forgejo or Gitea repository (their releases API is compatible), for examplehttps://git.example.com/acme/restow. Onlyhttpsaddresses are accepted, without credentials in the URL, because an access token travels with the request. - Channel. Stable offers final releases only. Beta also offers pre-releases such as
0.3.0-rc.1. Versions are compared as Semantic Versions, so a pre-release precedes its release. A release such as 0.1.0 is an ordinary release that the stable channel offers as well. - Access token. For a private repository, store a read-only access token. It is kept encrypted in the database, sent only as an
Authorizationheader to the source’s own host, never shown again (the tab only says whether one is stored, and lets you replace or remove it), and never written to a log or the audit log. If you point the source at another host, the stored token is removed instead of following you there. A private repository is built from source (see below).
RESTOW_UPDATE_CHECK_URL and its precedence
Section titled “RESTOW_UPDATE_CHECK_URL and its precedence”RESTOW_UPDATE_CHECK_URL is an environment override that predates the tab and keeps working. From strongest to weakest:
RESTOW_UPDATE_CHECK_URL, when set to anhttpsaddress. The check is on, the source is that address, and the tab shows it read-only. No stored token is sent to it. Accepted: a GitHubhttps://api.github.com/repos/<owner>/<repo>/releases(or.../releases/latest), a Forgejo or Gitea.../api/v1/repos/<owner>/<repo>/releases, or any otherhttpsaddress that returns the same JSON. The channel can still be changed in the tab.- The settings of the tab (switch, source, channel, token).
- The defaults: off, the public project releases, stable.
The “Update available” alert
Section titled “The “Update available” alert”Once per new version, Restow raises an Update available alert: an entry in the notification bell of the provider administrators, and the alert rules under Alerts & reports that list the event Update available (e-mail, webhook) in every tenant. Only provider administrators can create a rule for this event, a tenant’s own administrators are not told about your updates. The same version never raises it twice. See Alerts and reports.
In the integration API
Section titled “In the integration API”GET /api/v1/status carries a version object, so an RMM can flag installations that have fallen behind: running, latest, updateAvailable (null when not known), releaseUrl, updateCheck (disabled, pending, ok or failed), checkedAt, channel, latestTag, publishedAt, checkError (the reason code of a failed check) and maintenance (an update that is announced or running: phase, targetVersion, startsAt). Fields have only ever been added, never renamed or removed. See Integration API.
The opt-in updater
Section titled “The opt-in updater”The Updates tab shows Install update only when the updater service is running. Without it, the tab shows the manual steps of this page instead.
Enabling it
Section titled “Enabling it”-
Set the absolute path of the directory that holds
docker-compose.ymland.envin.env. The updater mounts it at the same path, so relative paths in the Compose file resolve as they do on the host.Terminal window RESTOW_PROJECT_DIR=/opt/restow -
Start the updater next to the rest of the stack:
Terminal window docker compose --profile updater up -d -
Open Settings → Updates. The install card says whether the updater is ready or what blocks it: Docker not reachable, the Docker command line image not pulled yet, Compose file not found, the project directory not matching
RESTOW_PROJECT_DIR,.envnot writable, or not enough free space. The first start pulls the Docker command line image (see below), which needs access to Docker Hub. Until then the card says it is preparing.
To remove it again: docker compose --profile updater rm -sf updater. The updater’s volume (restow-updater, holding the database dumps) stays until you remove it with docker volume rm.
The updater is not updated by an update. It keeps running the version it started with. After an update, recreate it so it matches: docker compose --profile updater up -d updater. The tab reminds you when its version differs from the running one.
Two modes
Section titled “Two modes”Restow picks the mode from the update source and shows it in the tab:
- Image (the default source, the project’s public releases). Pulls
ghcr.io/restow-backup/restow:<version>for the application andghcr.io/restow-backup/restow-web:<version>for the web edge. It verifies the pulled images against the digests the release publishes in its notes (the project’s releases do), writes the two image references into.env(RESTOW_IMAGE,RESTOW_WEB_IMAGE) and recreates the services. If a release has no web image, the web edge stays as it is and the run says so. A release that publishes no digests is still installable, and the run records that the image was not verified. The updater checks these digests, it does not verify the cosign signature: see Verifying a release if you want that step. - Source (any other repository, for example your own Forgejo). Downloads the tagged archive of the repository, with the stored token in an
Authorizationheader (never in a URL, a command line or a log), builds the application and web images locally withdocker build, then recreates the services the same way. This takes longer than a download.
What an update does
Section titled “What an update does”The owner picks the version and a lead time (immediately, 1, 5, 15, 30 minutes or 1 hour) and confirms. From then on every signed-in person, not only administrators, sees a banner with a live countdown, and a notice when it is announced. The owner can cancel until the update starts. At the start, everyone sees a full-screen notice with the steps and the progress.
- Prepare. Checks that Docker answers, the Compose file is there,
.envis writable, there is free space, the target is newer than the running version, and that the Compose file takes the image of api, worker, scheduler and web edge fromRESTOW_IMAGEandRESTOW_WEB_IMAGE(so a mixed-version installation cannot result). - Download or build. Nothing is stopped yet: a failure here changes nothing.
- Database backup.
pg_dump -Fcof the database into the updater’s volume, checked for readability. The last three are kept, plus the one a run that needs attention depends on. - Stop worker and scheduler. Jobs in the queue resume after the restart.
- Start the new version. The api is recreated with the new image and applies its database migrations as it starts.
- Health check. Waits until the api reports ready and the new version (it gives up at once when the api container keeps restarting), then starts worker and scheduler, then recreates the web edge last.
- Done.
While the api restarts, the edge answers browsers with a static maintenance page (in the browser’s language, light or dark) and answers API calls with a 503. The web interface treats that as “the server is restarting” and reloads by itself once the new version answers.
State lives in the updater’s volume, so it survives the api restarting. The result of every run also appears in the notification bell.
When something goes wrong
Section titled “When something goes wrong”The updater never guesses. It ends a failed run in exactly one of three states:
- Unchanged. It failed before anything was stopped (Docker unreachable, the image could not be pulled or did not match its digest, the build failed, the backup failed). The old version never stopped.
- Rolled back. The new version did not come up and the database migrations had not run (the updater stops the new api first, then compares the number of applied migrations with the one before the update). The previous images are running again,
.envis restored byte for byte, and the tab says which step failed and why. - Needs attention. The new api failed after its migrations ran. Migrations cannot be undone, so the updater does not start the old version on top of a migrated database. It stops api, worker and scheduler, keeps the database dump and tells you what to do. The web edge keeps showing the maintenance page.
If the updater itself is restarted or killed in the middle of a run, the run is recorded as interrupted (unchanged when it had not stopped anything yet, otherwise needs attention) and nothing is started on its own.
For needs attention, restore the dump taken before the update. The tab shows the exact file name and the previous image references:
# copy the dump out of the updater's volumedocker compose --profile updater cp updater:/state/dumps/<file> ./<file># stop the application and restoredocker compose stop api worker schedulerdocker compose exec -T postgres pg_restore -U restow -d restow --clean --if-exists < <file># put the previous images back into .env (RESTOW_IMAGE, RESTOW_WEB_IMAGE), thendocker compose up -dBackups made after the update are in the chunk store but not in the restored database, so run a backup after the rollback. Then report the failure with the log tail the tab shows. Dismiss clears a finished run from the page. Use it only after you have restored the installation, because the recovery commands disappear with it. The run stays in the audit log.
Audit events
Section titled “Audit events”Every step that matters is written to the audit log: update.check, update.settings.updated, update.scheduled, update.cancelled, update.started, update.succeeded, update.failed and update.acknowledged (dismissing a finished run). The updater has no database access of its own, so it keeps a journal and the api writes it to the audit log afterwards, in order and once, even when the api was replaced in between. See Audit log.
Settings of the updater
Section titled “Settings of the updater”The Compose service sets what it needs. These variables are read by the updater only (ROLE=updater):
| Variable | Default | Meaning |
|---|---|---|
RESTOW_UPDATER_PROJECT_DIR |
required, set from RESTOW_PROJECT_DIR |
Absolute host path of the Compose project, mounted at the same path. |
RESTOW_UPDATER_IMAGE_REPOSITORY |
ghcr.io/restow-backup/restow |
Application image repository for image mode. |
RESTOW_UPDATER_WEB_IMAGE_REPOSITORY |
ghcr.io/restow-backup/restow-web |
Web image repository for image mode. |
RESTOW_UPDATER_HEALTH_TIMEOUT_SECONDS |
600 |
How long to wait for the new api (migrations can take a while). |
RESTOW_UPDATER_MIN_FREE_MB |
1024 |
Free space required in the updater’s volume. |
RESTOW_UPDATER_CLI_IMAGE |
docker:27-cli |
Image used to run docker and docker compose (see below). |
RESTOW_UPDATER_SOURCE_HOSTS |
empty (every https host) | Optional comma-separated allowlist of hosts a source archive may be downloaded from. |
The published image contains no Docker command line. The updater therefore runs each docker and docker compose command in a short-lived helper container of RESTOW_UPDATER_CLI_IMAGE (by default from Docker Hub, pulled in the background when the updater starts; the updater cannot install anything before that and says so), through the mounted socket, without network access and with the project directory and the updater’s state volume mounted. If a docker binary is present in the updater’s own image, it is used directly instead. The helper containers carry no registry credentials: the images of the project’s public releases need none, and a private registry is not supported in this mode. The api reaches the updater at RESTOW_UPDATER_URL (default http://updater:8090). Nothing answers there unless the updater profile runs.
Rolling back by hand
Section titled “Rolling back by hand”-
No migrations in the release: check out (or pull) the previous version and run
docker compose up -dagain. The updater does this by itself when a new version does not start. -
With migrations: migrations are not reversible. Stop the stack, restore the database dump taken before the update, then start the previous version:
Terminal window docker compose stop api worker schedulerdocker compose exec -T postgres pg_restore -U restow -d restow --clean --if-exists < restow-YYYY-MM-DD.dumpgit checkout vPREVIOUSdocker compose up -d --buildWith the release stack, put the previous
RESTOW_IMAGEandRESTOW_WEB_IMAGEback into.envinstead of thegit checkout, and usedocker compose up -d. Backups taken after the update are in the chunk store but not in the restored database, so run a backup after the rollback.
Versions and channels
Section titled “Versions and channels”Restow uses Semantic Versioning. Before 1.0.0, a minor version (0.2.0) adds features and may carry migrations. A patch version (0.1.1) fixes problems and carries migrations only when a fix needs one. Tags are vMAJOR.MINOR.PATCH, and pre-releases are marked -rc.N. The stable channel of the update check offers releases only, the beta channel also offers the pre-releases. The Docker tags of a release are a separate matter, see Verifying a release.