| 
									
										
										
										
											2022-12-04 18:06:51 +01:00
										 |  |  | { config, lib, pkgs, ... }: | 
					
						
							|  |  |  | let | 
					
						
							|  |  |  |   cfg = config.my.services.backup; | 
					
						
							|  |  |  | in | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   options.my.services.backup = with lib; { | 
					
						
							| 
									
										
										
										
											2023-02-11 21:44:10 +01:00
										 |  |  |     enable = mkEnableOption (lib.mdDoc "Borgbackup Service"); | 
					
						
							| 
									
										
										
										
											2022-12-04 18:06:51 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     passwordFile = mkOption { | 
					
						
							|  |  |  |       type = types.path; | 
					
						
							| 
									
										
										
										
											2023-02-11 21:44:10 +01:00
										 |  |  |       description = lib.mdDoc "Password for the backup"; | 
					
						
							| 
									
										
										
										
											2022-12-04 18:06:51 +01:00
										 |  |  |       example = "/run/secrets/password"; | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2023-02-08 00:52:42 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     sshHost = mkOption { | 
					
						
							|  |  |  |       type = types.str; | 
					
						
							| 
									
										
										
										
											2023-02-11 21:44:10 +01:00
										 |  |  |       description = lib.mdDoc "ssh-hostname for remote access"; | 
					
						
							| 
									
										
										
										
											2023-02-08 00:52:42 +01:00
										 |  |  |       default = "u181505-sub1.your-storagebox.de"; | 
					
						
							|  |  |  |       example = "test.domain.com"; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     sshUser = mkOption { | 
					
						
							|  |  |  |       type = types.str; | 
					
						
							| 
									
										
										
										
											2023-02-11 21:44:10 +01:00
										 |  |  |       description = lib.mdDoc "ssh-user for remote access"; | 
					
						
							| 
									
										
										
										
											2023-02-08 00:52:42 +01:00
										 |  |  |       default = "u181505-sub1"; | 
					
						
							|  |  |  |       example = "max"; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     sshPort = mkOption { | 
					
						
							|  |  |  |       type = types.port; | 
					
						
							| 
									
										
										
										
											2023-02-11 21:44:10 +01:00
										 |  |  |       description = lib.mdDoc "ssh-port for remote access"; | 
					
						
							| 
									
										
										
										
											2023-02-08 00:52:42 +01:00
										 |  |  |       default = 23; | 
					
						
							|  |  |  |       example = 22; | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2022-12-04 18:06:51 +01:00
										 |  |  |     sshKeyFile = mkOption { | 
					
						
							|  |  |  |       type = types.path; | 
					
						
							| 
									
										
										
										
											2023-02-11 21:44:10 +01:00
										 |  |  |       description = lib.mdDoc "ssh-key for remote access"; | 
					
						
							| 
									
										
										
										
											2022-12-04 18:06:51 +01:00
										 |  |  |       example = "/run/secrets/ssh_key"; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     OnFailureNotification = mkOption { | 
					
						
							|  |  |  |       type = types.bool; | 
					
						
							| 
									
										
										
										
											2023-02-11 21:44:10 +01:00
										 |  |  |       description = lib.mdDoc "whether to show a warning to all users or not"; | 
					
						
							| 
									
										
										
										
											2022-12-04 18:06:51 +01:00
										 |  |  |       default = false; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     OnFailureMail = mkOption { | 
					
						
							| 
									
										
										
										
											2023-11-07 23:13:51 +01:00
										 |  |  |       type = types.nullOr types.str; | 
					
						
							| 
									
										
										
										
											2023-06-22 20:54:16 +02:00
										 |  |  |       description = lib.mdDoc "Mail address where to send the error report"; | 
					
						
							| 
									
										
										
										
											2022-12-04 18:06:51 +01:00
										 |  |  |       default = null; | 
					
						
							|  |  |  |       example = "alarm@mail.com"; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     paths = mkOption { | 
					
						
							|  |  |  |       type = with types; listOf str; | 
					
						
							| 
									
										
										
										
											2023-02-11 21:44:10 +01:00
										 |  |  |       description = lib.mdDoc "additional path(s) to back up"; | 
					
						
							| 
									
										
										
										
											2022-12-04 18:06:51 +01:00
										 |  |  |       default = [ "/" ]; | 
					
						
							|  |  |  |       example = [ | 
					
						
							|  |  |  |         "/home/user" | 
					
						
							|  |  |  |       ]; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     exclude = mkOption { | 
					
						
							|  |  |  |       type = with types; listOf str; | 
					
						
							| 
									
										
										
										
											2023-02-11 21:44:10 +01:00
										 |  |  |       description = lib.mdDoc "Exclude paths matching any of the given patterns. See `borg help patterns`"; | 
					
						
							| 
									
										
										
										
											2022-12-04 18:06:51 +01:00
										 |  |  |       default = [ ]; | 
					
						
							|  |  |  |       example = [ | 
					
						
							|  |  |  |         "/home/*/.cache" | 
					
						
							|  |  |  |         "/tmp" | 
					
						
							|  |  |  |       ]; | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2023-02-11 21:44:10 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     doInit = mkOption { | 
					
						
							|  |  |  |       type = types.bool; | 
					
						
							|  |  |  |       description = lib.mdDoc ''
 | 
					
						
							|  |  |  |         Run {command}`borg init` if the | 
					
						
							|  |  |  |         specified {option}`repo` does not exist. | 
					
						
							|  |  |  |         You should set this to `false` | 
					
						
							|  |  |  |         if the repository is located on an external drive | 
					
						
							|  |  |  |         that might not always be mounted. | 
					
						
							|  |  |  |       '';
 | 
					
						
							|  |  |  |       default = false; | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2022-12-04 18:06:51 +01:00
										 |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   config = lib.mkIf cfg.enable { | 
					
						
							|  |  |  |     # mails can only be delivered if postfix is available | 
					
						
							| 
									
										
										
										
											2023-03-19 16:14:20 +01:00
										 |  |  |     services.postfix.enable = lib.mkIf (cfg.OnFailureMail != null) true; | 
					
						
							| 
									
										
										
										
											2022-12-04 18:06:51 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     services.borgbackup.jobs.hetzner = { | 
					
						
							|  |  |  |       # always backup everything and only define excludes | 
					
						
							|  |  |  |       inherit (cfg) paths; | 
					
						
							|  |  |  |       exclude = [ | 
					
						
							|  |  |  |         "/nix" | 
					
						
							|  |  |  |         "/sys" | 
					
						
							|  |  |  |         "/run" | 
					
						
							|  |  |  |         "/proc" | 
					
						
							|  |  |  |         "/root/.cache/" | 
					
						
							| 
									
										
										
										
											2023-01-29 15:22:46 +01:00
										 |  |  |         "/root/.config/borg/security/" | 
					
						
							| 
									
										
										
										
											2022-12-04 18:06:51 +01:00
										 |  |  |         "**/.Trash" | 
					
						
							|  |  |  |         "/tmp" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         "/var/lock" | 
					
						
							|  |  |  |         "/var/lib/docker/devicemapper" | 
					
						
							|  |  |  |         "/var/run" | 
					
						
							|  |  |  |         "/var/tmp" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-07 00:00:34 +02:00
										 |  |  |         "/data/tmp" | 
					
						
							|  |  |  |         "/data/todo" | 
					
						
							| 
									
										
										
										
											2022-12-04 18:06:51 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         "/home/*/.cache" | 
					
						
							|  |  |  |         "/home/*/.gvfs" | 
					
						
							|  |  |  |         "/home/*/.local/share/Trash" | 
					
						
							|  |  |  |         "/home/*/.thumbnails" | 
					
						
							|  |  |  |         "/home/*/tmp" | 
					
						
							|  |  |  |         "/home/*/todo" | 
					
						
							|  |  |  |       ] ++ cfg.exclude; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       extraCreateArgs = "--exclude-caches --keep-exclude-tags --stats"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       encryption = { | 
					
						
							|  |  |  |         mode = "repokey-blake2"; | 
					
						
							|  |  |  |         passCommand = "cat ${cfg.passwordFile}"; | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-08 00:52:42 +01:00
										 |  |  |       environment.BORG_RSH = "ssh -o 'StrictHostKeyChecking=no' -i ${cfg.sshKeyFile} -p ${toString cfg.sshPort}"; | 
					
						
							|  |  |  |       repo = "${cfg.sshUser}@${cfg.sshHost}:${config.networking.hostName}/"; | 
					
						
							| 
									
										
										
										
											2022-12-04 18:06:51 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-07 23:13:51 +01:00
										 |  |  |       inherit (cfg) doInit; | 
					
						
							| 
									
										
										
										
											2022-12-04 18:06:51 +01:00
										 |  |  |       compression = "auto,zstd"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       postHook = ''
 | 
					
						
							| 
									
										
										
										
											2023-09-11 20:00:32 +02:00
										 |  |  |         if (( $exitStatus > 1 )); then | 
					
						
							| 
									
										
										
										
											2022-12-04 18:06:51 +01:00
										 |  |  |       '' + lib.optionalString cfg.OnFailureNotification '' | 
					
						
							|  |  |  |         # iterate over all logged in users | 
					
						
							|  |  |  |         for user in $(users); do | 
					
						
							|  |  |  |           sway_pid=$(${pkgs.procps}/bin/pgrep -x "sway" -u "$user") | 
					
						
							|  |  |  |           if [ -n "$sway_pid" ]; then | 
					
						
							|  |  |  |             # set environment variables | 
					
						
							|  |  |  |             export $(cat /proc/$sway_pid/environ | grep -z '^DBUS_SESSION_BUS_ADDRESS=' | tr -d '\0') | 
					
						
							|  |  |  |             export DISPLAY=:0 | 
					
						
							|  |  |  |             # send notification via dbus: https://wiki.archlinux.org/title/Desktop_notifications#Bash | 
					
						
							|  |  |  |             ${pkgs.sudo}/bin/sudo --preserve-env=DBUS_SESSION_BUS_ADDRESS,DISPLAY -u $user ${pkgs.libnotify}/bin/notify-send -u critical "BorgBackup Failed!" "Run journalctl -u borgbackup-job* for more details." | 
					
						
							|  |  |  |             echo "sent notification" | 
					
						
							|  |  |  |           fi | 
					
						
							|  |  |  |         done | 
					
						
							|  |  |  |       '' + lib.optionalString (cfg.OnFailureMail != null) '' | 
					
						
							|  |  |  |         journalctl -u borgbackup-job-hetzner.service | ${pkgs.mailutils}/bin/mail -r "Administrator<root@buehler.rocks>" -s "Backup Error" server@buehler.rocks | 
					
						
							|  |  |  |         echo "sent mail" | 
					
						
							|  |  |  |       '' + '' | 
					
						
							|  |  |  |         fi | 
					
						
							|  |  |  |       '';
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-29 20:15:49 +01:00
										 |  |  |       # for mail sending | 
					
						
							|  |  |  |       readWritePaths = lib.optional (cfg.OnFailureMail != null) "/var/lib/postfix/queue/maildrop/"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 18:06:51 +01:00
										 |  |  |       startAt = "daily"; | 
					
						
							|  |  |  |       persistentTimer = true; | 
					
						
							|  |  |  |       prune.keep = { | 
					
						
							|  |  |  |         last = 1; | 
					
						
							|  |  |  |         within = "3d"; | 
					
						
							|  |  |  |         daily = 7; | 
					
						
							|  |  |  |         weekly = 4; | 
					
						
							|  |  |  |         monthly = 6; | 
					
						
							|  |  |  |         yearly = 2; | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2023-06-19 22:20:36 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     my.services.prometheus.rules = { | 
					
						
							|  |  |  |       borgbackup_execution_missing = { | 
					
						
							|  |  |  |         condition = ''time() - systemd_timer_last_trigger_seconds{name="borgbackup-job-hetzner.timer"} >= (60 * 60 * (24 + 1))''; | 
					
						
							|  |  |  |         description = "{{$labels.instance}}: last backup was 25 hours ago please check."; | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  |       borgbackup_last_execution = { | 
					
						
							|  |  |  |         condition = ''systemd_unit_state{state="failed", name="borgbackup-job-hetzner.timer"} >= 1''; | 
					
						
							| 
									
										
										
										
											2023-06-22 20:54:16 +02:00
										 |  |  |         description = "{{$labels.instance}}: last backup was not successful please check."; | 
					
						
							| 
									
										
										
										
											2023-06-19 22:20:36 +02:00
										 |  |  |       }; | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2022-12-04 18:06:51 +01:00
										 |  |  |   }; | 
					
						
							|  |  |  | } |