From 61cd897d1f6f8952c7535b6d807b2c0d1422f100 Mon Sep 17 00:00:00 2001 From: Bruno BELANYI Date: Sun, 7 Feb 2021 12:19:52 +0000 Subject: [PATCH] services: add backup This is using `restic` and Backblaze B2 buckets --- services/backup.nix | 106 +++++++++++++++++++++++++++++++++++++++++++ services/default.nix | 1 + 2 files changed, 107 insertions(+) create mode 100644 services/backup.nix diff --git a/services/backup.nix b/services/backup.nix new file mode 100644 index 0000000..da45b5e --- /dev/null +++ b/services/backup.nix @@ -0,0 +1,106 @@ +# Backups using Backblaze B2 and `restic` +{ config, pkgs, lib, ... }: +let + cfg = config.my.services.backup; + + excludeArg = with builtins; with pkgs; "--exclude-file=" + + (writeText "excludes.txt" (concatStringsSep "\n" cfg.exclude)); +in +{ + options.my.services.backup = with lib; { + enable = mkEnableOption "Enable backups for this host"; + + repository = mkOption { + type = types.str; + example = "/mnt/backup-hdd"; + description = "The repository to back up to"; + }; + + passwordFile = mkOption { + type = types.str; + example = "/var/lib/restic/password.txt"; + description = "Read the repository's password from this path"; + }; + + credentialsFile = mkOption { + type = types.str; + example = "/var/lib/restic/creds.env"; + description = '' + Credential file as an 'EnvironmentFile' (see `systemd.exec(5)`) + ''; + }; + + paths = mkOption { + type = with types; listOf str; + default = [ ]; + example = [ + "/var/lib" + "/home" + ]; + description = "Paths to backup"; + }; + + exclude = mkOption { + type = with types; listOf str; + default = [ ]; + example = [ + # very large paths + "/var/lib/docker" + "/var/lib/systemd" + "/var/lib/libvirt" + + # temporary files created by `cargo` and `go build` + "**/target" + "/home/*/go/bin" + "/home/*/go/pkg" + ]; + description = "Paths to exclude from backup"; + }; + + pruneOpts = mkOption { + type = with types; listOf str; + default = [ + "--keep-last 10" + "--keep-hourly 24" + "--keep-daily 7" + "--keep-weekly 5" + "--keep-monthly 12" + "--keep-yearly 100" + ]; + example = [ "--keep-last 5" "--keep-weekly 2" ]; + description = '' + List of options to give to the `forget` subcommand after a backup. + ''; + }; + + timerConfig = mkOption { + # NOTE: I do not know how to cleanly set the type + default = { + OnCalendar = "daily"; + }; + example = { + OnCalendar = "00:05"; + RandomizedDelaySec = "5h"; + }; + description = '' + When to run the backup. See man systemd.timer for details. + ''; + }; + }; + + config = lib.mkIf cfg.enable { + services.restic.backups.backblaze = { + # Take care of included and excluded files + paths = cfg.paths; + extraOptions = with builtins; with lib;[ + (optionalString ((length cfg.exclude) != 0) excludeArg) + ]; + # Take care of creating the repository if it doesn't exist + initialize = true; + # Hijack S3-related env to give B2 API key + s3CredentialsFile = cfg.credentialsFile; + + inherit (cfg) passwordFile pruneOpts timerConfig repository; + }; + }; +} diff --git a/services/default.nix b/services/default.nix index a6d8a6d..488c4ba 100644 --- a/services/default.nix +++ b/services/default.nix @@ -2,6 +2,7 @@ { imports = [ + ./backup.nix ./gitea.nix ./indexers.nix ./jellyfin.nix