From 52ec14a3c15767684e3cd8c72467f789330f8e88 Mon Sep 17 00:00:00 2001 From: Felix Buehler Date: Sun, 4 Dec 2022 18:06:51 +0100 Subject: [PATCH] service/backup: modularize backup --- modules/services/backup/default.nix | 131 ++++++++++++++++++++++++++++ modules/services/default.nix | 1 + nixos/modules/backup.nix | 79 ----------------- nixos/serverle/backup.nix | 79 ----------------- nixos/serverle/services.nix | 10 +++ nixos/thinkman/configuration.nix | 2 +- nixos/thinkman/services.nix | 19 ++++ 7 files changed, 162 insertions(+), 159 deletions(-) create mode 100644 modules/services/backup/default.nix delete mode 100644 nixos/modules/backup.nix delete mode 100644 nixos/serverle/backup.nix create mode 100644 nixos/thinkman/services.nix diff --git a/modules/services/backup/default.nix b/modules/services/backup/default.nix new file mode 100644 index 0000000..d3390db --- /dev/null +++ b/modules/services/backup/default.nix @@ -0,0 +1,131 @@ +{ config, lib, pkgs, ... }: +let + cfg = config.my.services.backup; + borgbackupPath = "u181505-sub1@u181505-sub1.your-storagebox.de"; +in +{ + options.my.services.backup = with lib; { + enable = mkEnableOption "Borgbackup Service"; + + passwordFile = mkOption { + type = types.path; + description = "Password for the backup"; + example = "/run/secrets/password"; + }; + sshKeyFile = mkOption { + type = types.path; + description = "ssh-key for remote access"; + example = "/run/secrets/ssh_key"; + }; + + OnFailureNotification = mkOption { + type = types.bool; + description = "whether to show a warning to all users or not"; + default = false; + }; + OnFailureMail = mkOption { + type = types.nullOr (types.str); + description = "Mail adress where to send the error report"; + default = null; + example = "alarm@mail.com"; + }; + + paths = mkOption { + type = with types; listOf str; + description = "additional path(s) to back up"; + default = [ "/" ]; + example = [ + "/home/user" + ]; + }; + exclude = mkOption { + type = with types; listOf str; + description = "Exclude paths matching any of the given patterns. See `borg help patterns`"; + default = [ ]; + example = [ + "/home/*/.cache" + "/tmp" + ]; + }; + }; + + config = lib.mkIf cfg.enable { + # mails can only be delivered if postfix is available + services.postfix.enable = cfg.OnFailureMail != null; + + services.borgbackup.jobs.hetzner = { + # always backup everything and only define excludes + inherit (cfg) paths; + exclude = [ + "/nix" + "/sys" + "/run" + "/proc" + "/root/.cache/" + "**/.Trash" + "/tmp" + + "/var/lock" + "/var/lib/docker/devicemapper" + "/var/run" + "/var/tmp" + + "/srv/data/tmp" + "/srv/data/todo" + + "/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}"; + }; + + environment.BORG_RSH = "ssh -o 'StrictHostKeyChecking=no' -i ${cfg.sshKeyFile} -p 23"; + repo = borgbackupPath + ":${config.networking.hostName}/"; + + doInit = false; + compression = "auto,zstd"; + + postHook = '' + if [[ $exitStatus != 0 ]]; then + '' + 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" -s "Backup Error" server@buehler.rocks + echo "sent mail" + '' + '' + fi + ''; + + startAt = "daily"; + persistentTimer = true; + prune.keep = { + last = 1; + within = "3d"; + daily = 7; + weekly = 4; + monthly = 6; + yearly = 2; + }; + }; + }; +} diff --git a/modules/services/default.nix b/modules/services/default.nix index d7a2fd8..1f0b73a 100644 --- a/modules/services/default.nix +++ b/modules/services/default.nix @@ -1,6 +1,7 @@ { ... }: { imports = [ + ./backup ./gitea ./hedgedoc ./homepage diff --git a/nixos/modules/backup.nix b/nixos/modules/backup.nix deleted file mode 100644 index e25ea11..0000000 --- a/nixos/modules/backup.nix +++ /dev/null @@ -1,79 +0,0 @@ -{ config, lib, pkgs, ... }: -let - borgbackupPath = "u181505-sub1@u181505-sub1.your-storagebox.de"; - borgbackupMonitor = { config, pkgs, lib, ... }: with lib; { - key = "borgbackupMonitor"; - _file = "borgbackupMonitor"; - config.systemd.services = { - "notify-problems@" = { - enable = true; - serviceConfig.User = "felix"; - environment.SERVICE = "%i"; - script = '' - export $(cat /proc/$(${pkgs.procps}/bin/pgrep -x "sway" -u "$USER")/environ |grep -z '^DBUS_SESSION_BUS_ADDRESS=') - ${pkgs.libnotify}/bin/notify-send -u critical "$SERVICE FAILED!" "Run journalctl -u $SERVICE for details" - ''; - }; - } // flip mapAttrs' config.services.borgbackup.jobs (name: value: - nameValuePair "borgbackup-job-${name}" { - unitConfig.OnFailure = "notify-problems@%i.service"; - } - ); - }; - -in -{ - # notification - imports = [ - borgbackupMonitor - ]; - - sops.secrets."borgbackup/password" = { }; - sops.secrets."borgbackup/private_ssh_key" = { }; - - services.borgbackup.jobs.hetzner = { - paths = [ - "/" - ]; - exclude = [ - "/nix" - "/sys" - "/run" - "/proc" - "/root/.cache/" - "**/.Trash" - "/tmp" - "/var/lock" - "/var/lib/docker/devicemapper" - "/var/run" - "/var/tmp" - "/srv/data/tmp" - "/srv/data/todo" - "/home/*/.gvfs" - "/home/*/tmp" - "/home/*/todo" - "sh:/home/*/.cache" - "sh:/home/*/.local/share/Trash" - "sh:/home/*/.thumbnails" - ]; - extraCreateArgs = "--exclude-caches --keep-exclude-tags --stats"; - encryption = { - mode = "repokey-blake2"; - passCommand = "cat ${config.sops.secrets."borgbackup/password".path}"; - }; - environment.BORG_RSH = "ssh -o 'StrictHostKeyChecking=no' -i ${config.sops.secrets."borgbackup/private_ssh_key".path} -p 23"; - repo = borgbackupPath + ":${config.networking.hostName}/"; - compression = "auto,zstd"; - doInit = false; - startAt = "daily"; - persistentTimer = true; - prune.keep = { - last = 1; - within = "3d"; - daily = 7; - weekly = 4; - monthly = 6; - yearly = 2; - }; - }; -} diff --git a/nixos/serverle/backup.nix b/nixos/serverle/backup.nix deleted file mode 100644 index 0f3fe59..0000000 --- a/nixos/serverle/backup.nix +++ /dev/null @@ -1,79 +0,0 @@ -{ config, lib, pkgs, ... }: -let - borgbackupPath = "u181505-sub1@u181505-sub1.your-storagebox.de:serverle/"; - borgbackupMonitor = { config, pkgs, lib, ... }: with lib; { - key = "borgbackupMonitor"; - _file = "borgbackupMonitor"; - config.systemd.services = { - "notify-problems@" = { - enable = true; - serviceConfig.User = "felix"; - environment.SERVICE = "%i"; - script = '' - export $(cat /proc/$(${pkgs.procps}/bin/pgrep -x "sway" -u "$USER")/environ |grep -z '^DBUS_SESSION_BUS_ADDRESS=') - ${pkgs.libnotify}/bin/notify-send -u critical "$SERVICE FAILED!" "Run journalctl -u $SERVICE for details" - ''; - }; - } // flip mapAttrs' config.services.borgbackup.jobs (name: value: - nameValuePair "borgbackup-job-${name}" { - unitConfig.OnFailure = "notify-problems@%i.service"; - } - ); - }; - -in -{ - # notification - imports = [ - borgbackupMonitor - ]; - - sops.defaultSopsFile = ./secrets.yaml; - sops.secrets."borgbackup/password" = { }; - sops.secrets."borgbackup/private_ssh_key" = { }; - - services.borgbackup.jobs.hetzner = { - paths = [ - "/" - ]; - exclude = [ - "/nix" - "/sys" - "/run" - "/proc" - "/root/.cache/" - "**/.Trash" - "/tmp/*" - "/var/lock/*" - "/var/run/*" - "/var/tmp/*" - "/home/*/tmp" - "/home/*/todo" - "/home/*/.cache" - "/home/*/.gvfs" - "/home/*/.thumbnails" - "/home/*/.local/share/Trash" - "/srv/data/tmp" - "/srv/data/todo" - ]; - extraCreateArgs = "--exclude-caches --keep-exclude-tags --stats"; - encryption = { - mode = "repokey-blake2"; - passCommand = "cat ${config.sops.secrets."borgbackup/password".path}"; - }; - environment.BORG_RSH = "ssh -o 'StrictHostKeyChecking=no' -i ${config.sops.secrets."borgbackup/private_ssh_key".path} -p 23"; - repo = borgbackupPath; - compression = "auto,zstd"; - doInit = false; - startAt = "daily"; - persistentTimer = true; - prune.keep = { - last = 1; - within = "3d"; - daily = 7; - weekly = 4; - monthly = 6; - yearly = 2; - }; - }; -} diff --git a/nixos/serverle/services.nix b/nixos/serverle/services.nix index 14ebd09..4d2f431 100644 --- a/nixos/serverle/services.nix +++ b/nixos/serverle/services.nix @@ -4,8 +4,18 @@ let secrets = config.sops.secrets; in { + sops.secrets."borgbackup/password" = { }; + sops.secrets."borgbackup/private_ssh_key" = { }; + # List services that you want to enable: my.services = { + backup = { + enable = true; + OnFailureMail = "server@buehler.rocks"; + passwordFile = secrets."borgbackup/password".path; + sshKeyFile = secrets."borgbackup/private_ssh_key".path; + }; + ssh-server = { enable = true; }; diff --git a/nixos/thinkman/configuration.nix b/nixos/thinkman/configuration.nix index bbd7864..705b3c0 100644 --- a/nixos/thinkman/configuration.nix +++ b/nixos/thinkman/configuration.nix @@ -3,10 +3,10 @@ imports = [ ./disks.nix ./hardware-configuration.nix + ./services.nix ../modules/3d-design.nix ../modules/android.nix ../modules/avahi.nix - ../modules/backup.nix ../modules/bluetooth-audio.nix ../modules/clean.nix ../modules/desktop-default.nix diff --git a/nixos/thinkman/services.nix b/nixos/thinkman/services.nix new file mode 100644 index 0000000..973e019 --- /dev/null +++ b/nixos/thinkman/services.nix @@ -0,0 +1,19 @@ +# Deployed services +{ config, lib, ... }: +let + secrets = config.sops.secrets; +in +{ + sops.secrets."borgbackup/password" = { }; + sops.secrets."borgbackup/private_ssh_key" = { }; + + # List services that you want to enable: + my.services = { + backup = { + enable = true; + OnFailureNotification = true; + passwordFile = secrets."borgbackup/password".path; + sshKeyFile = secrets."borgbackup/private_ssh_key".path; + }; + }; +}