Open-source project
restic/rest-server avatar
restic/rest-server

rest-server is restic's REST backend as a single Go binary

Rest Server is a high performance HTTP server that implements restic's REST backend API.

1,525 stars180 forksGoBSD-2-Clause

At a glance

What is it?
rest-server implements restic's REST backend API as a high performance HTTP server in Go, so a restic client can back up to a machine you run, over a rest: URL, with .htpasswd authentication, optional TLS, an append-only mode that cannot delete existing backups, per-user repository isolation, a quota directory and Prometheus metrics. The default data directory is a temporary directory, and the README says plainly that backups started there are lost.
Who is it for?
rest-server suits a team that wants backups on hardware it controls, at a scale where a bucket is overkill and a single binary on a small server is enough, and that wants the option of a repository which cannot be deleted through the API. It does not suit a team that wants offsite durability, since the bytes live on the machine running the server, and it is the wrong choice if the server is the same box that fails.
Can I use it commercially?
Yes. BSD-2-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 5 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

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

Editorial analysis

The default data directory loses your backups

Rest Server is described as a high performance HTTP server that implements restic's REST backend API, providing a secure and efficient way to back up data remotely using the restic backup client over a rest: URL.

The mechanism is deliberately thin. The server exposes the REST API that the restic client speaks, stores the repository as ordinary files, and gets out of the way. That is what makes it a good fit for a home server, a NAS, a single VPS or a small cluster, and it is also why the storage question is the whole design decision.

The README then says something that should be on the front of the binary. By default the server persists backup data in the OS temporary directory, /tmp/restic on Linux and BSD and others and %TEMP%\restic on Windows, and if rest-server is launched using the default path, all backups will be lost.

That is not a subtlety. A temporary directory is exactly where a reboot, a cleanup job or a full disk will take your repository, and the server will keep accepting new backups in the meantime, so the failure is silent until the day you need to restore. The documented fix is to pass a real path, and the example does it in one argument:

sh
rest-server --path /user/home/backup --no-auth

The --no-auth in that example is for a test, and the next section is about why it should not survive into production.

Authentication is on unless you turn it off, and the server refuses to start without it

The server authenticates users with a .htpasswd file, the same format Apache uses. By default the file is looked for at the root of the persistence directory, and the location can be changed with the --htpasswd-file option.

The failure mode is the important part. If you want to disable authentication, you must add the --no-auth flag, and if that flag is not specified and the .htpasswd cannot be opened, rest-server will refuse to start. The README then notes that in older versions, up to 0.9.7, the flag did not exist and the server disabled authentication if the .htpasswd was missing or could not be opened. In other words, an old version fails open where a current one fails closed, which matters if you are reading an old tutorial.

Creating the file needs the htpasswd program from Apache's http-tools, and only bcrypt and SHA encryption methods are supported, so you choose the hash with the -B flag for bcrypt, which the README calls very secure, or -s for SHA, which it calls insecure by today's standards:

sh
htpasswd -B -c .htpasswd username

The -c creates the file, and to append a new user you omit that argument. The bcrypt recommendation is the one to follow.

Two more flags control access. The --group-accessible-repos flag lets the filesystem group be able to access repository files, and the --private-repos flag restricts users to their own repository, where access is granted only when a subdirectory with the same name as the user appears in the repository URL. The example is precise about the boundary: rest:https://foo:pass@host:8000/foo and the trailing slash variant are granted, while rest:https://foo:pass@host:8000/ and rest:https://foo:pass@host:8000/foobar/ are denied, and users can create their own subrepositories such as /foo/bar/.

There is also a --proxy-auth-username flag for proxy based authentication, which is the sensible option when the server sits behind something that already authenticates.

Basic authentication over plain HTTP is the part to fix first

The README is blunt about the default. By default the server uses the HTTP protocol, and this is not very secure since with Basic Authentication the user name and password will be sent in clear text in every request.

The fix is the --tls flag, with a key pair placed at the root of the persistence directory, or the pair given explicitly with --tls-cert and --tls-key, and the minimum TLS version raised with --tls-min-ver 1.3, since the default is 1.2.

