Skip to content


Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time

Qubes OS, Borg &

This repo contains a few utility scripts to manage Qubes OS backups using Borg Backup into


Backup of data is essential in any workflow. Two top concerns of any backup strategy are the security and the cost of maintaining backups.

Borg Backup offers a reasonably secure, open source backup software solution. offers special pricing discounts for borg users.

Qubes OS offsers separation of concerns and security domains on your desktop computer.

Let's combine them FTW!


This repo contains template files and scripts to setup your own backup workflow. I am using it for my own workflow, which may or may not be appropriate for your own needs.

Please review all files and scripts and adapt this flow to your preferred backup strategy.

I make no guarantees of backup performance, reliability and integrity if you follow this template.



This assumes the following:

  • You have setup an account at (or any backup provider that allows ssh+borg access);
  • You have installed borg and borgmatic;
  • If using Qubes, you have enabled the crond service on the AppVMs you'll be making backup from.

1. Setup

  • On your personal ~/.ssh/config file, create an entry named "rsyncnet" (see item 3 below) to serve as alias to connect to for administration purposes;
  • Create the root repository dir in (ssh rsyncnet mkdir -p repos);
  • Copy (or link) the public part of the ssh key you'll use to connect to to the file;
  • Create the file template/bakserver to serve as template for the AppVMs to connect to the backup server (see item 3 below - use bakserver.template as an example).

2. VM Backup

For each VM you'll want to backup data from, create a new key:

# Replace REPO-NAME. The full path on rsyncnet will be repos/REPO-NAME

# Example
$ ./ vm-personal

During key creation you'll need to enter the passphrase to the repo. I suggest generating and storing the passphrase on KeePassX on your VaultVM with high entropy parameters.

The script will also display your passphrase, so only do this when you can be certain nobody is watching your screen.

After generating the key for the new repo, run to generate an authorized_keys file to be installed on On the first few runs, manually check if the file is correct (specially the admin key section - if that gets messed up you may get locked out of the remote server).

Upload the file to with

