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;