For testing, the README notes that a signed certificate is normally required by the restic backend, and gives a command for generating a password-less unsigned key pair:

sh
openssl req -newkey rsa:2048 -nodes -x509 -keyout private_key -out public_key -days 365 -addext "subjectAltName = IP:127.0.0.1,DNS:yourdomain.com"

You can leave the defaults in the openssl dialog alone, and you can omit the IP:127.0.0.1 if you do not need to reach the server through SSH tunnels.

The operational consequence of a self-signed certificate is the part that catches people out. To use this server with restic you pass --cacert public_key, which means that with a self-signed certificate you have to distribute the public_key file to every restic client. That is a distribution problem before it is a backup problem, and it is why a real certificate from a public authority, or a certificate your clients already trust, is worth the extra step.

Two flags in the help output are worth knowing for the same reason. The --no-verify-upload flag disables the integrity check of uploaded data, and the help text says not to enable it unless the rest-server runs on a very low-power device. And --max-size sets the maximum size of the repository in bytes, which is a quota at the server level rather than at the account level.

Append-only mode is the answer to a backup server you cannot trust

Two flags turn the server from a file store into something you can put policy around, and they are the strongest argument for running it yourself.

The --append-only mode allows creation of new backups but prevents deletion and modification of existing backups, and the README says this can be useful when backing up systems that have a potential of being hacked. That is a real property, because most backup storage, whether it is an object store or a directory, is writable by the credential that writes to it. An append-only server cannot be used to erase the evidence, which is the specific scenario that turns a ransomware incident into a total loss.

The --private-repos flag is the isolation mechanism, and it is worth understanding precisely, because the boundary is subtle. Access is granted only when a subdirectory matching the user name appears in the repository URL, and a URL that names a different user's subdirectory is denied rather than served. The naming therefore carries the authorisation, which means the URL is part of the security model and not just a path.

The --max-size flag belongs to the same family. It bounds the size of the repository in bytes, which is a blunt instrument compared with per-user quotas, but it is a limit that exists at the server rather than in the client, and the repository also has a quota/ directory in the source tree, which suggests the storage layer keeps per-repository accounting of its own.

For the observability side, the --prometheus flag enables metrics and --prometheus-no-auth disables authentication for the /metrics endpoint, which is the usual arrangement when the scraper runs inside the same network. The repository ships an example directory called compose-with-grafana, so the intended monitoring path is a metrics scrape into a Grafana dashboard.

The directory layout is the same one restic uses locally

The architectural property that makes rest-server pleasant to use is stated in one line: Rest Server uses exactly the same directory structure as local backend, so you should be able to access it both locally and via HTTP, even simultaneously.

That has two consequences. The first is operational, and it is the good one. The repository on disk is a normal restic repository, so you can mount it, back it up, inspect it, copy it to another machine, or run restic against it with the local backend, without going through HTTP. A repository that only exists behind an API is a repository you can only reach through the program that wrote it.

The second consequence is a security one that follows from the same property. Because the files are ordinary files in a directory, the server's access control and the filesystem's access control are two separate gates, and the --group-accessible-repos flag exists to let the filesystem group participate. A user who can read the persistence directory directly can read every repository in it, whatever the .htpasswd file says. So the server's authentication is not a substitute for filesystem permissions on the data directory, and for a shared host the two have to be configured together.

That is also why the append-only mode has to be enforced at the level it is enforced. Restricting the API while leaving the files writable is a policy that a compromised client can route around, since the same repository is reachable locally.

Building it, and the container image

The build requirement is Go 1.26 or higher, and the README says the only tested compiler is the official Go compiler. The build command is a single line, with CGO disabled so the binary is static:

bash
CGO_ENABLED=0 go build -o rest-server ./cmd/rest-server

The client requirement is stated next to it: the required version of the restic backup client to use with rest-server is v0.7.1 or higher.

The Dockerfile builds the same binary from a golang:alpine builder and ships it on alpine:3.24, with the data directory at /data, the password file at /data/.htpasswd, apache2-utils and tzdata installed so that user creation and timezones work, a volume declared at /data, port 8000 exposed and the entrypoint script as the command. The docker/ directory holds that entrypoint script along with create_user and delete_user helpers, which is how the container manages .htpasswd entries for you.

