aboutsummaryrefslogtreecommitdiffstats
path: root/modules/by-name/ba/backup
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--modules/by-name/ba/backup/module.nix98
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;
};
};
};