Self-hosted service
garethgeorge/backrest avatar
garethgeorge/backrest

Backrest: a web UI and orchestrator for restic backups

Backrest is a web UI and orchestrator for restic backup.

7,393 stars216 forksTypeScriptGPL-3.0

At a glance

What is it?
Backrest wraps the restic CLI in a browser interface and a scheduler, so you can create repositories, browse snapshots and restore files without memorising flags. It is a single Go binary with restic as its only dependency, and it is GPL-3.0 licensed.
Who is it for?
Adopt Backrest if you already trust restic and want a browser, a cron-style scheduler and notification hooks around it, especially on a NAS or a home server where nobody wants to type restic commands at 2am. Skip it if you need per-file policy control that only the restic CLI exposes, or if you cannot run a long-lived HTTP service on the machine holding the data.
Can I use it commercially?
Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 9 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What Backrest adds on top of restic

restic is a command line backup program. It is fast, it deduplicates, and it encrypts repositories, but every operation is a subcommand with flags: init, backup, snapshots, restore, forget, prune, check. For a laptop that is fine. For a household NAS with three machines, four repositories and a retention policy, the flags become a maintenance burden, and the person who set it up is often not the person who needs to restore a file.

Backrest targets that gap. According to the README, it provides a WebUI which wraps the restic CLI and makes it easy to create repos, browse snapshots, and restore files. It also runs in the background and takes what the README calls an opinionated approach to scheduling snapshots and orchestrating repo health operations. That second half matters more than the first. A web form for restic init is a convenience; a background process that runs prune and check on a schedule and tells you when a repository has gone unhealthy is a different product category.

The intended user is someone who already has, or wants, restic repositories and is willing to run a small service next to them. NAS deployments are named explicitly in the feature list, and the Docker instructions mount a data directory, a config file, a cache directory and the paths to be backed up. That is a server-shaped deployment, not a desktop one, although Linux, macOS, Windows and FreeBSD are all listed as supported platforms.

How the WebUI, the scheduler and restic fit together

Backrest is written in Go and compiled to a standalone binary whose sole dependency is restic, as the README puts it. The repository layout confirms the split: cmd/ holds the entry points, internal/ and pkg/ hold the Go packages, proto/ holds protocol definitions, and webui/ holds the TypeScript front end that gives the project its primary language on paper. The go.mod file shows connectrpc.com/connect and google.golang.org/grpc, so the browser talks to the daemon over a Connect or gRPC-style API rather than a hand-rolled REST layer. It also pulls in github.com/ncruces/go-sqlite3, which is the likely home for operation history, and github.com/hashicorp/cronexpr, which is the cron expression parser behind the scheduling feature.

The data flow is straightforward. The daemon owns a config file, by default config.json under the data directory in the Docker example. Plans, repositories and hooks live there. When a plan fires, Backrest invokes the restic binary as a subprocess with the arguments the plan implies, streams the output, and records the result. Because restic is invoked rather than reimplemented, the repository format on disk is plain restic. You can point the restic CLI at the same repository and it will work, which is the README's stated escape hatch for advanced operations.

That design has a consequence worth naming. Backrest is an orchestrator, not a backup engine. Its correctness depends on restic's correctness, and its failure modes include all of restic's. It also means the daemon needs to know where restic lives. The README says Backrest will use your system's installed version if it is available and compatible, and otherwise download and install a suitable version in its data directory, keeping it updated. The BACKREST_RESTIC_COMMAND environment variable overrides that path. If you pin a restic version for reproducibility, that variable is how you do it.

Installing Backrest and running a first snapshot

The recommended Linux and macOS path is the install script, which the README says downloads the latest release, places the binary in /usr/local/bin, and sets up auto-start integration: systemd or OpenRC on Linux, launchd on macOS.

bash
curl -fsSL https://raw.githubusercontent.com/garethgeorge/backrest/main/install.sh | bash

By default the service binds to 127.0.0.1:9898 and runs as your user, so configuration and data live under your home directory. If you want it reachable from other machines on the network, pass the flag after the separator:

bash
curl -fsSL https://raw.githubusercontent.com/garethgeorge/backrest/main/install.sh | bash -s -- --allow-remote-access

That is a shortcut for setting BACKREST_PORT to a non-loopback address. The README's example value is BACKREST_PORT=0.0.0.0:9898. Treat that as a deliberate exposure decision, because the WebUI is the thing that can delete snapshots.

For a container deployment, the README gives a Compose file with the image ghcr.io/garethgeorge/backrest:latest. The environment block is the part to read closely, since it decides where state lives:

yaml
environment:
  - BACKREST_DATA=/data
  - BACKREST_CONFIG=/config/config.json
  - XDG_CACHE_HOME=/cache
  - TMPDIR=/tmp
  - TZ=America/Los_Angeles
ports:
  - "9898:9898"

Each of those paths needs a matching volume mount, and the README's example also mounts an rclone config directory at /root/.config/rclone, which it notes is needed when using rclone remotes.

Once the service is up, open http://localhost:9898. The README states that first-time setup prompts for username and password creation. After that, the workflow is: add a repository (create a new one or import an existing restic repository), define a plan with a cron schedule and the paths to back up, and let it run. Notifications can be wired to Discord, Slack, Shoutrrr, Gotify or Healthchecks, and pre and post backup command hooks can run shell scripts around each snapshot.

