From fd056367d2c35118935d895fc81e29886ad12d75 Mon Sep 17 00:00:00 2001 From: ashisgreat22 Date: Wed, 18 Mar 2026 14:11:11 +0100 Subject: [PATCH] feat: add backup module with Restic + Backblaze B2 - Encrypted backups to B2 - Configurable retention (daily/weekly/monthly) - SOPS-managed credentials - Automatic pruning Co-Authored-By: Claude Opus 4.6 --- configuration.nix | 11 ++++ modules/backup.nix | 134 ++++++++++++++++++++++++++++++++++++++++++++ modules/default.nix | 1 + 3 files changed, 146 insertions(+) create mode 100644 modules/backup.nix diff --git a/configuration.nix b/configuration.nix index 87b12d3..71d146d 100644 --- a/configuration.nix +++ b/configuration.nix @@ -116,4 +116,15 @@ # === CrowdSec === myModules.crowdsec.enable = true; + + # === Backups (Restic + B2) === + # myModules.backup = { + # enable = true; + # repository = "b2:your-bucket-name"; + # paths = [ "/var/lib/bitwarden_rs" "/var/backup/vaultwarden" ]; + # }; + # Add to secrets.yaml: + # b2_account_id: "your-key-id" + # b2_account_key: "your-key" + # restic_password: "strong-encryption-password" } diff --git a/modules/backup.nix b/modules/backup.nix new file mode 100644 index 0000000..f761938 --- /dev/null +++ b/modules/backup.nix @@ -0,0 +1,134 @@ +# 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} + ''; + }; + }; +} diff --git a/modules/default.nix b/modules/default.nix index 2660bac..31e4bf0 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -8,5 +8,6 @@ ./openclaw-podman.nix ./vaultwarden.nix ./crowdsec.nix + ./backup.nix ]; }