nixos-config/config/services/backup.nix

139 lines
4.2 KiB
Nix
Raw Normal View History

2022-06-12 15:39:15 +00:00
{
config,
pkgs,
...
}: let
2022-05-06 09:54:54 +00:00
resticPrunePre = pkgs.writeScript "resticPrunePre" ''
2022-08-26 18:27:47 +00:00
#!/bin/sh
2022-05-06 09:54:54 +00:00
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
# remove old backups
${pkgs.restic}/bin/restic forget --keep-daily 14 --keep-weekly 8 --keep-monthly 24 --keep-yearly 10
2022-05-06 09:54:54 +00:00
# Wait for the restic repository to be unlocked
2022-08-26 18:27:47 +00:00
while [ -n "$(${pkgs.restic}/bin/restic list locks)" ]; do
2022-06-09 11:44:19 +00:00
sleep 10
2022-08-26 18:27:47 +00:00
done
2022-05-06 09:54:54 +00:00
# Clone the Dataset
${pkgs.zfs}/bin/zfs snapshot tank/backup@prune
2022-06-09 11:44:19 +00:00
${pkgs.zfs}/bin/zfs clone -o mountpoint=/backup-prune tank/backup@prune tank/backup-prune
2022-05-06 09:54:54 +00:00
chown backup:backup /backup-prune
'';
resticPrune = pkgs.writeScript "resticPrune" ''
2022-08-26 18:27:47 +00:00
#!/bin/sh
2022-05-06 09:54:54 +00:00
export RESTIC_REPOSITORY="$RESTIC_REPOSITORY-prune"
2022-06-09 11:44:19 +00:00
${pkgs.restic}/bin/restic prune --no-cache --max-unused 0
${pkgs.restic}/bin/restic check --read-data-subset 10%
2022-05-06 09:54:54 +00:00
'';
resticPrunePost = pkgs.writeScript "resticPrunePost" ''
2022-08-26 18:27:47 +00:00
#!/bin/sh
2022-05-06 09:54:54 +00:00
set -ex
2022-06-09 11:44:19 +00:00
# Wait for the restic repository to be unlocked
2022-09-12 16:59:47 +00:00
while [ -n "$(${pkgs.restic}/bin/restic list locks)" ]; do
2022-06-09 11:44:19 +00:00
sleep 10
2022-09-12 16:59:47 +00:00
done
2022-06-09 11:44:19 +00:00
2022-05-06 09:54:54 +00:00
# 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
2022-06-09 11:44:19 +00:00
# Change the mount point
${pkgs.zfs}/bin/zfs set mountpoint=/backup tank/backup
2022-05-06 09:54:54 +00:00
# Destroy the old dataset
2022-06-09 11:44:19 +00:00
${pkgs.zfs}/bin/zfs destroy -rf tank/backup-old
${pkgs.zfs}/bin/zfs destroy tank/backup@prune
2022-09-12 16:59:47 +00:00
sleep 15
2022-06-09 11:44:19 +00:00
${pkgs.zfs}/bin/zfs mount tank/backup
2022-05-06 09:54:54 +00:00
'';
2022-06-12 15:39:15 +00:00
in {
2022-04-24 12:11:41 +00:00
users.users.backup = {
description = "Backup user";
home = "/backup";
isSystemUser = true;
openssh.authorizedKeys.keys = [
2022-05-06 15:04:02 +00:00
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAN/rVZJuwiO44LwOqimpH4zyGehYUMF2ZhYFXUCkupP hydra-queue-runner@nas"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFuWXwZAQYnC2oso7In6BNNM3H+Ek7s6ygIuEvqE3YUf root@nutty-noon"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDpO0Lh7eOE/EBttb/XWZ6ISiJ0RkmBYfruq3U6linEz root@nixos-8gb-fsn1-1"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKB8oH1XbuGrKn/SeguXz96sw4AjJQQvZyAdpptotzOr root@thinkrac"
2022-04-24 12:11:41 +00:00
];
2022-04-24 12:14:47 +00:00
group = "backup";
2022-05-07 09:12:32 +00:00
useDefaultShell = true;
2022-04-24 12:11:41 +00:00
};
2022-06-12 15:39:15 +00:00
users.groups.backup = {};
2022-05-06 09:54:54 +00:00
systemd.services.restic-prune = {
enable = true;
description = "Cleaning up restic backups";
serviceConfig = {
ExecStartPre = "!${resticPrunePre}";
ExecStart = "${resticPrune}";
ExecStartPost = "!${resticPrunePost}";
User = "backup";
Group = "backup";
Type = "oneshot";
2022-08-26 19:37:20 +00:00
EnvironmentFile = config.sops.secrets."services/restic/env".path;
2022-05-06 09:54:54 +00:00
};
};
2022-09-12 10:38:55 +00:00
systemd.timers.restic-prune = {
enable = true;
description = "Prune restic backups";
requires = ["restic-prune.service"];
wantedBy = ["multi-user.target"];
timerConfig = {
OnCalendar = "weekly";
RandomizedDelaySec = 604800;
};
};
2022-05-06 09:54:54 +00:00
sops.secrets."services/restic/env".owner = "backup";
2022-05-06 13:53:22 +00:00
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";
2022-06-12 15:39:15 +00:00
requires = ["backup-rclone.service"];
wantedBy = ["multi-user.target"];
2022-05-06 13:53:22 +00:00
timerConfig = {
2022-09-12 10:38:55 +00:00
OnCalendar = "weekly";
RandomizedDelaySec = 604800;
2022-05-06 13:53:22 +00:00
};
};
2022-04-24 12:11:41 +00:00
}