Where Backrest is the wrong tool

The clearest limitation is that Backrest does not replace restic's policy surface. Anything restic can do that is not exposed as a plan field, a hook or a repository setting is still a CLI operation. The README frames this positively, saying the WebUI handles most operations while still allowing direct access to the restic CLI for advanced operations, but read it as a boundary: fine-grained include and exclude rules, unusual backend flags, and one-off recovery procedures are yours to type.

A second constraint is the daemon itself. Backrest has to be running for scheduled backups to happen. On a laptop that sleeps, the schedule is only as reliable as the machine's uptime, and the install script's default of running as your user means the service stops when the session does on some configurations. The README does not document rollback of a Backrest upgrade, nor does it describe what happens to in-flight operations when the daemon is restarted mid-snapshot. Those are the questions to ask before putting it on a machine you cannot easily inspect.

Third, the notification and hook features are execution surfaces. A post-backup hook runs shell commands as the Backrest user. If the WebUI is exposed with --allow-remote-access and the credentials are weak, the blast radius includes arbitrary command execution on the backup host, not just snapshot deletion. The README does not describe a hardened authentication story beyond the first-run username and password prompt.

Finally, if your environment already has a configuration management system that drives restic directly, adding Backrest inserts a second source of truth for schedules. Two schedulers writing to the same repository is a good way to get overlapping prune operations.

Backrest compared with running restic yourself or using a wrapper

The honest alternative is restic plus your own cron entries and a shell script. That approach has no service to keep alive, no web port to secure, and no extra state beyond the repository and its password. The difference in approach is who owns the schedule and the health checks. With plain cron you write the forget and prune invocations, you parse the exit codes, and you decide what a failed check means. Backrest moves that into a config file and a UI, and adds a history of operations you can look at later.

A second alternative is a general-purpose backup front end that is not built on restic. Those tools typically own their own repository format and their own client. The trade-off is the reverse of Backrest's: you get a more integrated experience, and you give up the ability to point the restic CLI at the repository when the front end is broken or abandoned. Because Backrest shells out to restic and stores nothing proprietary in the repository, a Backrest repository remains readable by restic itself. That is the strongest argument for this design, and it is worth weighing against the convenience of a tool that manages everything internally.

Backrest also sits close to the line between those two categories. It has its own config file, its own SQLite-backed history and its own scheduling semantics, so it is not a thin skin over restic. The repository format is the only thing that stays portable.

Licence, maintenance and upgrade cost

Backrest is licensed under GPL-3.0. If you run it as a service for yourself or your organisation's internal machines, the licence is unlikely to change your plans. If you intend to embed it in a product or ship a modified binary to customers, the copyleft terms apply to the distributed work, and that is a question for your own legal review rather than something this article can settle.

The project is not archived, and the last push to the main branch was on 2026-09-21. Recent tagged releases are v1.14.1 and v1.14.0, both dated 2026-07-12, with v1.13.0 before them on 2026-05-04. That cadence suggests a project that ships, but the README does not document an upgrade procedure or a config schema version, so the practical upgrade cost is unknown until you look at CHANGELOG.md in the repository. The Docker path makes upgrades a pull and a restart, which is cheap if the config format is stable and expensive if it is not.

One operational cost is easy to overlook: the Docker image bundles rclone and common Unix utilities, while ghcr.io/garethgeorge/backrest:scratch is offered as a minimal alternative. Choosing the minimal image means anything your hooks call must exist inside it. That is a real constraint when a post-backup hook invokes a shell utility the README's example image happens to include.

Editorial conclusion

Adopt Backrest if you already trust restic and want a browser, a cron-style scheduler and notification hooks around it, especially on a NAS or a home server where nobody wants to type restic commands at 2am. Skip it if you need per-file policy control that only the restic CLI exposes, or if you cannot run a long-lived HTTP service on the machine holding the data. Before committing, verify three things: that your restic repositories were created with a password you still have, that BACKREST_PORT and BACKREST_RESTIC_COMMAND point where you expect, and that a restore of one real file works from the WebUI, not just a snapshot listing.

Frequently asked questions

How do I install Backrest on Linux?

The README recommends the install script, which downloads the latest release, places the binary in /usr/local/bin and sets up systemd or OpenRC auto-start. You can also clone the repository and run ./install.sh locally, which accepts the same flags.

Does Backrest work with Docker?

Yes. The README publishes ghcr.io/garethgeorge/backrest and a Docker Hub image, and gives a Compose example that mounts separate volumes for data, config, cache and tmp. It also notes a scratch variant for a minimal image.

What port does Backrest use by default?

The default is 9898, and the README says the first-run setup prompts for a username and password at http://localhost:9898. To change it, set the BACKREST_PORT environment variable.

Can Backrest manage an existing restic repository?

The feature list includes importing existing restic repositories, and because Backrest invokes the restic CLI rather than using a proprietary format, the README says the restic CLI remains available for advanced operations against the same repository.

Which storage backends does Backrest support?

The README states it supports all restic storage backends, including S3, B2, Azure, GCS, local and SFTP, and is compatible with rclone remotes. Using rclone remotes requires mounting an rclone config directory in the Docker setup.

Official sources

  1. garethgeorge/backrest on GitHub
  2. License: GPL-3.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/garethgeorge-backrest.svg)](https://hysenlabs.com/projects/garethgeorge-backrest)