nixos/modules/services/backup/default.nix

197 lines
5.6 KiB
Nix
Raw Normal View History

2024-07-28 21:08:02 +02:00
{
config,
lib,
pkgs,
...
}:
2022-12-04 18:06:51 +01:00
let
cfg = config.my.services.backup;
in
{
options.my.services.backup = with lib; {
2024-12-30 12:01:57 +01:00
enable = mkEnableOption "Borgbackup Service";
2022-12-04 18:06:51 +01:00
passwordFile = mkOption {
type = types.path;
2024-12-30 12:01:57 +01:00
description = "Password for the backup";
2022-12-04 18:06:51 +01:00
example = "/run/secrets/password";
};
sshHost = mkOption {
type = types.str;
2024-12-30 12:01:57 +01:00
description = "ssh-hostname for remote access";
default = "u181505-sub1.your-storagebox.de";
example = "test.domain.com";
};
sshUser = mkOption {
type = types.str;
2024-12-30 12:01:57 +01:00
description = "ssh-user for remote access";
default = "u181505-sub1";
example = "max";
};
sshPort = mkOption {
type = types.port;
2024-12-30 12:01:57 +01:00
description = "ssh-port for remote access";
default = 23;
example = 22;
};
2022-12-04 18:06:51 +01:00
sshKeyFile = mkOption {
type = types.path;
2024-12-30 12:01:57 +01:00
description = "ssh-key for remote access";
2022-12-04 18:06:51 +01:00
example = "/run/secrets/ssh_key";
};
OnFailureNotification = mkOption {
type = types.bool;
2024-12-30 12:01:57 +01:00
description = "whether to show a warning to all users or not";
2022-12-04 18:06:51 +01:00
default = false;
};
OnFailureMail = mkOption {
2023-11-07 23:13:51 +01:00
type = types.nullOr types.str;
2024-12-30 12:01:57 +01:00
description = "Mail address where to send the error report";
2022-12-04 18:06:51 +01:00
default = null;
example = "alarm@mail.com";
};
paths = mkOption {
type = with types; listOf str;
2024-12-30 12:01:57 +01:00
description = "additional path(s) to back up";
2022-12-04 18:06:51 +01:00
default = [ "/" ];
2024-07-28 21:08:02 +02:00
example = [ "/home/user" ];
2022-12-04 18:06:51 +01:00
};
exclude = mkOption {
type = with types; listOf str;
2024-12-30 12:01:57 +01:00
description = "Exclude paths matching any of the given patterns. See `borg help patterns`";
2022-12-04 18:06:51 +01:00
default = [ ];
example = [
"/home/*/.cache"
"/tmp"
];
};
2023-02-11 21:44:10 +01:00
doInit = mkOption {
type = types.bool;
2024-12-30 12:01:57 +01:00
description = ''
2023-02-11 21:44:10 +01:00
Run {command}`borg init` if the
specified {option}`repo` does not exist.
You should set this to `false`
if the repository is located on an external drive
that might not always be mounted.
'';
default = false;
};
2022-12-04 18:06:51 +01:00
};
config = lib.mkIf cfg.enable {
# mails can only be delivered if postfix is available
services.postfix.enable = lib.mkIf (cfg.OnFailureMail != null) true;
2022-12-04 18:06:51 +01:00
services.borgbackup.jobs.hetzner = {
# always backup everything and only define excludes
inherit (cfg) paths;
exclude = [
2024-05-05 13:05:35 +02:00
# system
2022-12-04 18:06:51 +01:00
"/nix"
2024-05-05 13:05:35 +02:00
"/mnt"
2022-12-04 18:06:51 +01:00
"/proc"
"/root/.cache/"
2023-01-29 15:22:46 +01:00
"/root/.config/borg/security/"
2024-05-05 13:05:35 +02:00
"/run"
"/sys"
2022-12-04 18:06:51 +01:00
"/tmp"
2024-05-05 13:05:35 +02:00
# other-os
"**/.Trash" # apple
"**/.DS_Store" # apple
2024-07-28 21:08:02 +02:00
"**/$RECYCLE.BIN" # windows
"**/System Volume Information" # windows
2024-05-05 13:05:35 +02:00
# var data
"/var/cache"
2022-12-04 18:06:51 +01:00
"/var/lib/docker/devicemapper"
2024-05-05 13:05:35 +02:00
"/var/lock"
"/var/log"
2022-12-04 18:06:51 +01:00
"/var/run"
"/var/tmp"
2024-05-05 13:05:35 +02:00
# home-directories
2022-12-04 18:06:51 +01:00
"/home/*/.cache"
"/home/*/.gvfs"
"/home/*/.local/share/Trash"
"/home/*/.thumbnails"
2024-05-12 20:01:31 +02:00
"/home/*/.config/Element/Cache"
2024-05-05 13:05:35 +02:00
# self-defined
"/data/tmp"
"/data/todo"
2022-12-04 18:06:51 +01:00
"/home/*/tmp"
"/home/*/todo"
] ++ cfg.exclude;
extraCreateArgs = "--exclude-caches --keep-exclude-tags --stats";
encryption = {
mode = "repokey-blake2";
passCommand = "cat ${cfg.passwordFile}";
};
environment.BORG_RSH = "ssh -o 'StrictHostKeyChecking=no' -i ${cfg.sshKeyFile} -p ${toString cfg.sshPort}";
repo = "${cfg.sshUser}@${cfg.sshHost}:${config.networking.hostName}/";
2022-12-04 18:06:51 +01:00
2023-11-07 23:13:51 +01:00
inherit (cfg) doInit;
2022-12-04 18:06:51 +01:00
compression = "auto,zstd";
2024-07-28 21:08:02 +02:00
postHook =
''
if (( $exitStatus > 1 )); then
''
+ lib.optionalString cfg.OnFailureNotification ''
# iterate over all logged in users
for user in $(users); do
sway_pid=$(${pkgs.procps}/bin/pgrep -x "sway" -u "$user")
if [ -n "$sway_pid" ]; then
# set environment variables
export $(cat /proc/$sway_pid/environ | grep -z '^DBUS_SESSION_BUS_ADDRESS=' | tr -d '\0')
export DISPLAY=:0
# send notification via dbus: https://wiki.archlinux.org/title/Desktop_notifications#Bash
${pkgs.sudo}/bin/sudo --preserve-env=DBUS_SESSION_BUS_ADDRESS,DISPLAY -u $user ${pkgs.libnotify}/bin/notify-send -u critical "BorgBackup Failed!" "Run journalctl -u borgbackup-job* for more details."
echo "sent notification"
fi
done
''
+ lib.optionalString (cfg.OnFailureMail != null) ''
journalctl -u borgbackup-job-hetzner.service | ${pkgs.mailutils}/bin/mail -r "Administrator<root@buehler.rocks>" -s "Backup Error" server@buehler.rocks
echo "sent mail"
''
+ ''
2022-12-04 18:06:51 +01:00
fi
2024-07-28 21:08:02 +02:00
'';
2022-12-04 18:06:51 +01:00
2023-01-29 20:15:49 +01:00
# for mail sending
readWritePaths = lib.optional (cfg.OnFailureMail != null) "/var/lib/postfix/queue/maildrop/";
2022-12-04 18:06:51 +01:00
startAt = "daily";
persistentTimer = true;
prune.keep = {
last = 1;
within = "3d";
daily = 7;
weekly = 4;
monthly = 6;
yearly = 2;
};
};
my.services.prometheus.rules = {
borgbackup_execution_missing = {
condition = ''time() - systemd_timer_last_trigger_seconds{name="borgbackup-job-hetzner.timer"} >= (60 * 60 * (24 + 1))'';
description = "{{$labels.instance}}: last backup was 25 hours ago please check.";
};
borgbackup_last_execution = {
condition = ''systemd_unit_state{state="failed", name="borgbackup-job-hetzner.timer"} >= 1'';
2023-06-22 20:54:16 +02:00
description = "{{$labels.instance}}: last backup was not successful please check.";
};
};
2022-12-04 18:06:51 +01:00
};
}