The host-keys/REPO-NAME dir should be copied and installed on the target AppVM (see item 4 below). Also, modify the file borgmatic.cfg to your needs (at a minimum you'll need to modify the source_directories section).

3. SSH Config

I usually config ssh connection aliases on ~/.ssh/config.d and then assemble the file ~/.ssh/config by concatenating everything in this dir.

The alias to connect to for administration purposes (i.e. anything except backing up from a VM) should look like:

# File ~/.ssh/config.d/rsyncnet
Host rsyncnet 
  IdentityFile ~/.ssh/rsyncnet-admin-key.openssh

The template file template/bakserver should have the HostName and User fields filled with the same information (you can use the bakserver.sample file as an example).

To generate the actual ssh config file run:

$ cat ~/.ssh/config.d/* > ~/.ssh/config

If you don't use this method for configuring aliases, you'll need to manually edit your ~/.ssh/config file on your admin VM and on all the AppVMs used to backup data with the appropriate aliases.

Another alternative is to start using this method by copying your existing ~/.ssh/config into the ~/.ssh/config.d dir and taking from there.

4. AppVM Configuration

The dir generated by the script should have everything needed to configure an AppVM to backup to The files are:

  • bak.crontab: Crontab entry for automated backups;
  • bakserver: The ssh config the VM will use to connect to the backup server (see item 3 above);
  • borgbak: A simple script copied to ~/bin to allow faster usage of borg on (seem item 5 below);
  • borgmatic.cfg: The borgmatic config file;
  • borgpass: The password for the backup repo in plain text (see security considerations below);
  • borgrepo: The name of the remote backup repo;
  • Install script (read it to see what it does and if it's appropriate to your use case);
  • REPO-NAME.openssh: The private key to backup;
  • The public key to install on the backup server.

This dir is meant to be installed on the target VM as ~/.ssh/backups. Changing this location means changing the location of the key on the bakserver alias and the borgbak utility.

5. The borgbak script

The command line to execute any borg action on looks like the following:

$ borg $ACTION --remote-path=borg1 bakserver:repos/$REPO(:$ARCHIVE) $REST
Password: (type password)

It can get tiring typing that all time, so the borgbak script simplifies it by extracting the repo from the file ~/.ssh/backups/borgrepo, the passphrase from the file ~/.ssh/backups/borgpass and the action, archive and rest of the command from the next arguments.

The most commonly used borg commands get simplified to:

$ borgbak list
$ borgbak list personal-2017-08-03T12:56:09.339289
$ borgbak info personal-2017-08-03T12:56:09.339289
$ borgbak extract personal-2017-08-03T12:56:09.339289 home/user/test-file

Complex borg actions may still be issued by using the original borg command and passing the full arguments.

Security Remarks

A few security considerations for this script. They do not represent all potential issues on a given borg installation, only the most relevant ones for this workflow.

Some of the decisions made by this flow can be modified to suit your desired security profile.

Borg Operation Mode

This script currently uses the repokey encryption mode of borg, which means the encryption key file (the actual key bits) is stored on the server. The key file is protected by the key passphrase, which never leaves the client.

If the backup server is compromised, the key file can be extracted. However, that alone should not give access to the actual key bits, as long as the passphrase is strong enough (or if there is a bug or vulnerability on borg's encryption algorithm).

This workflow could be modified to use keyfile mode by generating the key locally (in the script). Using this mode, you must also backup the key file on a different medium or risk losing access to your backups (see remarks about backup accessibility).

SSH Command Restriction

This script assembles an authorized_keys file to be installed on the backup server that restricts the actions of the individual client backup keys to the borg command on a given repo dir.

This is the recommended procedure when multiple sources will write to the same backup server, as it allows each source to have an independent ssh key and borg passphrase, and compromise of one source does not automatically compromise all.

The exception to this is the maintenance key used to connect to the server for full access. Obviously, this key is specially important, should be stored encrypted and only used from a trusted machine.

The current ssh line assembled for each client is the following (minus the newlines):

  cd repos/$HOST;
  borg1 serve --append-only --restrict-to-path repos/$HOST\",
ssh-rsa AAAA...

Append-only Mode

Another security feature of the assembled authorized_keys is to restrict every access of the backup clients to append-only mode.

A compromise of the client VM, the ssh key and/or the borg passphrase does not automatically imply loss of data, although it may imply disclosure of the encrypted data.

All remarks concerning Borg's append-only mode apply.

Plaintext Passphrase

The passphrase used to access a given borg repo is stored as plain text in the target VM and in the VM used to create the keys.

The passphrase must be stored as plaintext in order to allow automated backups.

If the VM (or a given backup client) is compromised and this password is leaked, the backups from this VM are also compromised.

Therefore, each VM (or backup client host) must use a different, strong passphrase such that the compromise of one passphrase does not imply the compromise of all backup repos.

SSH Keys

The same considerations apply to the ssh keys used to connect to the backup server as the ones to the borg repo passphrase.

The keys must be passwordless (in order to allow automated backups) and also unique among the clients such that a compromise of one key does not immediately give access to the others.

Backup Maintenance VM

It is the recommended Qubes philosophy to use a dedicated VM for a given set of activities.

One possible application of this is to use a VM dedicated to backup maintenance (the VM which will have the admin-keys.openssh) and this VM will generate the keys and passphrases for the other VMs.

In this situation, if the backup maintenance VM is compromised, all keys and passphrases may be compromised.

To mitigate against this, after verifying that the new repo is working, you should remove all files (except the *.pub files) from the host-keys dir.

You could also generate the ssh key and passphrase on the client VM and initialize the repository from there.

Backup Accessibility

Losing access to the backed up data in the event of loss of the primary data is as bad as not having a backup in the first place.

To prevent losing access to your backups using this workflow on you should have an offline, secondary backup of the relevant keys and passphrases.

At the very least, you should have an offline copy of:

  • The e-mail credentials used to register on
  • The passphrases for each borg repo
  • The user password

You should also try to maintain copies of:

  • The admin private key used to perform backup maintenance
  • The key file for each borg repo

This should be stored offline (preferably on multiple media) and on a different site. Obviously, you should also store all this information encrypted with a strong master password.

One possible approach to achieve this is to save all this information in a KeePassX file and then print it using PyPaperBak.

Additional Backup Copies

You can also further mitigate risk of data loss by having a copy of all data on either locally on another computer/disk or on another provider. supports the s3cmd utility, so you could clone your data to S3 or Glacier.

Another option is to rsync it to some other backup provider.

Another strategy altogether would be to use Borg to backup to a local computer and then rclone it to (or backblaze or S3).


Qubes OS + Borg + backup strategy scripts







No releases published


No packages published