diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index bc4d4cca7b5b..74c8c7bbc820 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -166,6 +166,7 @@ ./services/backup/crashplan-small-business.nix ./services/backup/mysql-backup.nix ./services/backup/postgresql-backup.nix + ./services/backup/restic.nix ./services/backup/rsnapshot.nix ./services/backup/tarsnap.nix ./services/backup/znapzend.nix diff --git a/nixos/modules/services/backup/restic.nix b/nixos/modules/services/backup/restic.nix new file mode 100644 index 000000000000..21d82469c605 --- /dev/null +++ b/nixos/modules/services/backup/restic.nix @@ -0,0 +1,150 @@ +{ config, lib, pkgs, ... }: + +with lib; +{ + options.services.restic.backups = mkOption { + description = '' + Periodic backups to create with Restic. + ''; + type = types.attrsOf (types.submodule ({ name, config, ... }: { + options = { + passwordFile = mkOption { + type = types.str; + description = '' + Read the repository password from a file. + ''; + example = "/etc/nixos/restic-password"; + + }; + + repository = mkOption { + type = types.str; + description = '' + repository to backup to. + ''; + example = "sftp:backup@192.168.1.100:/backups/${name}"; + }; + + paths = mkOption { + type = types.listOf types.str; + default = []; + description = '' + Which paths to backup. + ''; + example = [ + "/var/lib/postgresql" + "/home/user/backup" + ]; + }; + + timerConfig = mkOption { + type = types.attrsOf types.str; + default = { + OnCalendar = "daily"; + }; + description = '' + When to run the backup. See man systemd.timer for details. + ''; + example = { + OnCalendar = "00:05"; + RandomizedDelaySec = "5h"; + }; + }; + + user = mkOption { + type = types.str; + default = "root"; + description = '' + As which user the backup should run. + ''; + example = "postgresql"; + }; + + extraBackupArgs = mkOption { + type = types.listOf types.str; + default = []; + description = '' + Extra arguments passed to restic backup. + ''; + example = [ + "--exclude-file=/etc/nixos/restic-ignore" + ]; + }; + + extraOptions = mkOption { + type = types.listOf types.str; + default = []; + description = '' + Extra extended options to be passed to the restic --option flag. + ''; + example = [ + "sftp.command='ssh backup@192.168.1.100 -i /home/user/.ssh/id_rsa -s sftp'" + ]; + }; + + initialize = mkOption { + type = types.bool; + default = false; + description = '' + Create the repository if it doesn't exist. + ''; + }; + }; + })); + default = {}; + example = { + localbackup = { + paths = [ "/home" ]; + repository = "/mnt/backup-hdd"; + passwordFile = "/etc/nixos/secrets/restic-password"; + initialize = true; + }; + remotebackup = { + paths = [ "/home" ]; + repository = "sftp:backup@host:/backups/home"; + passwordFile = "/etc/nixos/secrets/restic-password"; + extraOptions = [ + "sftp.command='ssh backup@host -i /etc/nixos/secrets/backup-private-key -s sftp'" + ]; + timerConfig = { + OnCalendar = "00:05"; + RandomizedDelaySec = "5h"; + }; + }; + }; + }; + + config = { + systemd.services = + mapAttrs' (name: backup: + let + extraOptions = concatMapStrings (arg: " -o ${arg}") backup.extraOptions; + connectTo = elemAt (splitString ":" backup.repository) 1; + resticCmd = "${pkgs.restic}/bin/restic${extraOptions}"; + in nameValuePair "restic-backups-${name}" ({ + environment = { + RESTIC_PASSWORD_FILE = backup.passwordFile; + RESTIC_REPOSITORY = backup.repository; + }; + path = with pkgs; [ + openssh + ]; + restartIfChanged = false; + serviceConfig = { + Type = "oneshot"; + ExecStart = "${resticCmd} backup ${concatStringsSep " " backup.extraBackupArgs} ${concatStringsSep " " backup.paths}"; + User = backup.user; + }; + } // optionalAttrs backup.initialize { + preStart = '' + ${resticCmd} snapshots || ${resticCmd} init + ''; + }) + ) config.services.restic.backups; + systemd.timers = + mapAttrs' (name: backup: nameValuePair "restic-backups-${name}" { + wantedBy = [ "timers.target" ]; + timerConfig = backup.timerConfig; + }) config.services.restic.backups; + }; +}