aboutsummaryrefslogtreecommitdiff
path: root/systems/eldiron
diff options
context:
space:
mode:
authorIsmaël Bouya <ismael.bouya@normalesup.org>2024-06-10 13:13:11 +0200
committerIsmaël Bouya <ismael.bouya@normalesup.org>2024-06-11 00:18:33 +0200
commit1c90c0dd73b5b74612be736ac8deeaa4547e2c26 (patch)
tree80a7bfcecd7478fb42c57616f706c90441475b88 /systems/eldiron
parente8d50f14185867d490f002aa5c408343ea5ea062 (diff)
downloadNix-1c90c0dd73b5b74612be736ac8deeaa4547e2c26.tar.gz
Nix-1c90c0dd73b5b74612be736ac8deeaa4547e2c26.tar.zst
Nix-1c90c0dd73b5b74612be736ac8deeaa4547e2c26.zip
Migrate to borg backup
Diffstat (limited to 'systems/eldiron')
-rw-r--r--systems/eldiron/base.nix14
-rw-r--r--systems/eldiron/borg_backup.nix241
-rw-r--r--systems/eldiron/databases/openldap/default.nix3
-rw-r--r--systems/eldiron/duply_backup.nix278
-rw-r--r--systems/eldiron/flake.lock26
-rw-r--r--systems/eldiron/ftp.nix4
-rw-r--r--systems/eldiron/gitolite/default.nix16
-rw-r--r--systems/eldiron/pub/default.nix3
-rw-r--r--systems/eldiron/websites/cloud/default.nix9
-rw-r--r--systems/eldiron/websites/commento/default.nix3
-rw-r--r--systems/eldiron/websites/cryptpad/default.nix3
-rw-r--r--systems/eldiron/websites/tools/default.nix15
12 files changed, 524 insertions, 91 deletions
diff --git a/systems/eldiron/base.nix b/systems/eldiron/base.nix
index a77a438..5308ddb 100644
--- a/systems/eldiron/base.nix
+++ b/systems/eldiron/base.nix
@@ -118,6 +118,7 @@
118 ./buildbot 118 ./buildbot
119 ./coturn.nix 119 ./coturn.nix
120 ./dns.nix 120 ./dns.nix
121 ./borg_backup.nix
121 ./duply_backup.nix 122 ./duply_backup.nix
122 ./gemini 123 ./gemini
123 ./gitolite 124 ./gitolite
@@ -132,6 +133,19 @@
132 ./vpn 133 ./vpn
133 ]; 134 ];
134 135
136 services.borgBackup.enable = true;
137 services.borgBackup.profiles.global = {
138 bucket = "global";
139 hash = false;
140 remotes = [ "attilax" ];
141 ignoredPaths = [
142 "udev"
143 "portables"
144 "machines"
145 "nixos"
146 "nixos-containers"
147 ];
148 };
135 myServices.buildbot.enable = true; 149 myServices.buildbot.enable = true;
136 myServices.databases.enable = true; 150 myServices.databases.enable = true;
137 myServices.gitolite.enable = true; 151 myServices.gitolite.enable = true;
diff --git a/systems/eldiron/borg_backup.nix b/systems/eldiron/borg_backup.nix
new file mode 100644
index 0000000..9956a46
--- /dev/null
+++ b/systems/eldiron/borg_backup.nix
@@ -0,0 +1,241 @@
1{ lib, pkgs, config, name, ... }:
2
3let
4 cfg = config.myEnv.borg_backup;
5 varDir = "/var/lib/borgbackup";
6 borg_args = "--encryption repokey --make-parent-dirs init create prune compact check";
7 borg_backup_full_with_ignored = pkgs.writeScriptBin "borg_full_with_ignored" ''
8 #!${pkgs.stdenv.shell}
9
10 if [ -z "$1" -o "$1" = "-h" -o "$1" = "--help" ]; then
11 echo "borg_full_with_ignored /path/to/borgmatic.yaml"
12 echo "Does a full backup including directories with .duplicity-ignore"
13 exit 1
14 fi
15 ${pkgs.borgmatic}/bin/borgmatic -c "$1" --override 'storage.archive_name_format="{hostname}-with-ignored-{now:%Y-%m-%dT%H:%M:%S.%f}"' --override 'location.exclude_if_present=[]' ${borg_args}
16 '';
17 borg_backup = pkgs.writeScriptBin "borg_backup" ''
18 #!${pkgs.stdenv.shell}
19
20 declare -a profiles
21 profiles=()
22 ${builtins.concatStringsSep "\n" (lib.flatten (lib.mapAttrsToList (k: v: map (remote: [
23 ''profiles+=("${remote}_${k}")''
24 ]) v.remotes) config.services.borgBackup.profiles))}
25
26 if [ -f "${varDir}/last_backup_profile" ]; then
27 last_backup=$(cat ${varDir}/last_backup_profile)
28 for i in "''${!profiles[@]}"; do
29 if [[ "''${profiles[$i]}" = "$last_backup" ]]; then
30 break
31 fi
32 done
33 ((i+=1))
34 profiles=("''${profiles[@]:$i}" "''${profiles[@]:0:$i}")
35 fi
36
37 # timeout in minutes
38 timeout="''${1:-180}"
39 timeout_timestamp=$(date +%s -d "$timeout minutes")
40 for profile in "''${profiles[@]}"; do
41 if [ $(date +%s -d "now") -ge "$timeout_timestamp" ]; then
42 break
43 fi
44
45 touch "${varDir}/$profile.log"
46 ${pkgs.borgmatic}/bin/borgmatic -c "${config.secrets.location}/borg_backup/$profile/borgmatic.yaml" ${borg_args} >> ${varDir}/$profile.log
47 [[ $? = 0 ]] || echo -e "Error when doing backup for $profile, see above or logs in ${varDir}/$profile.log\n---------------------------------------" >&2
48 echo "$profile" > ${varDir}/last_backup_profile
49 done
50 '';
51
52 check_backups = pkgs.writeScriptBin "borg_list_not_backuped" ''
53 #!${pkgs.stdenv.shell}
54
55 do_check() {
56 local dir="$1" path ignored_path
57 find "$dir" -mindepth 1 -maxdepth 1 | while IFS= read -r path; do
58 if ${pkgs.gnugrep}/bin/grep -qFx "$path" ${config.secrets.fullPaths."borg_backup/backuped_list"}; then
59 continue
60 elif ${pkgs.gnugrep}/bin/grep -q "^$path/" ${config.secrets.fullPaths."borg_backup/backuped_list"}; then
61 do_check "$path"
62 else
63 while IFS= read -r ignored_path; do
64 if [[ "$path" =~ ^$ignored_path$ ]]; then
65 continue 2
66 fi
67 done < ${config.secrets.fullPaths."borg_backup/ignored_list"}
68 printf '%s\n' "$path"
69 fi
70 done
71 }
72
73 do_check /var/lib
74 '';
75 borgProfile = profile: remote: bucket: builtins.toJSON {
76 location = {
77 source_directories = map (p: "${profile.rootDir}/${p}") profile.includedPaths;
78 repositories = [
79 { path = cfg.remotes.${remote}.remote bucket; label = "backupserver"; }
80 ];
81 one_file_system = false;
82 exclude_if_present = [".duplicity-ignore"];
83 source_directories_must_exist = profile.directoriesMustExist;
84 borgmatic_source_directory = "${varDir}/${profile.bucket}/.borgmatic";
85 };
86 storage = {
87 encryption_passphrase = profile.password;
88 ssh_command = "ssh -i ${config.secrets.fullPaths."borg_backup/identity"}";
89 compression = "zlib";
90 borg_base_directory = "${varDir}/${profile.bucket}";
91 };
92 retention = {
93 keep_within = "10d";
94 keep_daily = 30;
95 };
96 };
97in
98{
99 options = {
100 services.borgBackup.enable = lib.mkOption {
101 type = lib.types.bool;
102 default = false;
103 description = ''
104 Whether to enable remote backups.
105 '';
106 };
107 services.borgBackup.profiles = lib.mkOption {
108 type = lib.types.attrsOf (lib.types.submodule {
109 options = {
110 hash = lib.mkOption {
111 type = lib.types.bool;
112 default = true;
113 description = ''
114 Hash bucket and directory names
115 '';
116 };
117 rootDir = lib.mkOption {
118 type = lib.types.path;
119 default = "/var/lib";
120 description = ''
121 Path to backup
122 '';
123 };
124 password = lib.mkOption {
125 type = lib.types.str;
126 default = cfg.password;
127 description = ''
128 password to use to encrypt data
129 '';
130 };
131 directoriesMustExist = lib.mkOption {
132 type = lib.types.bool;
133 default = true;
134 description = ''
135 Raise error if backuped directory doesn't exist
136 '';
137 };
138 bucket = lib.mkOption {
139 type = lib.types.str;
140 description = ''
141 Bucket to use
142 '';
143 };
144 remotes = lib.mkOption {
145 type = lib.types.listOf lib.types.str;
146 description = ''
147 Remotes to use for backup
148 '';
149 };
150 includedPaths = lib.mkOption {
151 type = lib.types.listOf lib.types.str;
152 default = [];
153 description = ''
154 Included paths (subdirs of rootDir)
155 '';
156 };
157 excludeFile = lib.mkOption {
158 type = lib.types.lines;
159 default = "";
160 description = ''
161 Content to put in exclude file
162 '';
163 };
164 ignoredPaths = lib.mkOption {
165 type = lib.types.listOf lib.types.str;
166 default = [];
167 description = ''
168 List of paths to ignore when checking non-backed-up directories
169 Can use (POSIX extended) regex
170 '';
171 };
172 };
173 });
174 };
175 };
176
177 config = lib.mkIf config.services.borgBackup.enable {
178 system.activationScripts.borg_backup = ''
179 install -m 0700 -o root -g root -d ${varDir}
180 '';
181 secrets.keys = lib.listToAttrs (lib.flatten (lib.mapAttrsToList (k: v:
182 let
183 bucket = if v.hash or true then builtins.hashString "sha256" v.bucket else v.bucket;
184 in map (remote: [
185 (lib.nameValuePair "borg_backup/${remote}_${k}/borgmatic.yaml" {
186 permissions = "0400";
187 text = borgProfile v remote bucket;
188 })
189 (lib.nameValuePair "borg_backup/${remote}_${k}" {
190 permissions = "0700";
191 isDir = true;
192 })
193 ]) v.remotes) config.services.borgBackup.profiles)) // {
194 "borg_backup/identity" = {
195 permissions = "0400";
196 text = "{{ .ssl_keys.borg_backup }}";
197 };
198 "borg_backup/ignored_list" = {
199 permissions = "0400";
200 text = let
201 ignored = map
202 (v: map (p: "${v.rootDir}/${p}") v.ignoredPaths)
203 (builtins.attrValues config.services.borgBackup.profiles);
204 in builtins.concatStringsSep "\n" (lib.flatten ignored);
205 };
206 "borg_backup/backuped_list" = {
207 permissions = "0400";
208 text = let
209 included = map
210 (v: map (p: "${v.rootDir}/${p}") v.includedPaths)
211 (builtins.attrValues config.services.borgBackup.profiles);
212 in builtins.concatStringsSep "\n" (lib.flatten included);
213 };
214 };
215
216 programs.ssh.knownHostsFiles = [
217 (pkgs.writeText
218 "borg_backup_known_hosts"
219 (builtins.concatStringsSep
220 "\n"
221 (builtins.filter
222 (v: v != null)
223 (builtins.map
224 (v: v.sshKnownHosts)
225 (builtins.attrValues cfg.remotes)
226 )
227 )
228 )
229 )
230 ];
231 environment.systemPackages = [ pkgs.borgbackup pkgs.borgmatic borg_backup_full_with_ignored borg_backup check_backups ];
232 services.cron = {
233 enable = true;
234 systemCronJobs = [
235 "0 0 * * * root ${borg_backup}/bin/borg_backup 300"
236 ];
237
238 };
239
240 };
241}
diff --git a/systems/eldiron/databases/openldap/default.nix b/systems/eldiron/databases/openldap/default.nix
index 7cd15da..fcab337 100644
--- a/systems/eldiron/databases/openldap/default.nix
+++ b/systems/eldiron/databases/openldap/default.nix
@@ -103,6 +103,9 @@ in
103 }; 103 };
104 users.users.openldap.extraGroups = [ "keys" ]; 104 users.users.openldap.extraGroups = [ "keys" ];
105 networking.firewall.allowedTCPPorts = [ 636 389 ]; 105 networking.firewall.allowedTCPPorts = [ 636 389 ];
106 services.borgBackup.profiles.global.includedPaths = [
107 "openldap"
108 ];
106 109
107 security.acme.certs."ldap" = { 110 security.acme.certs."ldap" = {
108 group = "openldap"; 111 group = "openldap";
diff --git a/systems/eldiron/duply_backup.nix b/systems/eldiron/duply_backup.nix
index 590d125..5143302 100644
--- a/systems/eldiron/duply_backup.nix
+++ b/systems/eldiron/duply_backup.nix
@@ -3,29 +3,108 @@
3let 3let
4 cfg = config.myEnv.backup; 4 cfg = config.myEnv.backup;
5 varDir = "/var/lib/duply"; 5 varDir = "/var/lib/duply";
6 duplyProfile = profile: remote: prefix: '' 6 default_action = "pre_bkp_purge_purgeFull_purgeIncr";
7 GPG_PW="${cfg.password}" 7 duply_backup_full_with_ignored = pkgs.writeScriptBin "duply_full_with_ignored" ''
8 TARGET="${cfg.remotes.${remote}.remote profile.bucket}${prefix}" 8 #!${pkgs.stdenv.shell}
9 export AWS_ACCESS_KEY_ID="${cfg.remotes.${remote}.accessKeyId}" 9
10 export AWS_SECRET_ACCESS_KEY="${cfg.remotes.${remote}.secretAccessKey}" 10 export DUPLY_FULL_BACKUP_WITH_IGNORED=yes
11 if [ -z "$1" -o "$1" = "-h" -o "$1" = "--help" ]; then
12 echo "duply_full_with_ignored /path/to/profile"
13 echo "Does a full backup including directories with .duplicity-ignore"
14 exit 1
15 fi
16 ${pkgs.duply}/bin/duply "$1" pre_full --force
17 '';
18 duply_backup = pkgs.writeScriptBin "duply_backup" ''
19 #!${pkgs.stdenv.shell}
20
21 declare -a profiles
22 profiles=()
23 ${builtins.concatStringsSep "\n" (lib.flatten (lib.mapAttrsToList (k: v: map (remote: [
24 ''profiles+=("${remote}_${k}")''
25 ]) v.remotes) config.services.duplyBackup.profiles))}
26
27 if [ -f "${varDir}/last_backup_profile" ]; then
28 last_backup=$(cat ${varDir}/last_backup_profile)
29 for i in "''${!profiles[@]}"; do
30 if [[ "''${profiles[$i]}" = "$last_backup" ]]; then
31 break
32 fi
33 done
34 ((i+=1))
35 profiles=("''${profiles[@]:$i}" "''${profiles[@]:0:$i}")
36 fi
37
38 # timeout in minutes
39 timeout="''${1:-180}"
40 timeout_timestamp=$(date +%s -d "$timeout minutes")
41 for profile in "''${profiles[@]}"; do
42 if [ $(date +%s -d "now") -ge "$timeout_timestamp" ]; then
43 break
44 fi
45
46 touch "${varDir}/$profile.log"
47 ${pkgs.duply}/bin/duply ${config.secrets.location}/backup/$profile/ ${default_action} --force >> ${varDir}/$profile.log
48 [[ $? = 0 ]] || echo -e "Error when doing backup for $profile, see above or logs in ${varDir}/$profile.log\n---------------------------------------" >&2
49 echo "$profile" > ${varDir}/last_backup_profile
50 done
51 '';
52
53 check_backups = pkgs.writeScriptBin "duply_list_not_backuped" ''
54 #!${pkgs.stdenv.shell}
55
56 do_check() {
57 local dir="$1" path ignored_path
58 find "$dir" -mindepth 1 -maxdepth 1 | while IFS= read -r path; do
59 if ${pkgs.gnugrep}/bin/grep -qFx "$path" ${config.secrets.fullPaths."backup/backuped_list"}; then
60 continue
61 elif ${pkgs.gnugrep}/bin/grep -q "^$path/" ${config.secrets.fullPaths."backup/backuped_list"}; then
62 do_check "$path"
63 else
64 while IFS= read -r ignored_path; do
65 if [[ "$path" =~ ^$ignored_path$ ]]; then
66 continue 2
67 fi
68 done < ${config.secrets.fullPaths."backup/ignored_list"}
69 printf '%s\n' "$path"
70 fi
71 done
72 }
73
74 do_check /var/lib
75 '';
76 duplyProfile = profile: remote: bucket: let
77 remote' = cfg.remotes.${remote};
78 in ''
79 if [ -z "$DUPLY_FULL_BACKUP_WITH_IGNORED" ]; then
80 GPG_PW="${cfg.password}"
81 fi
82 TARGET="${remote'.remote bucket}"
83 ${lib.optionalString (remote'.remote_type == "s3") ''
84 export AWS_ACCESS_KEY_ID="${remote'.s3AccessKeyId}"
85 export AWS_SECRET_ACCESS_KEY="${remote'.s3SecretAccessKey}"
86 ''}
87 ${lib.optionalString (remote'.remote_type == "rsync") ''
88 DUPL_PARAMS="$DUPL_PARAMS --ssh-options=-oIdentityFile='${config.secrets.fullPaths."backup/identity"}' "
89 ''}
11 SOURCE="${profile.rootDir}" 90 SOURCE="${profile.rootDir}"
12 FILENAME=".duplicity-ignore" 91 if [ -z "$DUPLY_FULL_BACKUP_WITH_IGNORED" ]; then
13 DUPL_PARAMS="$DUPL_PARAMS --exclude-if-present '$FILENAME'" 92 FILENAME=".duplicity-ignore"
93 DUPL_PARAMS="$DUPL_PARAMS --exclude-if-present '$FILENAME'"
94 fi
14 VERBOSITY=4 95 VERBOSITY=4
15 ARCH_DIR="${varDir}/caches" 96 ARCH_DIR="${varDir}/caches"
97 DUPL_PYTHON_BIN=""
16 98
17 # Do a full backup after 1 month 99 # Do a full backup after 6 month
18 MAX_FULLBKP_AGE=1M 100 MAX_FULLBKP_AGE=6M
19 DUPL_PARAMS="$DUPL_PARAMS --allow-source-mismatch --exclude-other-filesystems --full-if-older-than $MAX_FULLBKP_AGE " 101 DUPL_PARAMS="$DUPL_PARAMS --allow-source-mismatch --full-if-older-than $MAX_FULLBKP_AGE "
20 # Backups older than 2months are deleted 102 # Backups older than 1months are deleted
21 MAX_AGE=2M 103 MAX_AGE=1M
22 # Keep 2 full backups 104 # Keep 1 full backup
23 MAX_FULL_BACKUPS=2 105 MAX_FULL_BACKUPS=1
24 MAX_FULLS_WITH_INCRS=2 106 MAX_FULLS_WITH_INCRS=1
25 ''; 107 '';
26 action = "bkp_purge_purgeFull_purgeIncr";
27 varName = k: remoteName:
28 if remoteName == "eriomem" then k else remoteName + "_" + k;
29in 108in
30{ 109{
31 options = { 110 options = {
@@ -39,26 +118,46 @@ in
39 services.duplyBackup.profiles = lib.mkOption { 118 services.duplyBackup.profiles = lib.mkOption {
40 type = lib.types.attrsOf (lib.types.submodule { 119 type = lib.types.attrsOf (lib.types.submodule {
41 options = { 120 options = {
121 hash = lib.mkOption {
122 type = lib.types.bool;
123 default = true;
124 description = ''
125 Hash bucket and directory names
126 '';
127 };
128 excludeRootDir = lib.mkOption {
129 type = lib.types.bool;
130 default = true;
131 description = ''
132 Exclude root dir in exclusion file
133 '';
134 };
42 rootDir = lib.mkOption { 135 rootDir = lib.mkOption {
43 type = lib.types.path; 136 type = lib.types.path;
137 default = "/var/lib";
44 description = '' 138 description = ''
45 Path to backup 139 Path to backup
46 ''; 140 '';
47 }; 141 };
48 bucket = lib.mkOption { 142 bucket = lib.mkOption {
49 type = lib.types.str; 143 type = lib.types.str;
50 default = "immae-${name}";
51 description = '' 144 description = ''
52 Bucket to use 145 Bucket to use
53 ''; 146 '';
54 }; 147 };
55 remotes = lib.mkOption { 148 remotes = lib.mkOption {
56 type = lib.types.listOf lib.types.str; 149 type = lib.types.listOf lib.types.str;
57 default = ["eriomem"];
58 description = '' 150 description = ''
59 Remotes to use for backup 151 Remotes to use for backup
60 ''; 152 '';
61 }; 153 };
154 includedPaths = lib.mkOption {
155 type = lib.types.listOf lib.types.str;
156 default = [];
157 description = ''
158 Included paths (subdirs of rootDir)
159 '';
160 };
62 excludeFile = lib.mkOption { 161 excludeFile = lib.mkOption {
63 type = lib.types.lines; 162 type = lib.types.lines;
64 default = ""; 163 default = "";
@@ -66,6 +165,14 @@ in
66 Content to put in exclude file 165 Content to put in exclude file
67 ''; 166 '';
68 }; 167 };
168 ignoredPaths = lib.mkOption {
169 type = lib.types.listOf lib.types.str;
170 default = [];
171 description = ''
172 List of paths to ignore when checking non-backed-up directories
173 Can use (POSIX extended) regex
174 '';
175 };
69 }; 176 };
70 }); 177 });
71 }; 178 };
@@ -76,76 +183,91 @@ in
76 install -m 0700 -o root -g root -d ${varDir} ${varDir}/caches 183 install -m 0700 -o root -g root -d ${varDir} ${varDir}/caches
77 ''; 184 '';
78 secrets.keys = lib.listToAttrs (lib.flatten (lib.mapAttrsToList (k: v: 185 secrets.keys = lib.listToAttrs (lib.flatten (lib.mapAttrsToList (k: v:
79 map (remote: [ 186 let
80 (lib.nameValuePair "backup/${varName k remote}/conf" { 187 bucket = if v.hash or true then builtins.hashString "sha256" v.bucket else v.bucket;
188 in map (remote: [
189 (lib.nameValuePair "backup/${remote}_${k}/conf" {
81 permissions = "0400"; 190 permissions = "0400";
82 text = duplyProfile v remote "${k}/"; 191 text = duplyProfile v remote bucket;
83 }) 192 })
84 (lib.nameValuePair "backup/${varName k remote}/exclude" { 193 (lib.nameValuePair "backup/${remote}_${k}/exclude" {
85 permissions = "0400"; 194 permissions = "0400";
86 text = v.excludeFile; 195 text = v.excludeFile + (builtins.concatStringsSep "\n" (map (p: "+ ${v.rootDir}/${p}") v.includedPaths)) + (lib.optionalString v.excludeRootDir ''
196
197 - **
198 '');
87 }) 199 })
88 (lib.nameValuePair "backup/${varName k remote}" { 200 (lib.nameValuePair "backup/${remote}_${k}/pre" {
201 keyDependencies = [
202 pkgs.bash
203 pkgs.rsync
204 ];
89 permissions = "0500"; 205 permissions = "0500";
206 text = let
207 remote' = cfg.remotes.${remote};
208 in ''
209 #!${pkgs.stdenv.shell}
210
211 ${lib.optionalString (remote'.remote_type == "rsync") ''
212 # Recreate directory structure before synchronizing
213 mkdir -p ${varDir}/rsync_remotes/${remote}/${bucket}
214 ${pkgs.rsync}/bin/rsync -av -e \
215 "ssh -p ${remote'.sshRsyncPort} -oIdentityFile=${config.secrets.fullPaths."backup/identity"}" \
216 "${varDir}/rsync_remotes/${remote}/" \
217 ${remote'.sshRsyncHost}:
218 ''}
219 '';
220 })
221 (lib.nameValuePair "backup/${remote}_${k}" {
222 permissions = "0700";
90 isDir = true; 223 isDir = true;
91 }) 224 })
92 ]) v.remotes) config.services.duplyBackup.profiles)); 225 ]) v.remotes) config.services.duplyBackup.profiles)) // {
226 "backup/identity" = {
227 permissions = "0400";
228 text = "{{ .ssl_keys.duply_backup }}";
229 };
230 "backup/ignored_list" = {
231 permissions = "0400";
232 text = let
233 ignored = map
234 (v: map (p: "${v.rootDir}/${p}") v.ignoredPaths)
235 (builtins.attrValues config.services.duplyBackup.profiles);
236 in builtins.concatStringsSep "\n" (lib.flatten ignored);
237 };
238 "backup/backuped_list" = {
239 permissions = "0400";
240 text = let
241 included = map
242 (v: map (p: "${v.rootDir}/${p}") v.includedPaths)
243 (builtins.attrValues config.services.duplyBackup.profiles);
244 in builtins.concatStringsSep "\n" (lib.flatten included);
245 };
246 };
93 247
248 programs.ssh.knownHostsFiles = [
249 (pkgs.writeText
250 "duply_backup_known_hosts"
251 (builtins.concatStringsSep
252 "\n"
253 (builtins.filter
254 (v: v != null)
255 (builtins.map
256 (v: v.sshKnownHosts)
257 (builtins.attrValues cfg.remotes)
258 )
259 )
260 )
261 )
262 ];
263 environment.systemPackages = [ pkgs.duply check_backups duply_backup_full_with_ignored duply_backup ];
94 services.cron = { 264 services.cron = {
95 enable = true; 265 enable = true;
96 systemCronJobs = let 266 systemCronJobs = [
97 backups = pkgs.writeScript "backups" '' 267 "0 0 * * * root ${duply_backup}/bin/duply_backup 90"
98 #!${pkgs.stdenv.shell} 268 ];
99
100 ${builtins.concatStringsSep "\n" (lib.flatten (lib.mapAttrsToList (k: v:
101 map (remote: [
102 ''
103 touch ${varDir}/${varName k remote}.log
104 ${pkgs.duply}/bin/duply ${config.secrets.fullPaths."backup/${varName k remote}"}/ ${action} --force >> ${varDir}/${varName k remote}.log
105 [[ $? = 0 ]] || echo -e "Error when doing backup for ${varName k remote}, see above\n---------------------------------------" >&2
106 ''
107 ]) v.remotes
108 ) config.services.duplyBackup.profiles))}
109 '';
110 in
111 [
112 "0 2 * * * root ${backups}"
113 ];
114 269
115 }; 270 };
116 271
117 security.pki.certificateFiles = [
118 (pkgs.fetchurl {
119 url = "http://downloads.e.eriomem.net/eriomemca.pem";
120 sha256 = "1ixx4c6j3m26j8dp9a3dkvxc80v1nr5aqgmawwgs06bskasqkvvh";
121 })
122 ];
123
124 myServices.monitoring.fromMasterActivatedPlugins = [ "eriomem" ];
125 myServices.monitoring.fromMasterObjects.service = [
126 {
127 service_description = "eriomem backup is up and not full";
128 host_name = config.hostEnv.fqdn;
129 use = "external-service";
130 check_command = "check_backup_eriomem";
131
132 check_interval = 120;
133 notification_interval = "1440";
134
135 servicegroups = "webstatus-backup";
136 }
137
138 {
139 service_description = "ovh backup is up and not full";
140 host_name = config.hostEnv.fqdn;
141 use = "external-service";
142 check_command = "check_ok";
143
144 check_interval = 120;
145 notification_interval = "1440";
146
147 servicegroups = "webstatus-backup";
148 }
149 ];
150 }; 272 };
151} 273}
diff --git a/systems/eldiron/flake.lock b/systems/eldiron/flake.lock
index 27d4d5b..58291c5 100644
--- a/systems/eldiron/flake.lock
+++ b/systems/eldiron/flake.lock
@@ -129,7 +129,7 @@
129 "environment": { 129 "environment": {
130 "locked": { 130 "locked": {
131 "lastModified": 1, 131 "lastModified": 1,
132 "narHash": "sha256-VO82m/95IcX3xxJ63wcLh3hXzXDRFKUohYil/18pBSY=", 132 "narHash": "sha256-Kj3j/3B8V8IHbeSZ3ho33C7ktOcTle2h6dKEWWfVuvU=",
133 "path": "../environment", 133 "path": "../environment",
134 "type": "path" 134 "type": "path"
135 }, 135 },
@@ -141,7 +141,7 @@
141 "environment_2": { 141 "environment_2": {
142 "locked": { 142 "locked": {
143 "lastModified": 1, 143 "lastModified": 1,
144 "narHash": "sha256-VO82m/95IcX3xxJ63wcLh3hXzXDRFKUohYil/18pBSY=", 144 "narHash": "sha256-Kj3j/3B8V8IHbeSZ3ho33C7ktOcTle2h6dKEWWfVuvU=",
145 "path": "../environment", 145 "path": "../environment",
146 "type": "path" 146 "type": "path"
147 }, 147 },
@@ -153,7 +153,7 @@
153 "environment_3": { 153 "environment_3": {
154 "locked": { 154 "locked": {
155 "lastModified": 1, 155 "lastModified": 1,
156 "narHash": "sha256-VO82m/95IcX3xxJ63wcLh3hXzXDRFKUohYil/18pBSY=", 156 "narHash": "sha256-Kj3j/3B8V8IHbeSZ3ho33C7ktOcTle2h6dKEWWfVuvU=",
157 "path": "../environment", 157 "path": "../environment",
158 "type": "path" 158 "type": "path"
159 }, 159 },
@@ -165,7 +165,7 @@
165 "environment_4": { 165 "environment_4": {
166 "locked": { 166 "locked": {
167 "lastModified": 1, 167 "lastModified": 1,
168 "narHash": "sha256-VO82m/95IcX3xxJ63wcLh3hXzXDRFKUohYil/18pBSY=", 168 "narHash": "sha256-Kj3j/3B8V8IHbeSZ3ho33C7ktOcTle2h6dKEWWfVuvU=",
169 "path": "../environment", 169 "path": "../environment",
170 "type": "path" 170 "type": "path"
171 }, 171 },
@@ -177,7 +177,7 @@
177 "environment_5": { 177 "environment_5": {
178 "locked": { 178 "locked": {
179 "lastModified": 1, 179 "lastModified": 1,
180 "narHash": "sha256-VO82m/95IcX3xxJ63wcLh3hXzXDRFKUohYil/18pBSY=", 180 "narHash": "sha256-Kj3j/3B8V8IHbeSZ3ho33C7ktOcTle2h6dKEWWfVuvU=",
181 "path": "../environment", 181 "path": "../environment",
182 "type": "path" 182 "type": "path"
183 }, 183 },
@@ -189,7 +189,7 @@
189 "environment_6": { 189 "environment_6": {
190 "locked": { 190 "locked": {
191 "lastModified": 1, 191 "lastModified": 1,
192 "narHash": "sha256-VO82m/95IcX3xxJ63wcLh3hXzXDRFKUohYil/18pBSY=", 192 "narHash": "sha256-Kj3j/3B8V8IHbeSZ3ho33C7ktOcTle2h6dKEWWfVuvU=",
193 "path": "../environment", 193 "path": "../environment",
194 "type": "path" 194 "type": "path"
195 }, 195 },
@@ -1989,7 +1989,7 @@
1989 }, 1989 },
1990 "locked": { 1990 "locked": {
1991 "lastModified": 1, 1991 "lastModified": 1,
1992 "narHash": "sha256-ptLDqa3BTCX2orio9YgGsOwYa5bsz2DWn6TrtR2B45w=", 1992 "narHash": "sha256-Deh1qsi1UFskPSAwq2sUGyPeh7hVVHct8hhy4o6fEzE=",
1993 "path": "../../flakes/private/chatons", 1993 "path": "../../flakes/private/chatons",
1994 "type": "path" 1994 "type": "path"
1995 }, 1995 },
@@ -2001,7 +2001,7 @@
2001 "private-environment": { 2001 "private-environment": {
2002 "locked": { 2002 "locked": {
2003 "lastModified": 1, 2003 "lastModified": 1,
2004 "narHash": "sha256-VO82m/95IcX3xxJ63wcLh3hXzXDRFKUohYil/18pBSY=", 2004 "narHash": "sha256-Kj3j/3B8V8IHbeSZ3ho33C7ktOcTle2h6dKEWWfVuvU=",
2005 "path": "../../flakes/private/environment", 2005 "path": "../../flakes/private/environment",
2006 "type": "path" 2006 "type": "path"
2007 }, 2007 },
@@ -2020,7 +2020,7 @@
2020 }, 2020 },
2021 "locked": { 2021 "locked": {
2022 "lastModified": 1, 2022 "lastModified": 1,
2023 "narHash": "sha256-VhRXb3AAlSKwkq4BfVmoKzkLxEaAFGjYLAFETTZuhjE=", 2023 "narHash": "sha256-bWNhkERypwoog3lphO0xURJ4xt58CZEWKn7So7A5mtM=",
2024 "path": "../../flakes/private/milters", 2024 "path": "../../flakes/private/milters",
2025 "type": "path" 2025 "type": "path"
2026 }, 2026 },
@@ -2038,7 +2038,7 @@
2038 }, 2038 },
2039 "locked": { 2039 "locked": {
2040 "lastModified": 1, 2040 "lastModified": 1,
2041 "narHash": "sha256-Lpe56lKWhlMQiQoCgvMJuqJtJ8+szDldjqMAGyt2U3U=", 2041 "narHash": "sha256-VZjf9fXcyeS3LpVW6NvzJpiJuEtJsGlOOfH8XwL8CdI=",
2042 "path": "../../flakes/private/monitoring", 2042 "path": "../../flakes/private/monitoring",
2043 "type": "path" 2043 "type": "path"
2044 }, 2044 },
@@ -2073,7 +2073,7 @@
2073 }, 2073 },
2074 "locked": { 2074 "locked": {
2075 "lastModified": 1, 2075 "lastModified": 1,
2076 "narHash": "sha256-/vQ6FGFc53r79yiQrzF0NWTbRd4RKf8QiPSDhmiCciU=", 2076 "narHash": "sha256-fntajNe0urhuR0NbTOQZLTMhtHnd7p6PVuuEf0oAoFg=",
2077 "path": "../../flakes/private/opendmarc", 2077 "path": "../../flakes/private/opendmarc",
2078 "type": "path" 2078 "type": "path"
2079 }, 2079 },
@@ -2134,7 +2134,7 @@
2134 }, 2134 },
2135 "locked": { 2135 "locked": {
2136 "lastModified": 1, 2136 "lastModified": 1,
2137 "narHash": "sha256-gjapO6CZFeLMHUlhqBVZu5P+IJzJaPu4pnuTep4ZSuM=", 2137 "narHash": "sha256-uqftr7R3cVYwWuu8Xl6VbPVL2pqapv1bfmMJpq3LnZ4=",
2138 "path": "../../flakes/private/ssh", 2138 "path": "../../flakes/private/ssh",
2139 "type": "path" 2139 "type": "path"
2140 }, 2140 },
@@ -2153,7 +2153,7 @@
2153 }, 2153 },
2154 "locked": { 2154 "locked": {
2155 "lastModified": 1, 2155 "lastModified": 1,
2156 "narHash": "sha256-+s9C1mPCXRA44AC0Fg+B2uD6UiK0JfUA0F8fhceH0lQ=", 2156 "narHash": "sha256-ufaclDTTnoB7xLOCOY4EretrBp70rSmk0YzcVfglbLA=",
2157 "path": "../../flakes/private/system", 2157 "path": "../../flakes/private/system",
2158 "type": "path" 2158 "type": "path"
2159 }, 2159 },
diff --git a/systems/eldiron/ftp.nix b/systems/eldiron/ftp.nix
index 6aa1afc..e5bc0f5 100644
--- a/systems/eldiron/ftp.nix
+++ b/systems/eldiron/ftp.nix
@@ -30,6 +30,10 @@ in
30 }; 30 };
31 31
32 config = lib.mkIf config.myServices.ftp.enable { 32 config = lib.mkIf config.myServices.ftp.enable {
33 services.borgBackup.profiles.global.ignoredPaths = [
34 "ftp/test_ftp"
35 "proftpd/authorized_keys"
36 ];
33 myServices.dns.zones."immae.eu".subdomains.ftp = 37 myServices.dns.zones."immae.eu".subdomains.ftp =
34 with config.myServices.dns.helpers; ips servers.eldiron.ips.main; 38 with config.myServices.dns.helpers; ips servers.eldiron.ips.main;
35 39
diff --git a/systems/eldiron/gitolite/default.nix b/systems/eldiron/gitolite/default.nix
index 1885234..0882c18 100644
--- a/systems/eldiron/gitolite/default.nix
+++ b/systems/eldiron/gitolite/default.nix
@@ -11,6 +11,22 @@ in {
11 }; 11 };
12 12
13 config = lib.mkIf cfg.enable { 13 config = lib.mkIf cfg.enable {
14 services.borgBackup.profiles.global.ignoredPaths = [
15 "gitolite/.nix-.*"
16 "gitolite/.ssh"
17 "gitolite/.vim.*"
18 "gitolite/.bash_history"
19 ];
20 services.borgBackup.profiles.global.includedPaths = [
21 "gitolite/gitolite_ldap_groups.sh"
22 "gitolite/projects.list"
23 "gitolite/.gitolite.rc"
24 "gitolite/.gitolite"
25 "gitolite/repositories/github"
26 "gitolite/repositories/testing.git"
27 "gitolite/repositories/gitolite-admin.git"
28
29 ];
14 myServices.dns.zones."immae.eu".subdomains.git = 30 myServices.dns.zones."immae.eu".subdomains.git =
15 with config.myServices.dns.helpers; ips servers.eldiron.ips.main; 31 with config.myServices.dns.helpers; ips servers.eldiron.ips.main;
16 32
diff --git a/systems/eldiron/pub/default.nix b/systems/eldiron/pub/default.nix
index ca8122a..847e9d0 100644
--- a/systems/eldiron/pub/default.nix
+++ b/systems/eldiron/pub/default.nix
@@ -40,6 +40,9 @@ in
40 }; 40 };
41 41
42 config = lib.mkIf config.myServices.pub.enable { 42 config = lib.mkIf config.myServices.pub.enable {
43 services.borgBackup.profiles.global.ignoredPaths = [
44 "pub/.nix-.*"
45 ];
43 myServices.dns.zones."immae.eu".subdomains.pub = 46 myServices.dns.zones."immae.eu".subdomains.pub =
44 with config.myServices.dns.helpers; ips servers.eldiron.ips.main; 47 with config.myServices.dns.helpers; ips servers.eldiron.ips.main;
45 48
diff --git a/systems/eldiron/websites/cloud/default.nix b/systems/eldiron/websites/cloud/default.nix
index e1df883..c859f32 100644
--- a/systems/eldiron/websites/cloud/default.nix
+++ b/systems/eldiron/websites/cloud/default.nix
@@ -9,6 +9,15 @@ in {
9 }; 9 };
10 10
11 config = lib.mkIf cfg.enable { 11 config = lib.mkIf cfg.enable {
12 services.borgBackup.profiles.global.includedPaths = [
13 "nextcloud/appdata_occ80acffb591"
14 "nextcloud/files_external"
15 "nextcloud/config"
16 #"nextcloud/gpxpod"
17 "nextcloud/.ocdata"
18 "nextcloud/.htaccess"
19 "nextcloud/index.html"
20 ];
12 myServices.dns.zones."immae.eu".subdomains.cloud = 21 myServices.dns.zones."immae.eu".subdomains.cloud =
13 with config.myServices.dns.helpers; ips servers.eldiron.ips.main; 22 with config.myServices.dns.helpers; ips servers.eldiron.ips.main;
14 23
diff --git a/systems/eldiron/websites/commento/default.nix b/systems/eldiron/websites/commento/default.nix
index c5131b8..9abc180 100644
--- a/systems/eldiron/websites/commento/default.nix
+++ b/systems/eldiron/websites/commento/default.nix
@@ -12,6 +12,9 @@ in
12 enable = lib.mkEnableOption "Enable commento website"; 12 enable = lib.mkEnableOption "Enable commento website";
13 }; 13 };
14 config = lib.mkIf cfg.enable { 14 config = lib.mkIf cfg.enable {
15 services.borgBackup.profiles.global.includedPaths = [
16 "vhost/tools.immae.eu/commento"
17 ];
15 myServices.dns.zones."immae.eu".subdomains.commento = 18 myServices.dns.zones."immae.eu".subdomains.commento =
16 with config.myServices.dns.helpers; ips servers.eldiron.ips.main; 19 with config.myServices.dns.helpers; ips servers.eldiron.ips.main;
17 20
diff --git a/systems/eldiron/websites/cryptpad/default.nix b/systems/eldiron/websites/cryptpad/default.nix
index 4635548..34a51cd 100644
--- a/systems/eldiron/websites/cryptpad/default.nix
+++ b/systems/eldiron/websites/cryptpad/default.nix
@@ -75,6 +75,9 @@ in
75 inherit domain port; 75 inherit domain port;
76 config = configFile; 76 config = configFile;
77 }; 77 };
78 services.borgBackup.profiles.global.includedPaths = [
79 "cryptpad/immaeEu"
80 ];
78 services.websites.env.tools.modules = [ "proxy_wstunnel" ]; 81 services.websites.env.tools.modules = [ "proxy_wstunnel" ];
79 security.acme.certs.eldiron.extraDomainNames = [ domain ]; 82 security.acme.certs.eldiron.extraDomainNames = [ domain ];
80 services.websites.env.tools.vhostConfs.cryptpad = { 83 services.websites.env.tools.vhostConfs.cryptpad = {
diff --git a/systems/eldiron/websites/tools/default.nix b/systems/eldiron/websites/tools/default.nix
index b591190..46e6a9f 100644
--- a/systems/eldiron/websites/tools/default.nix
+++ b/systems/eldiron/websites/tools/default.nix
@@ -110,6 +110,21 @@ in {
110 ]; 110 ];
111 }; 111 };
112 112
113 services.borgBackup.profiles.global.ignoredPaths = [
114 "duply"
115 "kanboard"
116 "ntfy"
117 ];
118 services.borgBackup.profiles.global.includedPaths = [
119 "paste"
120 "dokuwiki/conf"
121 "dokuwiki/data"
122 "phpbb"
123 "shaarli/cache"
124 "shaarli/pagecache"
125 "shaarli/tmp"
126 ];
127
113 myServices.chatonsProperties.services = { 128 myServices.chatonsProperties.services = {
114 adminer = adminer.chatonsProperties; 129 adminer = adminer.chatonsProperties;
115 dokuwiki = dokuwiki.chatonsProperties; 130 dokuwiki = dokuwiki.chatonsProperties;