# Backup Module (Restic + Backblaze B2) # Provides: Automated encrypted backups to B2 # # Usage: # myModules.backup = { # enable = true; # repository = "b2:your-bucket-name"; # paths = [ "/var/lib/vaultwarden" "/var/backup/vaultwarden" ]; # }; # # Secrets needed in secrets.yaml: # b2_account_id: "your-b2-key-id" # b2_account_key: "your-b2-key" # restic_password: "your-encryption-password" { config, lib, ... }: let cfg = config.myModules.backup; in { options.myModules.backup = { enable = lib.mkEnableOption "Automated backups with restic to Backblaze B2"; repository = lib.mkOption { type = lib.types.str; example = "b2:my-backup-bucket"; description = "B2 bucket name (format: b2:bucket-name)"; }; paths = lib.mkOption { type = lib.types.listOf lib.types.str; default = [ ]; example = [ "/var/lib/vaultwarden" "/home" ]; description = "Paths to backup"; }; exclude = lib.mkOption { type = lib.types.listOf lib.types.str; default = [ ]; example = [ "*.tmp" "*/cache/*" ]; description = "Patterns to exclude from backup"; }; schedule = lib.mkOption { type = lib.types.str; default = "daily"; example = "*-*-* 02:00:00"; description = "Systemd timer schedule for backups"; }; pruneSchedule = lib.mkOption { type = lib.types.str; default = "weekly"; description = "Schedule for pruning old backups"; }; retainDays = lib.mkOption { type = lib.types.int; default = 30; description = "Keep daily backups for this many days"; }; retainWeeks = lib.mkOption { type = lib.types.int; default = 12; description = "Keep weekly backups for this many weeks"; }; retainMonths = lib.mkOption { type = lib.types.int; default = 12; description = "Keep monthly backups for this many months"; }; }; config = lib.mkIf cfg.enable { sops.secrets.b2_account_id = { }; sops.secrets.b2_account_key = { }; sops.secrets.restic_password = { }; services.restic.backups.b2 = { inherit (cfg) paths; repository = cfg.repository; # B2 credentials from SOPS environmentFile = config.sops.templates."backup.env".path; # Encryption password passwordFile = config.sops.secrets.restic_password.path; # Exclude patterns exclude = cfg.exclude; # Backup schedule timerConfig = { OnCalendar = cfg.schedule; RandomizedDelaySec = "1h"; Persistent = true; }; # Pruning pruneOpts = [ "--keep-daily ${toString cfg.retainDays}" "--keep-weekly ${toString cfg.retainWeeks}" "--keep-monthly ${toString cfg.retainMonths}" ]; }; # Prune schedule systemd.timers.restic-backups-b2-prune = { description = "Prune old B2 backups"; wantedBy = [ "timers.target" ]; timerConfig = { OnCalendar = cfg.pruneSchedule; RandomizedDelaySec = "1h"; Persistent = true; Unit = "restic-backups-b2.service"; }; }; # SOPS template for B2 credentials sops.templates."backup.env" = { content = '' B2_ACCOUNT_ID=${config.sops.placeholder.b2_account_id} B2_ACCOUNT_KEY=${config.sops.placeholder.b2_account_key} ''; }; }; }