-
Notifications
You must be signed in to change notification settings - Fork 0
/
borgbackup-sender.nix
98 lines (81 loc) · 3.35 KB
/
borgbackup-sender.nix
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.my.services.borgbackup;
script2matrix = pkgs.callPackage ./pkgs/script2matrix/default.nix {};
# e.g. "/var/lib/foo" -> "var-lib-foo"
sanitizeMountpoint = mountpoint: pipe mountpoint [
# split out unacceptable characters
(builtins.split "[^[:alnum:]]+")
# replace them with dashes
(concatMapStrings (s: if isList s then "-" else s))
# remove leading and trailing dashes
(removePrefix "-")
(removeSuffix "-")
# special case for the root directory
(s: if s == "" then "root" else s)
];
borgCreateInvocation = mountpoint: ''
borg create -s --one-file-system --exclude-caches \
${concatMapStrings (path: "--exclude ${path} ") cfg.excludedPaths} \
--compression auto,lzma \
--rsh "ssh -i /nix/my/unpacked/borgbackup-ssh-key" \
--upload-ratelimit 10240 \
"borgrecv@${cfg.targetHost}:/var/lib/borgrecv/repo/${config.networking.hostName}::${sanitizeMountpoint mountpoint}-{utcnow:%Y-%m-%dT%H:%M:%SZ}" ${mountpoint}
'';
borgbackup-send-script = pkgs.writeScriptBin "borgbackup-send-script" ''
#!${pkgs.bash}/bin/bash
${borgCreateInvocation "/"}
${concatStringsSep "\n" (map borgCreateInvocation cfg.additionalFileSystems)}
'';
in {
options.my.services.borgbackup = {
targetHost = mkOption {
description = "hostname or IP of backup receiver";
default = null;
type = types.nullOr types.str;
};
excludedPaths = mkOption {
description = "List of paths that will be excluded from the backup.";
default = [];
type = types.listOf types.str;
};
additionalFileSystems = mkOption {
description = "List of directories not stored on the root filesystem that shall be backed up.";
default = filter (hasPrefix "/var/lib") (attrNames config.fileSystems); # all mounted disks at or below /var/lib
type = types.listOf types.str;
};
};
config = mkIf (cfg.targetHost != null) {
# default set of excluded paths; other modules can add to this
my.services.borgbackup.excludedPaths = [
"/x"
"/nix"
"/boot"
"/var/log/journal"
"/root/.cache"
];
systemd.services.borgbackup-root = {
description = "Borg backup for root filesystem";
requires = [ "network-online.target" ];
after = [ "network-online.target" ];
startAt = "02:00:00"; # before nix-gc.service (at 03:15) and nixos-upgrade.service (at 04:40)
path = [ pkgs.borgbackup pkgs.openssh pkgs.coreutils script2matrix borgbackup-send-script ];
script = "exec script2matrix borgbackup-send-script";
environment = let cfgMatrix = config.my.services.monitoring.matrix; in {
BORG_PASSCOMMAND = "cat /nix/my/unpacked/generated-borgbackup-key";
MATRIX_USER = cfgMatrix.userName;
MATRIX_TARGET = cfgMatrix.target;
};
serviceConfig.EnvironmentFile = toString /nix/my/unpacked/generated-matrix-password;
serviceConfig.Type = "oneshot";
# despite the hardening below, we need to be able to write to our home
# directory, i.e. /root/, to access /root/.ssh/known_hosts (writing is not
# required here) and /root/.cache/borg/ (this one requires write access)
serviceConfig.ProtectHome = mkForce "no";
};
my.hardening.borgbackup-root = {
allowInternetAccess = true; # to reach backup location
};
};
}