@cryptotaxi247 / infra-1 / commits / 1d9b41c8

Copy backup module from nixos-org-configurations

Reusing the module is problematic due to different toplevel directories that flake based configuration cannot escape.

Martin Weinelt committed Feb 25, 2024 at 00:58 UTC 1d9b41c8b81666a6e569cee7099cc11271296923
2 files changed +166
modules/backup.nix new
+162
@@ -0,0 +1,162 @@
1 +{ lib
2 +, config
3 +, ...
4 +}:
5 +
6 +let
7 + cfg = config.services.backup;
8 +in
9 +{
10 + options.services.backup = with lib; with types; {
11 + user = mkOption {
12 + type = str;
13 + description = ''
14 + Username for the SSH remote host.
15 + '';
16 + };
17 +
18 + host = mkOption {
19 + type = str;
20 + description = ''
21 + Hostname of the SSH remote host.
22 + '';
23 + };
24 +
25 + hostPublicKey = mkOption {
26 + type = str;
27 + example = "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA5EB5p/5Hp3hGW1oHok+PIOH9Pbn7cnUiGmUEBrCVjnAw+HrKyN8bYVV0dIGllswYXwkG/+bgiBlE6IVIBAq+JwVWu1Sss3KarHY3OvFJUXZoZyRRg/Gc/+LRCE7lyKpwWQ70dbelGRyyJFH36eNv6ySXoUYtGkwlU5IVaHPApOxe4LHPZa/qhSRbPo2hwoh0orCtgejRebNtW5nlx00DNFgsvn8Svz2cIYLxsPVzKgUxs8Zxsxgn+Q/UvR7uq4AbAhyBMLxv7DjJ1pc7PJocuTno2Rw9uMZi1gkjbnmiOh6TTXIEWbnroyIhwc8555uto9melEUmWNQ+C+PwAK+MPw==";
28 + description = ''
29 + Public SSH host key of the remote host. Discoverable using e.g. `ssh-keyscan`.
30 + '';
31 + };
32 +
33 + port = mkOption {
34 + type = port;
35 + default = 22;
36 + description = ''
37 + Port of the SSH remote host.
38 + '';
39 + apply = toString;
40 + };
41 +
42 + sshKey = mkOption {
43 + type = path;
44 + example = "/var/keys/ssh-key";
45 + description = ''
46 + Path to the SSH key required to access the remote host.
47 + '';
48 + };
49 +
50 + secretPath = mkOption {
51 + type = path;
52 + example = "/var/keys/borg-secret";
53 + description = ''
54 + Path to the secret used to encrypt backups in the repository.
55 + '';
56 + };
57 +
58 + quota = mkOption {
59 + type = nullOr str;
60 + default = null;
61 + example = "90G";
62 + description = ''
63 + Quota for the borg repository. Useful to prevent the target disk from running full and ensuring borg keeps some space to work with.
64 + '';
65 + };
66 +
67 + includes = mkOption {
68 + type = listOf path;
69 + default = [];
70 + description = ''
71 + Paths to include in the backup.
72 + '';
73 + };
74 +
75 + excludes = mkOption {
76 + type = listOf path;
77 + default = [];
78 + description = ''
79 + Paths to exclude in the backup.
80 + '';
81 + };
82 +
83 + preHook = mkOption {
84 + type = lines;
85 + default = "";
86 + description = ''
87 + Shell commands to run before the backup.
88 + '';
89 + };
90 +
91 + postHook = mkOption {
92 + type = lines;
93 + default = "";
94 + description = ''
95 + Shell commands to run after the backup.
96 + '';
97 + };
98 +
99 + wantedUnits = mkOption {
100 + type = listOf str;
101 + default = [];
102 + description = ''
103 + List of units to require before starting the backup.
104 + '';
105 + };
106 + };
107 +
108 + config = lib.mkIf (cfg.includes != []) {
109 + programs.ssh.knownHosts."${if cfg.port != 22 then "[${cfg.host}]:${cfg.port}" else cfg.host}" = {
110 + publicKey = "${cfg.hostPublicKey}";
111 + };
112 +
113 + systemd.services.borgbackup-job-state = {
114 + wants = cfg.wantedUnits;
115 + after = cfg.wantedUnits;
116 + };
117 +
118 + systemd.timers.borgbackup-job-state.timerConfig = {
119 + # Spread all backups over the day
120 + RandomizedDelaySec = "24h";
121 + FixedRandomDelay = true;
122 + };
123 +
124 + services.borgbackup.jobs.state = {
125 + inherit (cfg) preHook postHook;
126 +
127 + # Create the repo
128 + doInit = true;
129 +
130 + # Create daily backups, but prune to a reasonable amount
131 + startAt = "daily";
132 + prune.keep = {
133 + daily = 7;
134 + weekly = 4;
135 + monthly = 3;
136 + };
137 +
138 + # What to backup
139 + paths = cfg.includes;
140 + exclude = cfg.excludes;
141 +
142 + # Where to backup it to
143 + repo = "${cfg.user}@${cfg.host}:${config.networking.fqdn}";
144 + environment.BORG_RSH = "ssh -p ${cfg.port} -i ${cfg.sshKey}";
145 +
146 + # Ensure we don't fill up the destination disk
147 + extraInitArgs = lib.optionalString (cfg.quota != null) "--storage-quota ${cfg.quota}";
148 +
149 + # Authenticated & encrypted, key resides in the repository
150 + encryption = {
151 + mode = "repokey-blake2";
152 + passCommand = "cat ${cfg.secretPath}";
153 + };
154 +
155 + # Reduce the backup size
156 + compression = "auto,zstd";
157 +
158 + # Show summary detailing data usage once completed
159 + extraCreateArgs = "--stats";
160 + };
161 + };
162 +}
modules/common.nix
+4
@@ -3,6 +3,10 @@
3 with lib;
4
5 {
6 + imports = [
7 + ./backup.nix
8 + ];
9 +
10 time.timeZone = "UTC";
11
12 users.mutableUsers = false;