borg-serve(1)
π NAME π
borg-serve β starts up in server mode, bestie. Like, this command is usually not run by hand, it just vibes there doing its job. π
β¨ SYNOPSIS β¨
borg [common options] serve [options]
π¦ DESCRIPTION π¦
Okay so this command spins up a repository server process. Normally you never type it yourself β a borg client starts it automatically over SSH, and it just chills and runs until that SSH connection gets yeeted. π
It works in one of two modes:
- default (no option at all): it serves a legacy (borg 1.x / v1) repository using the legacy RPC protocol. A borg client using an
ssh://repository together with--from-borg1(thinkborg transfer --from-borg1) fires this up automatically via SSH. It's command-line compatible with borg 1.xborg serve. β - --rest: it serves a current (non-legacy) repository as the server-side component of an
ssh://repository, talking HTTP over stdio. You say which repo to serve with--backend FILE:<path>. A borg client using anssh://repository starts this automatically via SSH. π
Just so we're clear, bestie: in legacy mode, borg serve does not support giving a specific repository via the --repo option or the BORG_REPO environment variable β it's the borg client that picks which repository gets used. No cap. π
ββοΈ
The --permissions option enforces repository permissions. Heads up, it only applies to --rest mode; in legacy mode it gets straight-up ignored, because legacy (borg 1.x) repositories have no permission system at all:
- all: every permission is granted. (This is the default; the permissions system isn't even in play.)
- no-delete: reading and writing are allowed; deleting and overwriting data are not. New archives can be created; existing archives cannot be deleted. New chunks can be added; existing chunks cannot be deleted or overwritten.
- write-only: writing is allowed; reading data is not. New archives can be created; existing archives cannot be read. New chunks can be added; existing chunks cannot be read, deleted, or overwritten.
- read-only: reading is allowed; writing or deleting data is not. Existing archives can be read, but no archives can be created or deleted.
πΈ OPTIONS πΈ
See borg-common(1) for common options of Borg commands.
options
--restβ serve a current (non-legacy) repository as anssh://server (HTTP over stdio). Requires--backend. Without this option, a legacy (borg 1.x) repository is served. π--backend BACKEND_URLβ (with--rest) the backend URL of the repository to serve, e.g.FILE:/path/to/repo.--restrict-to-path PATHβ restrict repository access to PATH. You can pass this multiple times to let the client reach several directories. Access to all subdirectories is granted implicitly; PATH doesn't need to point directly at a repository. π«Ά--restrict-to-repository PATHβ restrict repository access. Only the repository located at PATH (no subdirectories are considered) is reachable. Can be given multiple times to allow the client several repositories. Unlike--restrict-to-path, subdirectories are not accessible; PATH must point directly to a repository location. PATH may be an empty directory, or the last element of PATH may not exist, in which case the client may initialize a repository there. β¨--permissionsβ (with--rest) set the repository permission mode. Overrides theBORG_REPO_PERMISSIONSenvironment variable.
π₯ EXAMPLES π₯
borg serve has special support for ssh forced commands (peep the authorized_keys example below): if the environment variable SSH_ORIGINAL_COMMAND is set, it will ignore some options given on the command line and use the values from that variable instead. This only applies to a carefully controlled allowlist of safe options. That list currently contains:
- Options that control the log level and debug topics printed, like
--verbose,--info,--debug,--debug-topic, etc. --lock-wait, so the client can control how long to wait before giving up and aborting when another process is holding a lock.--backend, so the client can choose which repository it wants to use (seeborg serve --rest). The forced command keeps pinning the restrictions: the client-given backend is validated against--restrict-to-path/--restrict-to-repository.
And like, notably? --rest is not in the allowlist, so the forced command pins the mode (current repositories vs. legacy Borg 1.x repositories). Neither are --restrict-to-path, --restrict-to-repository, --umask and --permissions. π
Environment variables (such as BORG_XXX) contained in the original command sent by the client are not interpreted, just ignored. If BORG_XXX environment variables should be set on the borg serve side, then they have to be set in system-specific locations like /etc/environment or inside the forced command itself (example below). π
# Allow an SSH keypair to run only borg, and only have access to /path/to/repo.
# Use key options to disable unneeded and potentially dangerous SSH functionality.
# This will help to secure an automated remote backup system.
# --rest serves a current (ssh://) repository; without it, a legacy Borg 1.x
# repository would be served. The client supplies --backend FILE:<path>,
# which is validated against --restrict-to-path.
$ cat ~/.ssh/authorized_keys
command="borg serve --rest --restrict-to-path /path/to/repo",restrict ssh-rsa AAAAB3[...]
# Specify repository permissions for an SSH keypair.
$ cat ~/.ssh/authorized_keys
command="borg serve --rest --permissions=read-only",restrict ssh-rsa AAAAB3[...]
# Set a BORG_XXX environment variable on the "borg serve" side
$ cat ~/.ssh/authorized_keys
command="BORG_XXX=value borg serve [...]",restrict ssh-rsa [...]
Note: the examples above use the restrict directive and assume a POSIX compliant shell set as the user's login shell. This automatically blocks potentially dangerous SSH features, even when they get added in a future update. So yeah β this option should be preferred. π
Details about sshd usage: sshd(8) β https://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man8/sshd.8
SSH Configuration
borg serve's pipes (stdin/stdout/stderr) are connected to the sshd process on the server side. If the SSH connection between borg serve and the client gets disconnected or stuck abnormally (say, a network outage π), it can take a long time for sshd to notice the client is gone. In the meantime, sshd keeps running, and because of that, so does the borg serve process holding the lock on the repository. That can make later borg operations on the remote repository fail with the error: Failed to create/acquire the lock.
To avoid all that mess, it's recommended to do this extra SSH configuration:
Either in the client-side ~/.ssh/config file or in the client's /etc/ssh/ssh_config file:
Host backupserver
ServerAliveInterval 10
ServerAliveCountMax 30
Swap backupserver for the hostname, FQDN or IP address of the borg server.
This makes the client send a keepalive to the server every 10 seconds. If 30 consecutive keepalives go out with no response (that's 300 seconds), the SSH client process gets terminated, which causes the borg process to terminate gracefully. π§
In the server-side sshd configuration file (typically /etc/ssh/sshd_config):
ClientAliveInterval 10
ClientAliveCountMax 30
This makes the server send a keepalive to the client every 10 seconds. If 30 consecutive keepalives go out with no response (a time of 300 seconds), the server's sshd process gets terminated, causing the borg serve process to terminate gracefully and release the lock on the repository. π
If you then run borg commands with --lock-wait 600, that gives enough time for the borg serve processes to terminate after the SSH connection is torn down following the 300 second wait for the keepalives to fail.
You may, of course, modify the timeout values demonstrated above to values that suit your environment and use case. β¨
When the client is untrusted, it's a good idea to set the backup user's shell to a simple implementation (/bin/sh is only an example and may or may not be such a simple implementation):
chsh -s /bin/sh BORGUSER
Because the configured shell is used by OpenSSH (https://www.openssh.com/) to execute the command configured through the authorized_keys file using "$SHELL" -c "$COMMAND", setting a minimal shell implementation reduces the attack surface compared to when a feature-rich and complex shell implementation is used. π
π SEE ALSO π
π Author π
The Borg Collective
And that's the whole page, bestie β borg-serve(1) from the borg backup tool, dated 2026-10-07. Go forth and serve responsibly. πβ¨π¦
π¦ where this page comes from
- ubuntu stonking: borgbackup2 2.0.0b25-4 Β· BSD-3-Clause
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms