diff --git a/hosts/hel1-a/configuration.nix b/hosts/hel1-a/configuration.nix index 6ea71bd..7c78a0b 100644 --- a/hosts/hel1-a/configuration.nix +++ b/hosts/hel1-a/configuration.nix @@ -77,6 +77,30 @@ in { enable = true; mountpoints = ["/var/lib" "/var/log"]; }; + + zfsborg = { + enable = true; + repo = "zh2769@zh2769.rsync.net:hel1-a.servers.jakst"; + passwdPath = config.age.secrets.borgbackup-password.path; + mountpoints = { + "/var/lib" = { + paths = [ + "/var/lib/.snapshot-latest/gitea" + "/var/lib/.snapshot-latest/headscale" + "/var/lib/.snapshot-latest/matrix-synapse" + ]; + backup_at = "*-*-* 00:11:00"; + }; + "/var/log" = { + paths = ["/var/log/.snapshot-latest/caddy/"]; + patterns = [ + "+ /var/log/.snapshot-latest/caddy/access-jakstys.lt.log-*.zst" + "- *" + ]; + backup_at = "*-*-* 00:10:00"; + }; + }; + }; }; }; @@ -147,43 +171,6 @@ in { localuser = null; }; - borgbackup.jobs = - lib.mapAttrs' (name: value: let - snapshot = { - mountpoint = value.mountpoint; - zfs_name = value.zfs_name; - }; - rwpath = value.mountpoint + "/.snapshot-latest"; - in { - name = name; - value = - { - doInit = true; - repo = "zh2769@zh2769.rsync.net:hel1-a.servers.jakst"; - encryption = { - mode = "repokey-blake2"; - passCommand = "cat ${config.age.secrets.borgbackup-password.path}"; - }; - paths = value.paths; - extraArgs = "--remote-path=borg1"; - compression = "auto,lzma"; - startAt = value.backup_at; - readWritePaths = [rwpath]; - preHook = mountLatest snapshot; - postHook = umountLatest snapshot; - prune.keep = { - within = "1d"; - daily = 7; - weekly = 4; - monthly = 3; - }; - } - // lib.optionalAttrs (value ? patterns) { - patterns = value.patterns; - }; - }) - backup_paths; - headscale = { enable = true; settings = { @@ -539,20 +526,6 @@ in { systemd.services = { - "make-snapshot-dirs" = let - vals = builtins.attrValues backup_paths; - mountpoints = builtins.catAttrs "mountpoint" vals; - unique_mountpoints = lib.unique mountpoints; - in { - description = "prepare snapshot directories for backups"; - wantedBy = ["multi-user.target"]; - serviceConfig = { - Type = "oneshot"; - ExecStart = builtins.map (d: "${pkgs.coreutils}/bin/mkdir -p ${d}/.snapshot-latest") unique_mountpoints; - RemainAfterExit = true; - }; - }; - coturn = { preStart = '' ln -sf ''${CREDENTIALS_DIRECTORY}/tls-key.pem /run/coturn/tls-key.pem diff --git a/modules/base/default.nix b/modules/base/default.nix index d54c1c9..9fb41fc 100644 --- a/modules/base/default.nix +++ b/modules/base/default.nix @@ -9,6 +9,7 @@ ./sshd ./initrd ./snapshot + ./zfsborg ]; options.mj = { diff --git a/modules/base/zfsborg/default.nix b/modules/base/zfsborg/default.nix new file mode 100644 index 0000000..effc102 --- /dev/null +++ b/modules/base/zfsborg/default.nix @@ -0,0 +1,92 @@ +{ + config, + lib, + pkgs, + myData, + ... +}: let + mountLatest = mountpoint: zfs_name: '' + set -euo pipefail + ${pkgs.util-linux}/bin/umount ${mountpoint}/.snapshot-latest &>/dev/null || : + mkdir -p ${mountpoint}/.snapshot-latest + ${pkgs.util-linux}/bin/mount -t zfs $(${pkgs.zfs}/bin/zfs list -H -t snapshot -o name ${zfs_name} | sort | tail -1) ${mountpoint}/.snapshot-latest + ''; + + umountLatest = mountpoint: '' + exec ${pkgs.util-linux}/bin/umount ${mountpoint}/.snapshot-latest + ''; +in { + options.mj.base.zfsborg = { + enable = lib.mkEnableOption "backup zfs snapshots with borg"; + + repo = with lib.types; lib.mkOption {type = str;}; + passwdPath = with lib.types; lib.mkOption {type = str;}; + + mountpoints = lib.mkOption { + default = {}; + type = with lib.types; + attrsOf (submodule ( + {...}: { + options = { + paths = lib.mkOption {type = listOf path;}; + patterns = lib.mkOption { + type = listOf str; + default = []; + }; + backup_at = lib.mkOption {type = str;}; + }; + } + )); + }; + }; + + config = lib.mkIf config.mj.base.zfsborg.enable { + systemd.services."zfsborg-snapshot-dirs" = let + mountpoints = lib.unique (lib.attrNames config.mj.base.zfsborg.mountpoints); + in { + description = "zfsborg prepare snapshot directories"; + wantedBy = ["multi-user.target"]; + serviceConfig = { + Type = "oneshot"; + ExecStart = + builtins.map + (d: "${pkgs.coreutils}/bin/mkdir -p ${d}/.snapshot-latest") + mountpoints; + RemainAfterExit = true; + }; + }; + + services.borgbackup.jobs = lib.mapAttrs' (mountpoint: attrs: let + fs = builtins.getAttr mountpoint config.fileSystems; + in + assert fs.fsType == "zfs"; { + name = lib.strings.sanitizeDerivationName mountpoint; + value = + { + doInit = true; + repo = config.mj.base.zfsborg.repo; + encryption = { + mode = "repokey-blake2"; + passCommand = "cat ${config.mj.base.zfsborg.passwdPath}"; + }; + paths = attrs.paths; + extraArgs = "--remote-path=borg1"; + compression = "auto,lzma"; + startAt = attrs.backup_at; + readWritePaths = let p = mountpoint + "/.snapshot-latest"; in [p]; + preHook = mountLatest mountpoint fs.device; + postHook = umountLatest mountpoint; + prune.keep = { + within = "1d"; + daily = 7; + weekly = 4; + monthly = 3; + }; + } + // lib.optionalAttrs (attrs ? patterns) { + patterns = attrs.patterns; + }; + }) + config.mj.base.zfsborg.mountpoints; + }; +}