Repository navigation
Restow 0.2.0
Restow 0.2.0. Released 2026-10-03, 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.2.0 reorganises the web interface around three levels (the installation,
a tenant, all tenants), adds backup jobs that replace per-object schedules, and
shows running backups live with throughput charts and a History page. Updating
from 0.1.0 runs three additive database migrations and, on the first start, moves
your backup and restore-check schedules and your machines into jobs without
deleting anything; plan a few minutes for it and read the Upgrade Notes first. The
install script now covers installations behind a reverse proxy with an encrypted
hop, which needs the new docker-compose.yml of this release.
Breaking Changes
Three things behave differently for scripts and integrations that talk to the
API. Nothing changes for the data in your repositories or for the agent API
that installed agents use.
POST /api/v1/setuprequiresproviderName. The setup wizard asks for the
name of your own organisation, and the call that sets up an installation now
needs it. A script that sets up an installation without a browser has to add
the field; without it the call is refused with 422.- Backup and restore-check schedules are created through jobs.
POST /api/v1/scheduleswith kindbackuporverifyanswers 422
(kind_replaced_by_jobs). Maintenance schedules (retention run, storage check,
directory sync, archive sync) are unchanged. Create a backup job instead
(POST /api/v1/backup-jobs, or Mail & SaaS > Jobs in the web interface).
Schedules that existed before the update keep their rows and are shown with
supersededByJobId. - A machine that belongs to a job is configured from the job.
PATCH /api/v1/endpoints/:idanswers 409endpoint-config-managed-by-jobwhen
it would change folders, exclusions, hooks, bandwidth or the schedule. Change
them on the job, or take the machine out of the job first. Display name, the
power switch and the storage budget stay editable on the machine.
Web addresses did not break: every old address (/settings, /sources,
/schedules, /backup, /jobs/<run id>, /audit and more) redirects to its new
place and keeps its query, so bookmarks and links in mails keep working.
/api/v1/jobs keeps its meaning and its shape; /api/v1/runs is the new,
documented name for the same list.
Added
Backup jobs
- Jobs. A job is the definition of what is backed up, when, where and for how
long, over many mailboxes, OneDrives, IMAP accounts or machines at once.- Mail jobs (Mail & SaaS > Jobs) have a backup schedule, an optional
restore-check schedule, a retention policy (or the tenant default) and a
scope: the objects you pick, or "every object that is in no other job", which
also catches objects added later (one such job per tenant). An object belongs
to at most one job. - Machine jobs (Servers & endpoints > Jobs) cover servers and clients with an
agent: a schedule (every N hours, daily at a time, or when the machine
connects), folders, exclusions, a bandwidth limit, optional hooks and how many
daily, weekly and monthly restore points to keep. - Per-member overrides. One mailbox can run on its own schedule, one machine
can have other folders, exclusions, bandwidth, hooks or retention. An override
replaces the job's value for that member.
- Mail jobs (Mail & SaaS > Jobs) have a backup schedule, an optional
- The job pages and the editor.
/jobs?type=mailand/jobs?type=endpoint
list the jobs with scope, schedule, repository, last and next run, status and
the result of the last restore check (green only for a passed restore check). A
job opens in tabs (Overview, Scope, Settings, Runs). The editor is a side sheet
that works with the keyboard; for machine jobs it shows the folders as a tree
read from the latest backup, offers exclusions as chips (videos, disk images,
temporary files, installers, music, trash and caches, your own patterns, "skip
files larger than X GB") and takes a bandwidth limit and hooks. - Run now, per job or for selected members.
- A default mail job for new tenants. The first active source of a tenant
creates one mail job over all objects (backup every 8 hours, restore check every
Sunday at 03:00). - Bandwidth time windows. A machine job keeps its upload limit in kbit/s as the
default and can add windows that set another limit for certain days and hours
(for example Monday to Friday 08:00 to 18:00: 1000 kbit/s; 0 means unlimited). A
window may cross midnight, windows must not overlap (the editor and the API name
the later one), the times are read in the time zone of the job's schedule, and
the limit that applies when a run starts is used for the whole run. Up to 24
windows per job; per machine they are overridden together with the limit. No
agent update is needed: the server picks the limit when the agent asks for its
configuration. - The size limit works. Agent 0.2.0 passes "skip files larger than X GB" to
restic (--exclude-larger-than); the run log says so.
Live runs, History and the run drawer
- Live runs. One event stream per browser tab (
GET /api/v1/live) carries
running backups with their progress, the jobs' state with last and next run and
the machines' connection; pages stop polling while it is open. The top bar says
"Live, updated 4 s ago", "Connecting" or "Not connected, retrying", and the pages
fall back to polling when the stream is lost. - Throughput and sparklines. Running backups record what was read and what was
written to the repository (up to 300 points per run) and show progress, speed, a
sparkline and the time left in the job list and in History. - The run drawer. A click on a job row or a History row opens the run in a
panel from the right: state, progress, summary, two charts on one time axis (one
crosshair, keyboard operable), the objects of the same backup run, the timeline
and the actions (cancel, retry, edit the job). The address carries?run=<id>.
The transfer chart shows an average over 15 seconds, because data reaches the
repository in packs. - History (
/history) lists every run of the tenant, the server's and the
agents', in tabs (all, backup, restore, restore check, export, import,
maintenance) with a filter per job and paging. A retried restore check is one row
("attempt 3 of 6"). - Progress every 5 seconds (agent 0.2.0) instead of every 10, so the charts get
twice the resolution.
Interface structure, tenants and branding
- Three levels. The menu is organised as Daily, Mail & SaaS, Servers &
endpoints, Tenants and Installation. The tenant switcher moved to the top of the
sidebar, with a gear for the active tenant's settings; the page header names the
level ("Installation", "Own organisation", "Tenant: ...", "All tenants"). - The installation page (
/installation/<section>): Server, Notification mail,
Microsoft multi-tenant app, Journal receiving (Business), Default storage (with a
test that belongs to no tenant), Provider API (Service Provider), Updates,
License and About. Sections your edition does not include stay visible with a
lock. Provider roles that may look but not change see the forms closed with a
sentence. - The tenant page (
/tenants/<tenant>/<section>): Overview, Connections,
Protection, Jobs & schedules, Backup retention, Storage, Agents, Archive,
Notifications, Integrations, Members, Audit log and Master data. A tenant's own
administrator sees their tenant's page and no other. "Connect Proxmox" is
announced on the Inventory page as "Soon" and starts nothing. - Your own organisation. Every installation can mark one tenant as the
operator's own (kindinternal), listed first, protected from deletion and not
counted as a customer in provider figures. The setup wizard asks for its name and
creates it with its own key and two alert rules. - "All tenants" scope for provider administrators: the overview sums the
recovery readiness over every tenant and lists "Tenants by need for action"; pages
that exist only per tenant ask you to choose one. The entry that lists tenants is
now "Manage tenants". - "Start" in the menu replaces the setup card: it shows how many of the seven
steps are done and opens a popover with the steps. The notification mail is the
one optional step; an installation that skipped it sees "Start" disappear once
the other six are done. - Recovery readiness is linked. Every row of the readiness tile opens
/verify?state=<state>, with chips and counts for the five states. - Brand colours and a second colour scheme. The interface uses the Restow brand
colours (Limestone, Nile, Lapis); "Neutral" is the black-and-white look of 0.1.0,
chosen per browser in the user menu, in the command palette and on the sign-in and
setup pages. Inter Tight and IBM Plex Mono are bundled into the web image as
woff2files (about 320 KB) and served from/assets; nothing is fetched from
outside and the Content-Security-Policy is unchanged. - Wide tables scroll inside their own frame with the first column pinned
(two for the audit log), reachable with the keyboard; data views use the full
width of the content area.
Installation and setup
- The install script explains itself and asks how Restow is reached: public
with its own certificate, behind a reverse proxy you run, or local evaluation.
Every existing option still works;--non-interactiveasks nothing. - Behind a reverse proxy:
--behind-proxy(--domain,--proxy-ip). Restow
then needs no public DNS record, no certificate of its own and no inbound port
from the internet. The hop to the proxy is encrypted by default (new setting
RESTOW_EDGE_TLS=internal; the edge shows a certificate from Caddy's own
authority and the script copies its root certificate to
/opt/restow/edge-root-ca.crt).--proxy-hop httpselects the unencrypted hop,
only for a proxy on the same host or in an isolated network; the script says so.
RESTOW_HTTP_PORTandRESTOW_HTTPS_PORTnow accept an address such as
192.168.1.50:443. - The end of the installation shows the address and the setup token, and where
a proxy must forward to. The token goes to the terminal only, never to
/var/log/restow-install.log. - The setup wizard starts with the language (English or Deutsch, also the
language of your own organisation) and has seven steps. The notification mail can
be skipped ("Skip for now");POST /api/v1/setupacceptslanguageand an absent
mail.
Tenants and notifications
- Agent updates are paused once per tenant (Tenant page > Agents), which also
covers machines enrolled later. A machine with a pause of its own (the old way)
stays paused and is listed as an override with "Resume this machine" and "Resume
all". - Tenant administrators may read their tenant and edit its notification
recipients (GET /api/v1/tenants/:id,PUT /api/v1/tenants/:id/notification-recipients), and have an Audit log section on
their tenant page. GET /api/v1/history,GET /api/v1/history/:id,GET /api/v1/live,
/api/v1/backup-jobs(session API of the web app),kindandcustomerNumber
on tenants (GET /api/v1/me,GET /api/v1/tenants,GET /api/v1/provider/tenants),widgetsandproviderparameters onGET /api/v1/dashboard, andPUT /api/v1/settings/mail/not-needed. The integration
API is contract 1.2.0 (additive): the runs are also available as/runs,
/runs/{id},/runs/backupand/runs/{id}/events.- New audit actions:
backup_job.created,.updated,.deleted,.scope.changed,
.run_requested,.migrated(written by the system),tenant.internal.marked,
tenant.internal.unmarked,settings.mail.not_needed,
setup.internal_tenant_failed.
Changed
- Schedules now hold only maintenance and the schedules of an older release
that no job could take over. A restore check after every backup follows the job;
retention follows the job that names a policy (a policy scoped to one object still
wins), and a retention policy that a job names cannot be deleted (409). - Saving the notification recipients now changes who is mailed. Each category
(failed jobs, readiness turning red, weekly report) is carried by one rule of the
tenant, kept up to date from the next alert on. Before, the recipients were used
once to create rules and later edits changed nothing. The recipients field of such
a rule is read-only in the alert editor. - The default storage counts as tested once the installation tested it, whether
the tenant or the installation ran the test; a newer failed test shows the step
as failing. - Provider figures no longer count your own organisation as a customer. Its
objects, failures, mailboxes and storage are still part of the sums; the license
audit entries count customers only. - Texts follow the level. Community and Business pages say "your organisation",
never "tenant". - Error text and destructive buttons are easier to read in light mode (red text
contrast now at least 4.5:1, amber of the "Soon" badge a hair darker). - Green means proof only. A backup that merely completed is Lapis in the PDF
statistics report, as in the web charts. - Small headings and badges are in sentence case, the wordmark reads "restow
backup suite" (your ownRESTOW_PRODUCT_NAMEis shown as written), and PDF
reports follow the brand palette with the standard PDF fonts. - Capacity planning (Installation, formerly "Resources") announces 0.5.0.
- Where things moved. Settings > General, Mail, Microsoft 365, Updates, About,
Danger zone and Integrations > Provider keys are sections of Installation; Sources,
Imports, Protected objects, Schedules, Retention, Repositories, Alert rules,
Integrations, Members and the tenant detail page are sections of the tenant page;
/backupleads to/jobs?type=mail. docker-compose.ymlof the release passesRESTOW_EDGE_TLSto the edge and
documents that the two published host ports accept an address;
RESTOW_EDGE_TLSis empty inenv.example.- Dependabot groups its updates and no longer runs CI twice for its branches;
Hono 4.13.10, better-auth and its passkey plugin 1.7.6, TanStack Router 1.170.40
and Query 5.104.0 and react-hook-form 7.89.0 were updated (patch and minor, no
configuration, API or database change). The build stageagent-diststarts from
Alpine 3.24; Alpine is not part of the shipped image. scripts/release/sign-agent.shruns from any directory and the release
workflow explains why a tag signature is not verified (and refuses it when the
repository variableREQUIRE_SIGNED_TAGSistrue). Release tooling; operators
are not affected.
Fixed
- Saving a migrated job reset its timer. The schedule before and after an edit
was compared by how its JSON was ordered and spelled, not by its meaning; it is
compared by meaning now, so saving a job without changing its schedule keeps the
next run. - Editing notification recipients later changed nothing. Recipients were only
used when the tenant was created; saving them now updates the rules (see
Changed). - A tenant that tested the default storage kept the setup reason "the server's
default storage has not been tested". The test was recorded for the installation
and the tenant only read its own; the newest test counts now. - A tenant administrator who opened another tenant's address saw "All tenants" in
the header. The header named the wrong level; it names the administrator's own
level and the page belongs to Tenant settings in the menu. - Tenant page > Storage showed two "Repositories" headings. The list is a
region of that name with its explanation. - The mail preview tests failed on slow CI runners (they gave the plain-text
fallback half of a short time limit, which a loaded runner spent starting the
parser process; this failed the v0.1.0 release CI three times). Each phase has
its own limit now. The product's behaviour and its default limits are unchanged.
Security
No advisory or CVE affects 0.1.0 and is fixed here. Two points concern the update
of the sign-in library and the new proxy mode.
- Over-long passwords are refused before they are processed. better-auth 1.7.6
rejects a password longer than its configured maximum on sign-in and on the other
password endpoints before it is hashed or compared. Restow accepted passwords of
up to 256 characters before and now sets the maximum to 256 explicitly:
operators whose password is between 129 and 256 characters long are
unaffected. The limits are at least 12 and at most 256 characters, as before. - The hop between a reverse proxy and Restow is encrypted by default with
--behind-proxy. The plain HTTP hop (--proxy-hop http) sends session cookies
and passwords unencrypted between the proxy and Restow, and port 80 is open to the
network; use it only on the same host or in an isolated network. Docker publishes
ports pastufw: behind a proxy, publish the edge's port on one address
(RESTOW_HTTPS_PORT=192.168.1.50:443) or add a rule to Docker'sDOCKER-USER
chain. - Typefaces are served by your installation; nothing is requested from Google Fonts
or any other host.
Upgrade Notes
Order: back up (docs/UPDATING.md), replace the compose file if you want the
encrypted proxy hop, pull the 0.2.0 images, start. Migrations run automatically at
start.
- Database: five additive migrations,
0020_tenant_kind,
0021_tenant_page_settings,0022_setup_mail_not_needed,0023_backup_jobsand
0024_run_samples. They add
columns and tables (with Row Level Security) and delete nothing; each is safe to
run twice and needs no downtime. 0020 addstenants.kind, 0021
tenants.agent_updates_pausedandreport_rules.recipient_category, 0022
settings.mail_not_needed, 0023 the tablesbackup_jobsand
backup_job_members,schedules.superseded_by_job_idand
tenants.backup_jobs_migrated_at, and 0024 the tablerun_samplesand two byte
columns onjob_progress. Existing runs have no samples; their charts say "No
measurements were kept". - Your schedules and machines become jobs when the API starts, once per tenant.
The step runs in the API process before it serves requests, one transaction per
tenant. Nothing is deleted, and a second start finds nothing to do.- Mail. A tenant's enabled backup and verify schedules become one mail job
("Mail backup" or "Mail-Sicherung" after the tenant's language). A tenant-wide
schedule becomes the job's schedule and the job covers every object, so mailboxes
added later are backed up. A schedule of one object becomes that object's
override only when it protects the object at least as well as the job's schedule
at every time of day and week; otherwise it stays exactly as it was and keeps
running next to the job, so no object is ever backed up less often than before
(nights, weekends, monthly schedules and the further schedules of an object stay
as they were). The next run times are carried over, so nothing runs early or is
skipped. - A tenant that already has a mail job (the step failed at an earlier start and an
administrator created a job by hand) keeps all its schedules; they run next to
that job. The tenant's audit entry lists them (reasonmail_job_exists); switch
them off under Tenant settings > Jobs & schedules once the job covers the same
objects. - Replaced schedules stay on record with
superseded_by_job_id; the scheduler no
longer plans them and the API refuses to change them. - Machines. Active machines with the same profile, operating system and schedule
become one job (for example "Linux servers · daily 02:00"); what most machines of
a group share is the job's, a machine that differs gets an override with just the
differences. Revoked machines are left out. The step checks that the job
reproduces every machine's configuration exactly: nothing is rewritten and no
machine gets a new configuration version. - Audit. Every tenant gets a
backup_job.migratedentry written by the system
with the numbers; the API log carries the totals at start. - Failure. If the step fails for a tenant, the API still starts, nothing of that
tenant is changed, its old schedules keep running and the step is tried again at
the next start. The API log names the tenant ("a tenant could not be moved to
backup jobs and keeps its schedules"). Do not create a mail job by hand for such
a tenant, or its old schedules and the new job both run.
- Mail. A tenant's enabled backup and verify schedules become one mail job
- Machines in a job are configured from the job. Tenants created after the update
do not get their machines grouped automatically: put a new machine into a job, or
leave it with the configuration it enrolled with. - Encrypted proxy hop: replace
docker-compose.yml. The 0.1.0 compose file does
not passRESTOW_EDGE_TLSto the edge, and changing the image lines in.envdoes
not replace it. To switch an installation behind a reverse proxy from the plain
HTTP hop to the encrypted one: replace/opt/restow/docker-compose.ymlwith the one
of the 0.2.0 release assets, setRESTOW_APP_DOMAIN=<name>(withouthttp://),
RESTOW_EDGE_TLS=internalandRESTOW_HTTP_PORT=127.0.0.1:in.env, run
docker compose up -d, and set the proxy to schemehttps, port443. In Nginx
Proxy Manager add under Advancedproxy_ssl_server_name on;,
proxy_ssl_name $host;andproxy_buffering off;. Without these steps an
installation made with 0.1.0 keeps working unchanged: the edge behaves as before
whileRESTOW_EDGE_TLSis unset oracme, and the script never changes an
existing.env.--behind-proxyitself needs release 0.2.0 or newer;
--proxy-hop httpworks with any release. - Reverse proxies must not buffer
text/event-streamfor/api/v1/live. The
stream answers withcache-control: no-cacheandx-accel-buffering: no, which
nginx honours; switch response buffering off for that path on other proxies. If the
stream cannot be held open, the indicator says so and the pages poll. One stream is
held per open tab, and only while the tab is in front. A proxy must also pass
/assets/*through unchanged, as it already does. - Agents update themselves. An agent asks the server every 6 hours for a newer,
signed agent (the 0.2.0 agent ships in the 0.2.0 image), checks the signature
against the key compiled into it, replaces itself and its restic where the release
pins another one and restarts its service. Machines that are off update when they
are next online. The size limit and the 5 second progress need agent 0.2.0. If you
paused automatic updates (Tenant page > Agents) or paused one machine, that machine
keeps its old agent until you resume or install it again with the install command. - Service Provider installations: mark your own organisation once. Sign in as an
owner or administrator of the provider team; the overview asks you to choose the
tenant that holds your own data or to create a new one. Until then everything works
as before. A Community or Business installation with exactly one tenant marks it at
the first start (audit entry, actor "system"); an installation with several tenants
and no Service Provider key is asked the same question. - Automation: every
POST /api/v1/setupcall needsproviderName; the tenant
lists are ordered own organisation first, then by name; scripts that created
backup or verify schedules must create jobs. A script that runs the installer
behind a proxy passes--behind-proxy --domain <name> --proxy-ip <address> --non-interactive; the setup token is not printed in a run without a terminal,
read it from the API's log. - Rolling back to 0.1.x. Migrations stay applied; 0.1.x ignores the new columns
and tables and backups keep running, with these effects:- 0.1.x does not know
superseded_by_job_idand plans every backup and verify
schedule again, the replaced ones included. Their next run times stayed where
they were at the upgrade, so right after the rollback every replaced schedule is
overdue and runs once (a backup and a restore check of every covered object at
once), then on its old cadence. - 0.1.x does not know jobs. A tenant whose first source was connected after the
update has only its default mail job and no backup or verify schedule: nothing
backs it up on 0.1.x until you choose "Apply recommended schedules" for it.
Changes made to a job after the update do not exist on 0.1.x. - Machines keep the configuration last written to them, a job's later change
included; the agent ignoresexcludeLargerThanBytes, and 0.1.x lets you change a
machine's settings on its page again. A 0.1.x server sends the stored default
bandwidth limit and never the size limit or time windows; windows stay in the job
and apply again after the next update. - A pause of agent updates set on the tenant after the update is not honoured by
0.1.x, which only knows the pause stored on the machines. - Updating to 0.2.0 again does not move a tenant twice. Schedules created on 0.1.x
run next to the jobs (backups twice), changes made on 0.1.x to replaced schedules
are ignored, and machine settings changed on 0.1.x are overwritten the next time
their job is changed. Check each tenant's jobs and its "Jobs & schedules" section
after updating again. - Run one scheduler version at a time. A 0.1.x and a 0.2.0 scheduler share the
leader lock, so only one plans at a time, but each change of leader between them
runs what the other left overdue.
- 0.1.x does not know
- Where to look afterwards: the tenant's mail job under Mail & SaaS > Jobs, its
machine jobs under Servers & endpoints > Jobs, andbackup_job.migratedin the
audit log.
Known Issues
- Microsoft 365 backup and restore have still never run against a real Microsoft 365
tenant; they are covered by tests against a simulated Graph API. Run Restow next to
your existing backups and restore a test mailbox before you rely on it. - Jobs write to the tenant's primary storage target. The editor shows it and the
API refuses another; a repository per job comes later. A machine job cannot be
paused (the agent decides when to back up; taking machines out of the job ends the
management, not the backups), and restore checks of machines follow every backup
with no cadence to set. - Schedules the migration could not take over stay old-style schedules in Tenant
settings > Jobs & schedules and keep running next to the job: an object's own
schedule that pauses longer than the job's, the further schedules of an object
that had several of one kind, a second tenant-wide schedule with another cadence
and a cadence the scheduler cannot plan. Move such an object into a job with the
schedule you want and then switch the old schedule off. A tenant without a
tenant-wide schedule gets a job over exactly the objects that had one of their
own; an object that had only one kind of schedule now also gets the other kind
(more runs, never fewer). - A run keeps the bandwidth limit of its start, and time windows apply to
backups only, not to restores or restore tests. Throughput of an agent run is
derived from the growth of the repository, so another machine writing to the same
repository adds to it; runs started before the update and agents that report no
progress have no throughput line. - Under "All tenants" there is no cross-tenant history, alert list or object
list; those pages ask for a tenant. The notifications bell, the Statistics tab
and the command palette have no "All tenants" scope, and "Start" is hidden there. - The archive retention period cannot be changed yet (8 years, not settable); the
tenant page shows what applies. Google Workspace and Proxmox are announced, not
built. Leaving an installation or tenant section with unsaved changes drops them. - Not looked at in a browser: the layout of the seven-step wizard on a narrow
screen was checked in code and tests, not by eye.--behind-proxywas verified
against stub commands and a real Caddy edge, not on a VM with a real Nginx Proxy
Manager since the encrypted hop was added; the plain HTTP hop is the configuration
verified by hand on a Proxmox VM. - Deferred to 0.2.1: context menus, the "assigned to" column and owner of a machine
in the machine table, file restore from the machine table with the shared
timeline, and simulated runs in the public demo. - The checks listed as not run under Verification were not repeated for this
entry; the release pipeline runs the smoke checks.
Verification
Measured on 2026-10-03 on the release candidate (revision 9272693 plus the
uncommitted 0.2.0 changes; the tag commit differs and the release pipeline repeats
the smoke on it). Host: Apple M4 MacBook Air, macOS 26.5.2; Node 25.9.0, pnpm 9.15.9,
Go 1.27.1, restic 0.19.1 (the pinned binary of agent/dist), PostgreSQL 16.14
(local). No Microsoft 365 development tenant was used. Heavy steps ran one after
another with VITEST_MAX_FORKS=3.
- Lint, typecheck, build:
pnpm lint(Biome over 2461 files, theee/import
boundary, the former-name and package-file guards),pnpm build:libsand
typecheckover every workspace passed. - Test suites: Vitest over 13 workspaces with the PostgreSQL suites and
RESTIC_BINARYset: 770 test files, 9600 tests, all passed (apps/web 3352,
apps/api 2825, packages/core 1914, apps/worker 379, packages/i18n 244, ee/api 238,
demo seed 172, ee/web 177, packages/db 139, apps/scheduler 65, ee/licensing 59,
packages/cli 32, ee/worker 4). The same run withoutRESTIC_BINARYpassed 9463
tests and skipped 137 (the restic-dependent ones).deploy/install/test.sh: 601
checks passed under bash 3.2 (macOS). - Endpoint agent:
gofmt -lclean,go vet ./...andgo test -race ./...passed
for all packages. - Migrations: 25 (0000 to 0024); the PostgreSQL suites ran against them.
- Not run in this pass, and so not claimed: the release smoke and image builds,
Trivy,pnpm audit, the license check, gitleaks, ShellCheck, the updater
end-to-end test, the installer on VMs and the upgrade path from a 0.1.0 database
with the schedule migration (the migration is covered by its own PostgreSQL
tests). The release pipeline runs the smoke for both builds on amd64 and arm64 and
attaches the smoke reports; this section is completed with their result.
Release pipeline, 2026-10-03:
| Check | Result | Duration |
|---|---|---|
| 1. Install: images, compose up, migrations (new install and upgrade) | PASS | 84s |
| 2. Health endpoints, worker and scheduler registered | PASS | 0s |
| 3. Passkey sign-in E2E with a virtual authenticator, tenant creation, i18n de/en | PASS | 113s |
| 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 | 24s |
| 8. Storage targets: S3 (Garage), local path, mounted directory | PASS | 20s |
| 9. Image scan (Trivy) and dependency audit (pnpm audit) | PASS | 19s |
| 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.2.0
ghcr.io/restow-backup/restow-web:0.2.0
ghcr.io/restow-backup/restow-community:0.2.0
ghcr.io/restow-backup/restow-web-community:0.2.0
The digests of the multi-arch manifests (the opt-in updater verifies the pulled images against the two lines of its build):
restow: sha256:baa9c4e42d38acfc4e8bae11c33c7ad3b4be17936d809789ca0fa39169e25b06
restow-web: sha256:7ea7981820dc7b739f8f409095f32f47c0a5ab899897ca0a1d2bf9a183f0c112
restow-community: sha256:262305ea1fc3400278eafa1fce1e27ffcf246b5085188e4770ddc69b27c6579d
restow-web-community: sha256:e48dddb7e80111c875ffb349c1100af80b680e6300972f47f0c69f0e94efee6c
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.2.0 \
--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.2.0 \
--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.2.0 \
--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.2.0 \
--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).