The examples directory shows the deployment shapes the project expects. There is a systemd directory with a service file for a plain Linux host, a compose-with-grafana directory for the monitoring path, and a bsd directory for the BSD case.

The rest of the tree is the server itself. The cmd/ directory holds the command, handlers.go the HTTP handlers, htpasswd.go the authentication, metrics.go the Prometheus exposition, mux.go the routing, and the repo/ and quota/ directories the storage layer. The build tooling is goreleaser with a Dockerfile.goreleaser variant, and there is a golangci lint configuration, a VERSION file and a changelog/ directory alongside CHANGELOG.md and a Release.md describing the release process.

Where it fits, and what it costs

The licence is BSD-2-Clause, the repository is not archived, and the last push was on 2026-10-18. The published releases are v0.14.0 from 2025-05-31, v0.13.0 from 2024-07-26 and v0.12.1 from 2023-07-09, so the version line moves slowly and the last release is a little over a year old while commits continue to land on master.

The fit is narrow and clear. rest-server is for a team that wants backups on hardware it controls, that would rather not pay for object storage for a small estate, and that wants the repository to be a directory it can also read with a local restic client. It is also the natural fit for a machine that cannot reach the internet reliably, since the server can live on the same network as the client.

The costs are equally clear. The server is the single point of failure for every repository behind it, and a repository is only as safe as the disk it sits on and the backups of that disk. The append-only mode helps with one threat and does nothing for another, since a machine that is hacked can still be used to write new backups that fill the volume, and the --max-size flag is a blunt instrument against that.

The alternative to running a server at all is to point restic at a storage backend that someone else runs, and the choice between them is a choice about who holds the bytes and who is responsible for their availability. restic also has a local backend, which is the same directory layout without the HTTP layer, and that is the fallback if the server's policy features are not needed and the client is on the same machine.

For a team that has decided to keep the data on its own hardware, the practical checks are short. Confirm the persistence path is a real volume and not the default temporary directory. Confirm the .htpasswd file exists and is readable, since the server will not start without it unless you disable authentication deliberately. Turn on TLS and distribute the certificate to the clients. And decide whether append-only and per-user isolation are worth the configuration, because they are the two features you cannot add later without moving the data.

Editorial conclusion

rest-server suits a team that wants backups on hardware it controls, at a scale where a bucket is overkill and a single binary on a small server is enough, and that wants the option of a repository which cannot be deleted through the API. It does not suit a team that wants offsite durability, since the bytes live on the machine running the server, and it is the wrong choice if the server is the same box that fails. Verify first that the persistence directory is a real path rather than the default temporary directory, that the .htpasswd file is reachable and its password hash uses bcrypt, and that TLS is enabled and the client is given the certificate through the cacert option, because plain HTTP sends Basic Authentication credentials in clear text on every request.

Frequently asked questions

What is rest-server and what does it do?

It is a high performance HTTP server written in Go that implements restic's REST backend API, giving a secure and efficient way to back up data remotely using the restic backup client over a rest: URL.

Where does rest-server store the backup data by default?

In the OS temporary directory, /tmp/restic on Linux and BSD and %TEMP%\restic on Windows, and the README warns that if rest-server is launched with the default path all backups will be lost. Pass --path to use a persistent directory.

How do I create the user file for rest-server?

With the htpasswd program from Apache's http-tools, for example htpasswd -B -c .htpasswd username, omitting -c to append a user. Only bcrypt and SHA are supported, and the README describes -B as very secure and -s as insecure by today's standards.

What does the append-only mode do?

It allows creation of new backups but prevents deletion and modification of existing ones, which the README suggests for systems that have a potential of being hacked.

How do I build rest-server and what does it need?

Go 1.26 or higher, with the official Go compiler the only tested one, and the build command CGO_ENABLED=0 go build -o rest-server ./cmd/rest-server. The restic client must be v0.7.1 or higher.

Official sources

  1. Issues
  2. License: BSD-2-Clause
  3. README
  4. Releases
  5. restic/rest-server on GitHub
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/restic-rest-server.svg)](https://hysenlabs.com/projects/restic-rest-server)

Was this useful?