nixos-config/config/services/backup.nix

103 lines
2.9 KiB
Nix

{ config, pkgs, ... }:
let
resticPrunePre = pkgs.writeScript "resticPrunePre" ''
set -ex
# Recover from an unclean shutdown
if ${pkgs.zfs}/bin/zfs list tank/backup-old; then
${pkgs.zfs}/bin/zfs list tank/backup || ${pkgs.zfs}/bin/zfs rename tank/backup-old tank/backup
fi
# Undo a prune that has been aborted
${pkgs.zfs}/bin/zfs destroy tank/backup-prune || true
${pkgs.zfs}/bin/zfs destroy tank/backup@prune || true
${pkgs.zfs}/bin/zfs destroy tank/backup-old || true
# Wait for the restic repository to be unlocked
while [ -n "$(${pkgs.restic}/bin/restic list locks)" ]; then
sleep
fi
# Clone the Dataset
${pkgs.zfs}/bin/zfs snapshot tank/backup@prune
${pkgs.zfs}/bin/zfs clone tank/backup@prune tank/backup-prune
chown backup:backup /backup-prune
'';
resticPrune = pkgs.writeScript "resticPrune" ''
export RESTIC_REPOSITORY="$RESTIC_REPOSITORY-prune"
${pkgs.restic} prune --no-cache --max-unused 0
'';
resticPrunePost = pkgs.writeScript "resticPrunePost" ''
set -ex
# make the original read-only
${pkgs.zfs}/bin/zfs set readonly=on tank/backup
# Copy new data over
${pkgs.restic}/bin/restic copy --no-cache --no-lock
# Promote the pruned dataset
${pkgs.zfs}/bin/zfs promote tank/backup-prune
# Change the dataset names
${pkgs.zfs}/bin/zfs rename tank/backup tank/backup-old
${pkgs.zfs}/bin/zfs rename tank/backup-prune tank/backup
# Destroy the old dataset
${pkgs.zfs}/bin/zfs destroy -r tank/backup-old
'';
in
{
users.users.backup = {
description = "Backup user";
home = "/backup";
isSystemUser = true;
openssh.authorizedKeys.keys = [
];
group = "backup";
};
users.groups.backup = { };
systemd.services.restic-prune = {
enable = true;
description = "Cleaning up restic backups";
serviceConfig = {
ExecStartPre = "!${resticPrunePre}";
ExecStart = "${resticPrune}";
ExecStartPost = "!${resticPrunePost}";
User = "backup";
Group = "backup";
Type = "oneshot";
EnvironmentFile = config.sops.secrets."services/restic/env".owner;
};
};
sops.secrets."services/restic/env".owner = "backup";
sops.secrets."services/restic/rclone.conf" = {
owner = "backup";
path = "/backup/.config/rclone/rclone.conf";
};
systemd.services.backup-rclone = {
enable = true;
description = "Upload backup to remote";
script = ''
${pkgs.rclone}/bin/rclone sync /backup backup:backup-darkkirb-de/backup
'';
serviceConfig = {
User = "backup";
Group = "backup";
Type = "oneshot";
};
};
systemd.timers.backup-rclone = {
enable = true;
description = "Upload backup to remote";
requires = [ "backup-rclone.service" ];
wantedBy = [ "multi-user.target" ];
timerConfig = {
onBootSec = 300;
onUnitActiveSec = 86400;
};
};
}