diff options
Diffstat (limited to 'modules/by-name/ba/backup/module.nix')
-rw-r--r-- | modules/by-name/ba/backup/module.nix | 98 |
1 files changed, 68 insertions, 30 deletions
diff --git a/modules/by-name/ba/backup/module.nix b/modules/by-name/ba/backup/module.nix index 95abcb14..63186e91 100644 --- a/modules/by-name/ba/backup/module.nix +++ b/modules/by-name/ba/backup/module.nix @@ -9,50 +9,88 @@ # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>. { lib, - pkgs, config, + pkgs, ... }: let - backup-script = pkgs.writeShellScriptBin "backsnap" '' - set -xeu; - - ${pkgs.util-linux}/bin/mount --mkdir "/dev/disk/by-uuid/${cfg.backupDiskUuid}" "/run/media/${cfg.backupDiskUuid}"; - ${pkgs.snap-sync-forked}/bin/snap-sync-forked --UUID "${cfg.backupDiskUuid}" --noconfirm; - ${pkgs.util-linux}/bin/umount "/run/media/${cfg.backupDiskUuid}"; - ''; - cfg = config.soispha.services.backup; in { options.soispha.services.backup = { - enable = lib.mkEnableOption "backups with my forked snap-sync"; - backupDiskUuid = lib.mkOption { + enable = lib.mkEnableOption "backups via restic to a storagebox"; + + user = lib.mkOption { type = lib.types.str; - example = lib.literalExpression "d1d20ae7-3d8a-44da-86da-677dbbb10c89"; - description = "The UUID of the backup disk"; + description = "The storagebox-user to use"; + example = "u384702-sub2"; + }; + privateSshKey = lib.mkOption { + type = lib.types.path; + description = "The age-encrypted ssh-key, passed to agenix"; + }; + privatePassword = lib.mkOption { + type = lib.types.path; + description = "The age-encrypted restic password, passed to agenix"; }; }; config = lib.mkIf cfg.enable { - systemd = { - services.backup = { - wantedBy = lib.mkForce []; - unitConfig = { - Description = "Backup the last snapshots of the persitent-storage subvolume."; - }; - serviceConfig = { - Type = "oneshot"; - ExecStart = "${backup-script}/bin/backsnap"; - }; + age.secrets = { + resticpass = { + file = cfg.privatePassword; + mode = "0700"; + owner = "root"; + group = "root"; }; + resticssh = { + file = cfg.privateSshKey; + mode = "0700"; + owner = "root"; + group = "root"; + }; + }; + + services.restic.backups = let + snapshotDir = "/srv/snapshots"; + homeDir = "${snapshotDir}/home"; + in { + storagebox = { + initialize = true; + backupPrepareCommand = + # bash + '' + [ -d /srv/snapshots/home ] && ${lib.getExe' pkgs.btrfs-progs "btrfs"} subvolume delete /srv/snapshots/home; + + # -r := Make the snapshot read-only + ${lib.getExe' pkgs.btrfs-progs "btrfs"} subvolume snapshot -r /home /srv/snapshots/home; + + [ -d /srv/snapshots/srv ] && ${lib.getExe' pkgs.btrfs-progs "btrfs"} subvolume delete /srv/snapshots/srv; + ${lib.getExe' pkgs.btrfs-progs "btrfs"} subvolume snapshot -r /srv /srv/snapshots/srv; + ''; + paths = [ + snapshotDir + ]; + exclude = [ + "${homeDir}/soispha/.cache" + ]; + extraBackupArgs = [ + "--verbose" # Spam log + ]; + + passwordFile = config.age.secrets.resticpass.path; + extraOptions = [ + "rclone.program='ssh -p 23 ${cfg.user}@${cfg.user}.your-storagebox.de -i ${config.age.secrets.resticssh.path} command_forced_on_remote'" + ]; + + # This setting is normally passed to rclone, but we force + # the command on the remote. + # As such, the value does not matter and must only be parseable by restic. + repository = "rclone: "; - timers.backup = { - wantedBy = ["timers.target"]; - unitConfig = { - Description = "Backup 15min after boot and every 8 hours"; - }; timerConfig = { - OnBootSec = "15min"; - OnUnitActiveSec = "8h"; + Requires = "network-online.target"; + OnActiveSec = "30m"; + OnUnitInactiveSec = "2h"; + Persistent = true; }; }; }; |