Repository navigation
Restow 0.3.5
Restow 0.3.5. Released 2026-10-14, channel beta.
Beta release. Run it alongside your existing backups, not as your only one, until
you have verified restores against your own data.
Summary
Restow 0.3.5 makes long first backups of large mailboxes finish instead of running out
of retries, says plainly how big a Proxmox VE guest's backups are and when a container
backup is incomplete, warns when a machine job leaves out the folders where Linux
services keep their data, and adds a restore operator role. It also stores the backup
index (which items each backup contains) as item versions instead of a full copy per
backup, which shrinks the database of large installations by an order of magnitude, and
gives sign-in a database role of its own. One database migration, run automatically at
start.
Breaking Changes
None. A Compose file you keep yourself should get stop_grace_period: 60s on the
worker service (see Changed); without it, Docker stops the worker after 10 seconds as
before.
The first start after the upgrade converts the existing backup index in the background
(see Changed). Backups, browsing and restores keep working meanwhile. Once the worker log
says manifest index conversion finished, restart the api once
(cd /opt/restow && docker compose restart api): only then is the space of the old
index handed back to the file system.
Added
- A restore operator role per tenant: sees and restores every backup of the tenant,
without administering it (jobs, storage, users). Creating a user or an invitation now
always needs a role to be chosen; there is no preselected one any more. - Proxmox VE › VMs & containers and the inventory: a Backup column with what the
newest restore point contains and what its run added ("9.4 GB in the backup, +2.5 MB
new"), with the first backup on hover. The former "Size" column is now called "Disk". - Proxmox VE guest page: restore points show their type (first backup, incremental, full
read), what they contain and what they added. A container backup that restic could not
read completely shows as "Last backup incomplete" / "Succeeded with gaps" with the
number of unreadable items, and counts as "Incomplete" in the inventory. - Machine jobs and File restore (Linux): a notice names the usual data folders (
/opt,
/srv,/var/lib,/home, …) that the job's paths leave out, with a button to add
them.
Changed
- Installation: "Default repository" and "Network shares" are one page again. Old links
to the network shares open it. - A backup that is interrupted by its time limit (23 hours) or by a worker restart, after
it saved a checkpoint, continues without using up one of its retries, for up to 21
days after it first started. The run view shows such an interruption as information,
not as an error. - Microsoft 365: a Graph request that gets no answer within 5 minutes is retried, instead
of hanging until the job's time limit. Requests and throttling waits end with the job. - The worker gets 60 seconds to save checkpoints when it stops (
stop_grace_periodin
the Compose files, drain time 50 seconds,WORKER_SHUTDOWN_TIMEOUT_MS). - Proxmox VE: "Back up now" and restore say that the node starts the task at its next
check-in, a second click says a backup is already waiting, and the pages refresh every
5 seconds while a guest waits for its node or backs up. - Backup index: a backup no longer copies every item of a mailbox or OneDrive into the
database. Restow keeps one row per version of an item, so an unchanged item costs
nothing on later backups. On an installation with 14 million index rows (25 GB), the
index needs about 0.5 to 1.5 GB afterwards. The worker converts existing backups one at
a time after the upgrade. - Database roles: sign-in (sessions, passwords, passkeys, two-factor secrets) runs on a
third database role of its own, created and kept up to date by the migration. The
application role keeps to tenant data under Row Level Security and may only add jobs
to the queue. No.envchange is needed;DATABASE_AUTH_URLis optional for
installations that manage their database roles themselves (see SECURITY.md). - File restore: the file list has a fixed height and scrolls inside, so the path bar and
the actions stay in place.
Fixed
- A first backup of a large mailbox that needed several days ended as failed after five
interruptions, and the next run started over. - "The run was interrupted" said nothing was lost also after the last attempt, when the
checkpoint is discarded. - Archive: header, storage-protection notice, search and results had no space between
them. - The database of installations with many item backups (Microsoft 365) grew by the full
item count with every backup, until the disk ran full. - After an update, the maintenance page kept saying "Restow was updated, this page reloads
now" whenever the application was down later (for example after a reboot with a full
disk). After 10 minutes it now says the server is temporarily unavailable. - The browser console warned on every page load that three preloaded fonts were not used
within the first seconds. The fonts are no longer preloaded. - Forms reported no error for a missing field inside a list (for example the role of a
new user in the setup wizard).
Security
- Database roles (hardening, no known exploit): up to 0.3.4 the application's database
role could also read and write the tables outside Row Level Security, among them
better-auth's sign-in tables, the installation settings, the license and the job
queue. A flaw in tenant-scoped query code could therefore have reached data beyond
its tenant. 0.3.5 moves sign-in to a role of its own and leaves the application role
only tenant data and adding jobs. Affected: up to 0.3.4. Nothing to do beyond
updating; the migration changes the grants of an existing installation.
Upgrade Notes
New image and one database migration (0033), which only creates a table and drops two
indexes and takes seconds on any database size. After the start, the worker converts
the existing backup index in the background, one backup at a time (about 19,000 index
rows per second in testing, so roughly 15 minutes for 14 million rows); backups,
browsing and restores keep working meanwhile. When the worker log says
manifest index conversion finished, restart the api once
(docker compose restart api) to give the old table's space back.
- Free space: the conversion writes the new index before the old one is released, and
the updater writes a database dump before it updates. On a nearly full disk, free
space first (see docs/UPDATING.md). - No new required environment variables.
DATABASE_AUTH_URLis optional. - Compose files kept by hand: add
stop_grace_period: 60sto theworkerservice. - Rollback: the migration is not reversible; go back to 0.3.4 only with the database
dump taken before the update.
Known Issues
- The background conversion of the backup index was tested on generated histories, not
yet on a production database of 25 GB; how long it takes there is an estimate. - The known issues of 0.3.4 still apply.
Verification
Before the tag, on 2026-10-14, on the release branch (main plus #71 and #72): CI green
(lint, typecheck, build, Docker images, Go agent, licenses, secret scan, and the unit
and Postgres suites on Postgres 16 with password authentication). Locally on the
combined branch: packages/db 171, packages/core 1981, apps/worker 444,
apps/scheduler 65, apps/api 3250 (1 skipped), apps/web 3820, ee/api 243. The release
smoke runs in the release pipeline; no Microsoft 365 tenant was used before the tag.
Release pipeline, 2026-10-14:
| Check | Result | Duration |
|---|---|---|
| 1. Install: images, compose up, migrations (new install and upgrade) | PASS | 72s |
| 2. Health endpoints, worker and scheduler registered | PASS | 0s |
| 3. Passkey sign-in E2E with a virtual authenticator, tenant creation, i18n de/en | PASS | 116s |
| 4. Microsoft 365 backup and restore against the dev tenant | SKIPPED | 0s |
| 5. IMAP backup and restore against Dovecot, hash comparison | PASS | 8s |
| 6. Journal receipt, chain verification, export | PASS | 3s |
| 7. Standalone restore with restow-restore from the storage of check 5 | PASS | 23s |
| 8. Storage targets: S3 (Garage), local path, mounted directory | PASS | 20s |
| 9. Image scan (Trivy) and dependency audit (pnpm audit) | PASS | 15s |
| 10. Endpoint backup: the agent enrolls, backs up a folder, restores it | PASS | 11s |
| 11. Mail import (folder and upload) and export (EML ZIP, MBOX), compared by hash | PASS | 8s |
10 of 11 checks passed in full, 0 partly, 1 skipped, 0 failed. The full report, including the reason for every skipped or partial check, is attached to the release as smoke-report.md.
The Community images were smoke-tested on their own (smoke-report-community.md, smoke-report-community-arm64.md): amd64 PASS with gaps: 8 of 11 checks passed in full, 0 partly, 3 skipped (see the reasons below); arm64 PASS with gaps: 8 of 11 checks passed in full, 0 partly, 3 skipped (see the reasons below).
Images
Two builds of the same release. The full build is the Apache-2.0 core plus the Business and Service Provider modules (Restow Enterprise License), which stay locked until a license key is installed. The Community build is the Apache-2.0 core alone.
ghcr.io/restow-backup/restow:0.3.5
ghcr.io/restow-backup/restow-web:0.3.5
ghcr.io/restow-backup/restow-community:0.3.5
ghcr.io/restow-backup/restow-web-community:0.3.5
The digests of the multi-arch manifests (the opt-in updater verifies the pulled images against the two lines of its build):
restow: sha256:1b95f10649e900cf51ae02cfbaabb0d7fc5ce4c22788f32f3e253d6c95c82772
restow-web: sha256:2a973e0fc56a4c844103fd68910fc2617b807a6f21f82c6a26fd469524083f9a
restow-community: sha256:10b90464c9d2272181807627790633a42775ea5299c453fa57fd89ec033282ff
restow-web-community: sha256:88ae43915b6d485c69b5042631807ad48571fec580ebee6aa10037c9354f5649
All four images are multi-arch (linux/amd64, linux/arm64), signed with cosign (keyless) and carry an SPDX SBOM as attestation. Verify any of them with:
cosign verify ghcr.io/restow-backup/restow:0.3.5 \
--certificate-identity-regexp '^https://github.com/restow-backup/restow/\.github/workflows/release\.yml@refs/tags/v' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
cosign verify ghcr.io/restow-backup/restow-web:0.3.5 \
--certificate-identity-regexp '^https://github.com/restow-backup/restow/\.github/workflows/release\.yml@refs/tags/v' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
cosign verify ghcr.io/restow-backup/restow-community:0.3.5 \
--certificate-identity-regexp '^https://github.com/restow-backup/restow/\.github/workflows/release\.yml@refs/tags/v' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
cosign verify ghcr.io/restow-backup/restow-web-community:0.3.5 \
--certificate-identity-regexp '^https://github.com/restow-backup/restow/\.github/workflows/release\.yml@refs/tags/v' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
docker-compose.yml and env.example are the release stack (deploy/release/); install.sh installs it on a dedicated Linux VM (README.md, "Install with the script"; install.sh.sha256 for sha256sum -c after the download); restow-agent-THIRD_PARTY_NOTICES.txt holds the licenses of the agent binaries and of the restic they run; SHA256SUMS lists every file of this release and is signed (SHA256SUMS.sigstore.json).