2017-06-09 10:00:46 -04:00
|
|
|
|
.. include:: ../global.rst.inc
|
|
|
|
|
|
.. highlight:: none
|
2023-06-11 17:03:21 -04:00
|
|
|
|
.. _central-backup-server:
|
2017-06-09 10:00:46 -04:00
|
|
|
|
|
|
|
|
|
|
Central repository server with Ansible or Salt
|
|
|
|
|
|
==============================================
|
|
|
|
|
|
|
2025-08-23 18:21:57 -04:00
|
|
|
|
This section gives an example of how to set up a Borg repository server for multiple
|
2017-06-09 10:00:46 -04:00
|
|
|
|
clients.
|
|
|
|
|
|
|
remove ssh:// and socket:// remote repository for current repos
The modern client/server transport (RemoteRepository served by `borg serve`
over an msgpack RPC protocol) is now redundant for current (borg 2) repos:
its functionality is replaced by rest:// (which can tunnel over ssh to a
remote borgstore REST server).
Remove the modern RemoteRepository (both ssh:// and socket://) entirely.
Legacy v1 (borg 1.x) repos remain reachable over ssh:// via the separate
LegacyRemoteRepository client, and `borg serve` / RepositoryServer is kept,
trimmed to the legacy-only path, so a remote borg2 can still serve a v1 repo
for `borg transfer --from-borg1`.
Details:
- remote.py: delete RemoteRepository, SleepingBandwidthLimiter and the `api`
decorator; trim RepositoryServer to legacy-only (drop modern _rpc_methods,
socket serving, non-legacy open() branch); keep cache_if_remote /
RepositoryCache / RepositoryNoCache (used by all repos).
- get_repository(): non-legacy ssh:// now raises a clear "use rest://" error;
socket:// route and the global --socket option removed.
- parseformat: drop the socket:// scheme (now an invalid location).
- borg serve: keep the command (serves legacy v1 ssh only); update epilog.
- borg version: drop modern remote query; keep legacy ssh path.
- update isinstance/import sites (cache, archive, fuse/hlfuse, analyze/compact,
archiver __init__ -> LegacyRemoteRepository.RPCError).
- tests/docs updated; obsolete socket serve test removed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 02:04:59 -04:00
|
|
|
|
.. note::
|
|
|
|
|
|
|
|
|
|
|
|
This example predates Borg 2 and uses the legacy ``ssh://`` transport (served
|
|
|
|
|
|
by ``borg serve``) and ``borg init``. With Borg 2, the ``ssh://`` transport is
|
|
|
|
|
|
only used for legacy borg 1.x (v1) repositories; for current repositories use a
|
|
|
|
|
|
``rest://`` repository instead (Borg connects via ssh and runs a borgstore REST
|
|
|
|
|
|
server on the remote host), and use ``borg repo-create`` instead of ``borg init``.
|
|
|
|
|
|
|
2017-06-09 10:00:46 -04:00
|
|
|
|
Machines
|
|
|
|
|
|
--------
|
|
|
|
|
|
|
2025-08-23 18:21:57 -04:00
|
|
|
|
This section uses multiple machines, referred to by their
|
|
|
|
|
|
respective fully qualified domain names (FQDNs).
|
2017-06-09 10:00:46 -04:00
|
|
|
|
|
|
|
|
|
|
* The backup server: `backup01.srv.local`
|
|
|
|
|
|
* The clients:
|
|
|
|
|
|
|
|
|
|
|
|
- John Doe's desktop: `johndoe.clnt.local`
|
2025-08-23 18:21:57 -04:00
|
|
|
|
- Web server 01: `web01.srv.local`
|
2017-06-09 10:00:46 -04:00
|
|
|
|
- Application server 01: `app01.srv.local`
|
|
|
|
|
|
|
|
|
|
|
|
User and group
|
|
|
|
|
|
--------------
|
|
|
|
|
|
|
2025-08-23 18:21:57 -04:00
|
|
|
|
The repository server should have a single UNIX user for all the clients.
|
2017-06-09 10:00:46 -04:00
|
|
|
|
Recommended user and group with additional settings:
|
|
|
|
|
|
|
|
|
|
|
|
* User: `backup`
|
|
|
|
|
|
* Group: `backup`
|
2025-08-23 18:21:57 -04:00
|
|
|
|
* Shell: `/bin/bash` (or another shell capable of running the `borg serve` command)
|
2017-06-09 10:00:46 -04:00
|
|
|
|
* Home: `/home/backup`
|
|
|
|
|
|
|
2025-08-23 18:21:57 -04:00
|
|
|
|
Most clients should initiate a backup as the root user to capture all
|
|
|
|
|
|
users, groups, and permissions (e.g., when backing up `/home`).
|
2017-06-09 10:00:46 -04:00
|
|
|
|
|
|
|
|
|
|
Folders
|
|
|
|
|
|
-------
|
|
|
|
|
|
|
2025-08-23 18:21:57 -04:00
|
|
|
|
The following directory layout is suggested on the repository server:
|
2017-06-09 10:00:46 -04:00
|
|
|
|
|
|
|
|
|
|
* User home directory, /home/backup
|
|
|
|
|
|
* Repositories path (storage pool): /home/backup/repos
|
2025-08-23 18:21:57 -04:00
|
|
|
|
* Clients’ restricted paths (`/home/backup/repos/<client fqdn>`):
|
2017-06-09 10:00:46 -04:00
|
|
|
|
|
|
|
|
|
|
- johndoe.clnt.local: `/home/backup/repos/johndoe.clnt.local`
|
|
|
|
|
|
- web01.srv.local: `/home/backup/repos/web01.srv.local`
|
|
|
|
|
|
- app01.srv.local: `/home/backup/repos/app01.srv.local`
|
|
|
|
|
|
|
|
|
|
|
|
Restrictions
|
|
|
|
|
|
------------
|
|
|
|
|
|
|
|
|
|
|
|
Borg is instructed to restrict clients into their own paths:
|
|
|
|
|
|
``borg serve --restrict-to-path /home/backup/repos/<client fqdn>``
|
|
|
|
|
|
|
|
|
|
|
|
The client will be able to access any file or subdirectory inside of ``/home/backup/repos/<client fqdn>``
|
|
|
|
|
|
but no other directories. You can allow a client to access several separate directories by passing multiple
|
2017-06-17 06:27:53 -04:00
|
|
|
|
``--restrict-to-path`` flags, for instance: ``borg serve --restrict-to-path /home/backup/repos/<client fqdn> --restrict-to-path /home/backup/repos/<other client fqdn>``,
|
2017-06-09 10:00:46 -04:00
|
|
|
|
which could make sense if multiple machines belong to one person which should then have access to all the
|
|
|
|
|
|
backups of their machines.
|
|
|
|
|
|
|
2025-08-23 18:21:57 -04:00
|
|
|
|
Only one SSH key per client is allowed. Keys are added for ``johndoe.clnt.local``, ``web01.srv.local`` and
|
|
|
|
|
|
``app01.srv.local``. They will access the backup under a single UNIX user account as
|
2017-06-09 10:00:46 -04:00
|
|
|
|
``backup@backup01.srv.local``. Every key in ``$HOME/.ssh/authorized_keys`` has a
|
2025-08-23 18:21:57 -04:00
|
|
|
|
forced command and restrictions applied, as shown below:
|
2017-06-09 10:00:46 -04:00
|
|
|
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
|
|
|
|
command="cd /home/backup/repos/<client fqdn>;
|
|
|
|
|
|
borg serve --restrict-to-path /home/backup/repos/<client fqdn>",
|
2017-06-23 07:28:49 -04:00
|
|
|
|
restrict <keytype> <key> <host>
|
2017-06-09 10:00:46 -04:00
|
|
|
|
|
|
|
|
|
|
.. note:: The text shown above needs to be written on a single line!
|
|
|
|
|
|
|
2025-08-23 18:21:57 -04:00
|
|
|
|
The options added to the key perform the following:
|
2017-06-09 10:00:46 -04:00
|
|
|
|
|
|
|
|
|
|
1. Change working directory
|
|
|
|
|
|
2. Run ``borg serve`` restricted to the client base path
|
|
|
|
|
|
3. Restrict ssh and do not allow stuff which imposes a security risk
|
|
|
|
|
|
|
2025-08-23 18:21:57 -04:00
|
|
|
|
Because of the ``cd`` command, the server automatically changes the current
|
|
|
|
|
|
working directory. The client then does not need to know the absolute
|
2017-06-09 10:00:46 -04:00
|
|
|
|
or relative remote repository path and can directly access the repositories at
|
2024-09-09 22:49:41 -04:00
|
|
|
|
``ssh://<user>@<host>/./<repo>``.
|
2017-06-09 10:00:46 -04:00
|
|
|
|
|
2025-08-23 18:21:57 -04:00
|
|
|
|
.. note:: The setup above ignores all client-given command line parameters
|
|
|
|
|
|
that are normally appended to the `borg serve` command.
|
2017-06-09 10:00:46 -04:00
|
|
|
|
|
|
|
|
|
|
Client
|
|
|
|
|
|
------
|
|
|
|
|
|
|
|
|
|
|
|
The client needs to initialize the `pictures` repository like this:
|
|
|
|
|
|
|
2019-08-09 17:13:11 -04:00
|
|
|
|
::
|
|
|
|
|
|
|
2024-09-09 22:49:41 -04:00
|
|
|
|
borg init ssh://backup@backup01.srv.local/./pictures
|
2017-06-09 10:00:46 -04:00
|
|
|
|
|
2025-08-23 18:21:57 -04:00
|
|
|
|
Or with the full path (this should not be used in practice; it is only for demonstration purposes).
|
|
|
|
|
|
The server automatically changes the current working directory to the `<client fqdn>` directory.
|
2017-06-09 10:00:46 -04:00
|
|
|
|
|
2019-08-09 17:13:11 -04:00
|
|
|
|
::
|
|
|
|
|
|
|
2024-09-09 22:49:41 -04:00
|
|
|
|
borg init ssh://backup@backup01.srv.local/home/backup/repos/johndoe.clnt.local/pictures
|
2017-06-09 10:00:46 -04:00
|
|
|
|
|
2025-08-23 18:21:57 -04:00
|
|
|
|
When `johndoe.clnt.local` tries to access a path outside its restriction, the following error is raised.
|
|
|
|
|
|
John Doe tries to back up into the web01 path:
|
2017-06-09 10:00:46 -04:00
|
|
|
|
|
2019-08-09 17:13:11 -04:00
|
|
|
|
::
|
|
|
|
|
|
|
2024-09-09 22:49:41 -04:00
|
|
|
|
borg init ssh://backup@backup01.srv.local/home/backup/repos/web01.srv.local/pictures
|
2017-06-09 10:00:46 -04:00
|
|
|
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
|
|
|
|
~~~ SNIP ~~~
|
|
|
|
|
|
Remote: borg.remote.PathNotAllowed: /home/backup/repos/web01.srv.local/pictures
|
|
|
|
|
|
~~~ SNIP ~~~
|
|
|
|
|
|
Repository path not allowed
|
|
|
|
|
|
|
|
|
|
|
|
Ansible
|
|
|
|
|
|
-------
|
|
|
|
|
|
|
|
|
|
|
|
Ansible takes care of all the system-specific commands to add the user, create the
|
2020-11-06 08:28:27 -05:00
|
|
|
|
folder, install and configure software.
|
2017-06-09 10:00:46 -04:00
|
|
|
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
|
|
|
|
- hosts: backup01.srv.local
|
|
|
|
|
|
vars:
|
|
|
|
|
|
user: backup
|
|
|
|
|
|
group: backup
|
|
|
|
|
|
home: /home/backup
|
|
|
|
|
|
pool: "{{ home }}/repos"
|
|
|
|
|
|
auth_users:
|
|
|
|
|
|
- host: johndoe.clnt.local
|
|
|
|
|
|
key: "{{ lookup('file', '/path/to/keys/johndoe.clnt.local.pub') }}"
|
|
|
|
|
|
- host: web01.clnt.local
|
|
|
|
|
|
key: "{{ lookup('file', '/path/to/keys/web01.clnt.local.pub') }}"
|
|
|
|
|
|
- host: app01.clnt.local
|
|
|
|
|
|
key: "{{ lookup('file', '/path/to/keys/app01.clnt.local.pub') }}"
|
|
|
|
|
|
tasks:
|
2020-11-02 04:09:28 -05:00
|
|
|
|
- package: name=borg state=present
|
2017-06-09 10:00:46 -04:00
|
|
|
|
- group: name="{{ group }}" state=present
|
|
|
|
|
|
- user: name="{{ user }}" shell=/bin/bash home="{{ home }}" createhome=yes group="{{ group }}" groups= state=present
|
|
|
|
|
|
- file: path="{{ home }}" owner="{{ user }}" group="{{ group }}" mode=0700 state=directory
|
|
|
|
|
|
- file: path="{{ home }}/.ssh" owner="{{ user }}" group="{{ group }}" mode=0700 state=directory
|
|
|
|
|
|
- file: path="{{ pool }}" owner="{{ user }}" group="{{ group }}" mode=0700 state=directory
|
|
|
|
|
|
- authorized_key: user="{{ user }}"
|
|
|
|
|
|
key="{{ item.key }}"
|
2017-06-23 07:28:49 -04:00
|
|
|
|
key_options='command="cd {{ pool }}/{{ item.host }};borg serve --restrict-to-path {{ pool }}/{{ item.host }}",restrict'
|
2017-06-09 10:00:46 -04:00
|
|
|
|
with_items: "{{ auth_users }}"
|
|
|
|
|
|
- file: path="{{ home }}/.ssh/authorized_keys" owner="{{ user }}" group="{{ group }}" mode=0600 state=file
|
|
|
|
|
|
- file: path="{{ pool }}/{{ item.host }}" owner="{{ user }}" group="{{ group }}" mode=0700 state=directory
|
|
|
|
|
|
with_items: "{{ auth_users }}"
|
|
|
|
|
|
|
|
|
|
|
|
Salt
|
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
|
|
This is a configuration similar to the one above, configured to be deployed with
|
|
|
|
|
|
Salt running on a Debian system.
|
|
|
|
|
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
|
|
|
|
Install borg backup from pip:
|
|
|
|
|
|
pkg.installed:
|
|
|
|
|
|
- pkgs:
|
|
|
|
|
|
- python3
|
|
|
|
|
|
- python3-dev
|
|
|
|
|
|
- python3-pip
|
|
|
|
|
|
- python-virtualenv
|
|
|
|
|
|
- libssl-dev
|
|
|
|
|
|
- openssl
|
|
|
|
|
|
- libacl1-dev
|
|
|
|
|
|
- libacl1
|
|
|
|
|
|
- build-essential
|
|
|
|
|
|
- libfuse-dev
|
|
|
|
|
|
- fuse
|
|
|
|
|
|
- pkg-config
|
|
|
|
|
|
pip.installed:
|
|
|
|
|
|
- pkgs: ["borgbackup"]
|
|
|
|
|
|
- bin_env: /usr/bin/pip3
|
|
|
|
|
|
|
|
|
|
|
|
Setup backup user:
|
|
|
|
|
|
user.present:
|
|
|
|
|
|
- name: backup
|
|
|
|
|
|
- fullname: Backup User
|
|
|
|
|
|
- home: /home/backup
|
|
|
|
|
|
- shell: /bin/bash
|
|
|
|
|
|
# CAUTION!
|
|
|
|
|
|
# If you change the ssh command= option below, it won't necessarily get pushed to the backup
|
|
|
|
|
|
# server correctly unless you delete the ~/.ssh/authorized_keys file and re-create it!
|
|
|
|
|
|
{% for host in backupclients %}
|
|
|
|
|
|
Give backup access to {{host}}:
|
|
|
|
|
|
ssh_auth.present:
|
|
|
|
|
|
- user: backup
|
|
|
|
|
|
- source: salt://conf/ssh-pubkeys/{{host}}-backup.id_ecdsa.pub
|
|
|
|
|
|
- options:
|
|
|
|
|
|
- command="cd /home/backup/repos/{{host}}; borg serve --restrict-to-path /home/backup/repos/{{host}}"
|
2017-06-23 07:28:49 -04:00
|
|
|
|
- restrict
|
2017-06-09 10:00:46 -04:00
|
|
|
|
{% endfor %}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Enhancements
|
|
|
|
|
|
------------
|
|
|
|
|
|
|
2022-12-28 19:01:48 -05:00
|
|
|
|
As this section only describes a simple and effective setup, it could be further
|
2017-06-09 10:00:46 -04:00
|
|
|
|
enhanced when supporting (a limited set) of client supplied commands. A wrapper
|
|
|
|
|
|
for starting `borg serve` could be written. Or borg itself could be enhanced to
|
|
|
|
|
|
autodetect it runs under SSH by checking the `SSH_ORIGINAL_COMMAND` environment
|
|
|
|
|
|
variable. This is left open for future improvements.
|
|
|
|
|
|
|
|
|
|
|
|
When extending ssh autodetection in borg no external wrapper script is necessary
|
|
|
|
|
|
and no other interpreter or application has to be deployed.
|
|
|
|
|
|
|
|
|
|
|
|
See also
|
|
|
|
|
|
--------
|
|
|
|
|
|
|
2020-12-19 14:11:32 -05:00
|
|
|
|
* `SSH Daemon manpage <https://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man8/sshd.8>`_
|
2017-06-09 10:00:46 -04:00
|
|
|
|
* `Ansible <https://docs.ansible.com>`_
|
|
|
|
|
|
* `Salt <https://docs.saltstack.com/>`_
|