December 27, 2020

Proof of concept: Backup from Unix to Nixos with Borg

I want to get a directory backed up with borg on my nixos-server ( The client may just be a regular unixoid, doesn't have to be nixos (I am using MacOS for testing). All the commands (unless explicitly stated otherwise) are executed on the client. Both systems have borg installed. This is a tutorial, so most explaining will be about what to do, not why to do it.


We first create the directory with our valuable data.

echo "1234567890" > files_to_back_up/zahlen.txt
echo "abcdefghijklmnopqrstuvwxyz" > files_to_back_up/buchstaben.txt

For borg to access the server without a password we need to create a keyfile pair (on the client). Name it however you want.

ssh-keygen -N '' -t ed25519 -f key_backups_of_NUE-MAC-087_id_ed25519
Generating public/private ed25519 key pair.
Your identification has been saved in key_backups_of_NUE-MAC-087_id_ed25519.
Your public key has been saved in
The key fingerprint is:
SHA256:KAkg+ve2A+D9TWYYdlshCIECDfP3SWAXAyml8NkZFPA jlippmann@NUE-MAC-087
The key's randomart image is:
+--[ED25519 256]--+
|Oo.=@*+o         |
|+*+*.=... .      |
|..*.E .  . .     |
| ..o +oo. .      |
| ..o+.++So       |
|  ..oo. =        |
|     oo=         |
|     .o..        |
|      ..         |

Have a look at the public key:

ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIE+u6Q/ycvxM1XG7JitWqla/nTKvT29rHS9IUjZMaPwH jlippmann@NUE-MAC-087

Now we tell the server about this key and what should be done with it. Nixos will do all the complicated stuff for us (creating a user and paths, setting the rights correctly), we just have to add the following to the (server-)nixos-configuration.

  services.borgbackup.repos = {
    my_borg_repo = {
      authorizedKeys = [
        # Here goes the public key we just created
        "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIE+u6Q/ycvxM1XG7JitWqla/nTKvT29rHS9IUjZMaPwH jlippmann@NUE-MAC-087"
      ] ;
      # where the backup will be placed
      path = "/var/lib/my_borg_repo" ;

Rebuild and switch. A user of the name borg has been created, has been assigned the mentioned directory and the key has been placed in the correct spot. You can check that this worked like this (still on the server):

cat /etc/ssh/authorized_keys.d/borg
command="cd '/var/lib/my_borg_repo' && borg serve --restrict-to-repository .  ",restrict ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIE+u6Q/ycvxM1XG7JitWqla/nTKvT29rHS9IUjZMaPwH jlippmann@NUE-MAC-087

Initialize the backup

We will have a password, which is the password for our backup itself. To be more precise: it is the password for a key stored in the backup-repo with which the backup wil be encrypted. It has nothing to do with the keypair we created earlier (which is just for connecting to the server). To safe time we will export this backup-passwort to a shell variable beforehand. There are other ways, for example setting a BORG_PASSCOMMAND. If you don't you will be asked to enter the password each time interactively (which is nice for exploration but bad for scripting.

export BORG_PASSPHRASE="test"

Now back on the client we can init the borg repo. Note especially the trailing colon and dot in the adress.

borg init --encryption=repokey-blake2 --rsh "ssh -i key_backups_of_NUE-MAC-087_id_ed25519"
By default repositories initialized with this version will produce security
errors if written to with an older version (up to and including Borg 1.0.8).

If you want to use these older versions, you can disable the check by running:
borg upgrade --disable-tam ssh://

See for details about the security implications.

IMPORTANT: you will need both KEY AND PASSPHRASE to access this repo!
Use "borg key export" to export the key, optionally in printable format.
Write down the passphrase. Store both at safe place(s).

To confirm that we indeed created the repository remotly we can check that the repo was created on the server:

ls /var/lib/my_borg_repo/
config  data  hints.1  index.1  integrity.1  nonce  README

Back on the client again, lets do this key export that was mentioned after we initialized the repo. I THINK that key is what the repo is encrypted with.

borg key export --rsh "ssh -i key_backups_of_NUE-MAC-087_id_ed25519" test_export
cat test_export
BORG_KEY ab6cb44a7ed5b13e6bb9fd62e93731d741de161d031aa74c5e903a7c1e9cb9ef

Create a backup

Now we can do our first backup:

borg create --stats --rsh "ssh -i key_backups_of_NUE-MAC-087_id_ed25519" files_to_back_up
Archive name: 01_first_backup
Archive fingerprint: e40e34c423ed1dba3ab1243840a3840b244f0f423f8bc96e50773879ae3184cd
Time (start): Sat, 2020-12-26 22:13:26
Time (end):   Sat, 2020-12-26 22:13:26
Duration: 0.04 seconds
Number of files: 2
Utilization of max. archive size: 0%
                       Original size      Compressed size    Deduplicated size
This archive:                1.20 kB              1.12 kB              1.12 kB
All archives:                1.20 kB              1.12 kB              1.12 kB

                       Unique chunks         Total chunks
Chunk index:                       4                    4

Now we can see if it is realy there:

borg list  --rsh "ssh -i key_backups_of_NUE-MAC-087_id_ed25519"
01_first_backup                      Sat, 2020-12-26 22:13:26 [e40e34c423ed1dba3ab1243840a3840b244f0f423f8bc96e50773879ae3184cd]

And see what is in it:

borg list  --rsh "ssh -i key_backups_of_NUE-MAC-087_id_ed25519"
drwxr-xr-x jlippmann 1728021072        0 Mon, 2020-12-21 07:48:10 files_to_back_up
-rw-r--r-- jlippmann 1728021072       11 Sat, 2020-12-26 22:04:13 files_to_back_up/zahlen.txt
-rw-r--r-- jlippmann 1728021072       27 Sat, 2020-12-26 22:04:13 files_to_back_up/buchstaben.txt

change some files and back up again

Now we add/change some files, create a new backup (without –stats this time) and check if it is there as well.

echo "ABCDEFGHIJKLMNOPQRSTUVWXYZ" >> files_to_back_up/buchstaben.txt # change a file
echo "gnu penguin chamaeleon" > files_to_back_up/animals.txt         # add a new file
# new backup
borg create --rsh "ssh -i key_backups_of_NUE-MAC-087_id_ed25519" files_to_back_up

List all the backups.

borg list  --rsh "ssh -i key_backups_of_NUE-MAC-087_id_ed25519"
01_first_backup                      Sat, 2020-12-26 22:13:26 [e40e34c423ed1dba3ab1243840a3840b244f0f423f8bc96e50773879ae3184cd]
02_second_backup                     Sat, 2020-12-26 22:15:35 [7a9d60039583b5c01dbf50df4b3f11c7736f1f5701c8822cc80b97e90aa2d220]

Look into 02_second_backup.

borg list --rsh "ssh -i key_backups_of_NUE-MAC-087_id_ed25519"
drwxr-xr-x jlippmann 1728021072        0 Sat, 2020-12-26 22:15:33 files_to_back_up
-rw-r--r-- jlippmann 1728021072       11 Sat, 2020-12-26 22:04:13 files_to_back_up/zahlen.txt
-rw-r--r-- jlippmann 1728021072       54 Sat, 2020-12-26 22:15:33 files_to_back_up/buchstaben.txt
-rw-r--r-- jlippmann 1728021072       23 Sat, 2020-12-26 22:15:33 files_to_back_up/animals.txt

Looking at the size of the file buchstaben.txt we see that it has grown.

Restore from backup

Next we loose our precious directory by accident…

rm -rf files_to_back_up # Oh no!

… and want to get an old version of it back.

borg extract --rsh "ssh -i key_backups_of_NUE-MAC-087_id_ed25519"

The files are back, as expected.

ls -la files_to_back_up
total 16
drwxr-xr-x   4 jlippmann  1728021072  128 21 Dez 07:48 .
drwxr-xr-x  12 jlippmann  1728021072  384 26 Dez 22:40 ..
-rw-r--r--   1 jlippmann  1728021072   27 26 Dez 22:04 buchstaben.txt
-rw-r--r--   1 jlippmann  1728021072   11 26 Dez 22:04 zahlen.txt