Borg backup

From NixOS Wiki
Revision as of 11:45, 16 June 2020 by imported>Danbst (Created page with "Borg is a backup tool to perform incremental backups, local or remote. <syntaxHighlight lang=bash> $ nix-env -iA nixpkgs.borgbackup </syntaxHighlight> To be able to do remot...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Borg is a backup tool to perform incremental backups, local or remote.

$ nix-env -iA nixpkgs.borgbackup

To be able to do remote backups it should be installed both locally and remotely, but usually no remote configuration required, only local one.

Creating backups

I'll describe remote SSH backups here, as this is the most important case. It should be as easy as:

  services.borgbackup.jobs.home-danbst = {
    paths = "/home/danbst";
    encryption.mode = "none";
    environment.BORG_RSH = "ssh -i /home/danbst/.ssh/id_ed25519";
    repo = "ssh://user@example.com:23/path/to/backups-dir/home-danbst";
    compression = "auto,zstd";
    startAt = "daily";
  };

First, create a directory for backups /path/to/backups-dir on your remote machine, then rebuild local machine using this config and correctly specified paths, BORG_RSH, etc.

It will create "archives" with identifiers like station-home-danbst-2020-06-10T00:00:46 every day.

Personally, I've adapted that to exclude unrelated stuff and split into multiple repos, but you don't necessarily need that:

  services.borgbackup.jobs =
    let common-excludes = [
          # Largest cache dirs
          ".cache"
          "*/cache2" # firefox
          "*/Cache"
          ".config/Slack/logs"
          ".config/Code/CachedData"
          ".container-diff"
          ".npm/_cacache"
          # Work related dirs
          "*/node_modules"
          "*/bower_components"
          "*/_build"
          "*/.tox"
          "*/venv"
          "*/.venv"
        ];
        work-dirs = [
          "/home/danbst/dev/company1"
          "/home/danbst/dev/company2"
        ];
        basicBorgJob = name: {
          encryption.mode = "none";
          environment.BORG_RSH = "ssh -o 'StrictHostKeyChecking=no' -i /home/danbst/.ssh/id_ed25519";
          environment.BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK = "1";
          extraCreateArgs = "--verbose --stats --checkpoint-interval 600";
          repo = "ssh://user@example.com//media/backup/${name}";
          compression = "zstd,1";
          startAt = "daily";
          user = "danbst";
        };
  in {
    home-danbst = basicBorgJob "backups/station/home-danbst" // rec {
      paths = "/home/danbst";
      exclude = work-dirs ++ map (x: paths + "/" + x) (common-excludes ++ [
        "Downloads"
      ]);
    };
    home-danbst-downloads = basicBorgJob "backups/station/home-danbst-downloads" // rec {
      paths = "/home/danbst/Downloads";
      exclude = map (x: paths + "/" + x) common-excludes;
    };
    extra-drive-important = basicBorgJob "backups/station/extra-drive-important" // rec {
      paths = "/media/extra-drive/important";
      exclude = map (x: paths + "/" + x) common-excludes;
    };
  };

After doing at least one successful backup don't forget to test mount it (see next)

Mounting point-in-time archives

First, check if there are any archives:

$ borg list user@example.name:/media/backup/backups/station/home-danbst
...
station-home-danbst-2020-06-02T00:00:02 Mon, 2020-06-01 21:00:09 [24e6318a379ac3b494448fb2ab2ca7b2df7188426d0814978165cab8e09cd642]
station-home-danbst-2020-06-03T00:00:12 Tue, 2020-06-02 21:00:20 [2912b78d306f5b4a254e099f0878d743849c1b99c4441815e3fa43d485414438]
station-home-danbst-2020-06-04T00:00:07 Wed, 2020-06-03 21:00:29 [8a5e03a8f9a1a397e5e05585e112f2206043cfdc8cca4d97f73079be89ba1009]
station-home-danbst-2020-06-05T00:00:02 Thu, 2020-06-04 21:00:11 [14df97419fd2e2a243d24cd04b643044a5c732b815cc25d3bddd8df6cf1f2549]
station-home-danbst-2020-06-06T00:00:00 Fri, 2020-06-05 21:00:11 [69684418497adc43a0ae8ebc617494247bf6ecfe42ba6c04db354253c7f5e144]
station-home-danbst-2020-06-08T00:00:52 Sun, 2020-06-07 21:00:59 [d5b08fa57cfb3727c5f7d855509158a70907b6fa009abe30579328def74fd2a6]
station-home-danbst-2020-06-10T00:00:46 Tue, 2020-06-09 21:00:53 [85a5329ae39c46a03e2e925ef740f8d5090a61c35161cdd539ac248a53e5b7d4]

Choose one of "archives" and mount it locally:

$ borgfs -f -o uid=1002 \
    user@example.com:/media/backup/backups/station/home-danbst::station-home-danbst-2020-06-10T00:00:46 \
    ~/borg-home-danbst2 
    home/danbst

where uid is your user's UID, in case you are restoring on a different system. You also should have private ssh key in your ssh-agent, or specified in BORG_RSH. The last arg is optional, but without it you'll get root view of backup.

Automounting backups using NixOS

Actually, I don't have a solution as of time being, so I'll share a setup which allows automount, but requires sudo to access.

  fileSystems."/run/user/1002/borg-home-danbst" = {
    device = "user@example.com:/media/backup/backups/station/home-danbst::station-home-danbst-2020-06-10T00:00:46";
    noCheck = true;
    fsType = "fuse.borgfs";      # note that this requires a custom binary, see below
    options = [ "x-systemd.automount" "noauto" "uid=1002" "exec" ];    # I'm using automount here to skip mount on boot, which slows startup
  };
  
  # this one should mount the actual directory from the root view of backup
  fileSystems."/run/user/1002/home-danbst" = {
    device = "/run/user/1002/borg-home-danbst/home/danbst";
    options = [ "bind" ];
  };

  environment.systemPackages = [
    ...
    (pkgs.writeScriptBin "mount.fuse.borgfs" ''
      #!/bin/sh
      export BORG_RSH="ssh -i /home/danbst/.ssh/id_ed25519"
      export BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=yes
      export BORG_RELOCATED_REPO_ACCESS_IS_OK=yes
      exec ${pkgs.borgbackup}/bin/borgfs "$@"
    '')
  ];

If anybody reading this have found a way to mount as a user properly, please update the code above.