From 3a679356ad773b86f1c2452a770d5ed458eb07ef Mon Sep 17 00:00:00 2001 From: wi11-holdsworth <83637728+wi11-holdsworth@users.noreply.github.com> Date: Wed, 1 Oct 2025 00:18:12 +1000 Subject: [PATCH 1/2] feat: replace borgbackup and bespoke backup function with borgmatic --- hosts/server/configuration.nix | 2 +- modules/nixos/backup.nix | 75 ------------------ modules/nixos/features/borgbackup-srv.nix | 31 -------- modules/nixos/features/borgmatic.nix | 92 +++++++++++++++++++++++ secrets/borgbackup-server-offsite.age | 9 --- secrets/borgbackup-server-onsite.age | 9 --- secrets/borgmatic-pg.age | 9 +++ secrets/borgmatic.age | 9 +++ secrets/secrets.nix | 4 +- 9 files changed, 113 insertions(+), 127 deletions(-) delete mode 100644 modules/nixos/backup.nix delete mode 100644 modules/nixos/features/borgbackup-srv.nix create mode 100644 modules/nixos/features/borgmatic.nix delete mode 100644 secrets/borgbackup-server-offsite.age delete mode 100644 secrets/borgbackup-server-onsite.age create mode 100644 secrets/borgmatic-pg.age create mode 100644 secrets/borgmatic.age diff --git a/hosts/server/configuration.nix b/hosts/server/configuration.nix index 8fd8fb8..98ffeda 100644 --- a/hosts/server/configuration.nix +++ b/hosts/server/configuration.nix @@ -12,7 +12,7 @@ # reusable modules # keep-sorted start - borgbackup-srv.enable = true; + borgmatic.enable = true; intel-gpu.enable = true; server.enable = true; # keep-sorted end diff --git a/modules/nixos/backup.nix b/modules/nixos/backup.nix deleted file mode 100644 index f262da5..0000000 --- a/modules/nixos/backup.nix +++ /dev/null @@ -1,75 +0,0 @@ -service: servicecfg: -{ - # keep-sorted start - pkgs, - config, - lib, -# keep-sorted end -}: -let - notify = - { - tag, - msg, - location, - }: - '' - ${pkgs.curl}/bin/curl \ - -H "X-Tags: ${tag},BorgBackup,Server,${location}" \ - -d "${msg}" \ - ${config.services.ntfy-sh.settings.base-url}/backups - ''; - notifySuccess = - context: - notify { - tag = "tada"; - msg = "Backup succeeded"; - location = "${context}/${service}"; - }; - notifyFailure = - context: - notify { - tag = "rotating_light"; - msg = "Backup failed, check logs"; - location = "${context}/${service}"; - }; - job = - context: contextcfg: - lib.nameValuePair "${context}-${service}" ( - { - compression = "auto,zstd"; - startAt = "*-*-* 04:00:00 Australia/Melbourne"; - prune.keep = { - daily = 7; - weekly = 4; - monthly = 6; - }; - postHook = '' - if [ $exitStatus -eq 0 ]; then - ${notifySuccess context} - else - ${notifyFailure context} - fi - ''; - } - // contextcfg - // servicecfg - ); -in -builtins.listToAttrs [ - (job "onsite" { - repo = "/backup/repo"; - encryption = { - mode = "repokey-blake2"; - passCommand = "cat ${config.age.secrets.borgbackup-server-onsite.path}"; - }; - }) - (job "offsite" { - repo = "vuc5c3xq@vuc5c3xq.repo.borgbase.com:repo"; - encryption = { - mode = "repokey-blake2"; - passCommand = "cat ${config.age.secrets.borgbackup-server-offsite.path}"; - }; - environment.BORG_RSH = "ssh -i /home/srv/.ssh/id_ed25519"; - }) -] diff --git a/modules/nixos/features/borgbackup-srv.nix b/modules/nixos/features/borgbackup-srv.nix deleted file mode 100644 index 89b07f8..0000000 --- a/modules/nixos/features/borgbackup-srv.nix +++ /dev/null @@ -1,31 +0,0 @@ -{ - config, - lib, - ... -}: -let - feature = "borgbackup-srv"; -in -{ - config = lib.mkIf config.${feature}.enable { - # onsite drive - services.udisks2.enable = true; - - fileSystems."/backup" = { - device = "/dev/disk/by-uuid/d3b3d7dc-d634-4327-9ea2-9d8daa4ecf4e"; - fsType = "ext4"; - }; - - # secrets - age.secrets = { - "borgbackup-server-onsite" = { - file = ../../../secrets/borgbackup-server-onsite.age; - }; - "borgbackup-server-offsite" = { - file = ../../../secrets/borgbackup-server-offsite.age; - }; - }; - }; - - options.${feature}.enable = lib.mkEnableOption "enables ${feature}"; -} diff --git a/modules/nixos/features/borgmatic.nix b/modules/nixos/features/borgmatic.nix new file mode 100644 index 0000000..e0bf694 --- /dev/null +++ b/modules/nixos/features/borgmatic.nix @@ -0,0 +1,92 @@ +{ + config, + lib, + ... +}: +let + feature = "borgmatic"; +in +{ + config = lib.mkIf config.${feature}.enable { + # service + services.borgmatic = { + enable = true; + settings = { + # keep-sorted start block=yes + compression = "auto,zlib"; + keep_daily = 7; + keep_weekly = 4; + keep_monthly = 6; + keep_yearly = 1; + repositories = [ + { + path = "/backup/repo"; + label = "onsite"; + # encryption = "repokey-blake2"; + } + { + path = "ssh://vuc5c3xq@vuc5c3xq.repo.borgbase.com/./repo"; + label = "offsite"; + # encryption = "repokey-blake2"; + } + ]; + encryption_passcommand = "cat ${config.age.secrets.borgmatic.path}"; + ssh_command = "ssh -i /home/srv/.ssh/id_ed25519"; + ntfy = { + topic = "backups"; + server = config.services.ntfy-sh.settings.base-url; + finish = { + title = "Ping!"; + message = "Your backups have succeeded :)"; + tags = "tada,BorgBackup,Server"; + }; + fail = { + title = "Ping!"; + message = "Your backups have failed :("; + tags = "rotating_light,BorgBackup,Server"; + }; + states = [ + "finish" + "fail" + ]; + }; + retries = 3; + retry_wait = 10; + # keep-sorted end + }; + }; + + # postgres + services.postgresql.ensureUsers = [ + { + name = "root"; + } + ]; + systemd.services.postgresql.postStart = lib.mkAfter '' + /run/current-system/sw/bin/psql postgres -c "GRANT pg_read_all_data TO root" + ''; + systemd.services.borgmatic.path = [ + config.services.postgresql.package + ]; + + # credentials + systemd.services.borgmatic.serviceConfig.LoadCredential = [ + "borgmatic-pg:${config.age.secrets.borgmatic-pg.path}" + ]; + + # onsite drive + services.udisks2.enable = true; + fileSystems."/backup" = { + device = "/dev/disk/by-uuid/d3b3d7dc-d634-4327-9ea2-9d8daa4ecf4e"; + fsType = "ext4"; + }; + + # secrets + age.secrets = { + "borgmatic".file = ../../../secrets/borgmatic.age; + "borgmatic-pg".file = ../../../secrets/borgmatic-pg.age; + }; + }; + + options.${feature}.enable = lib.mkEnableOption "enables ${feature}"; +} diff --git a/secrets/borgbackup-server-offsite.age b/secrets/borgbackup-server-offsite.age deleted file mode 100644 index 0fa5170..0000000 --- a/secrets/borgbackup-server-offsite.age +++ /dev/null @@ -1,9 +0,0 @@ -age-encryption.org/v1 --> ssh-ed25519 LtK9yQ ffY9sDLotAZPq7WYBhBCo/+CG8hs8oSb+Zc26XQ5Kxs -7JwKBUAUWfuOyfaf/pVcq1zv58OtrPAh9wGqPcEhlt8 --> ssh-ed25519 qLT+DQ ulTuZ469zjWcwcuH54SUDaAsaNcpEqXkO0cdGsv2tEE -jwqDMwd/hyHvT+FQjHj8fziycK9WMGJqM6UZKB1yXrQ --> ssh-ed25519 7+xRyQ ZcybG8n14hpc/B9p1KWDzCi9T2UmVzzsTG32LtKtNFY -81CixZ1eUgAZLS1LDceYeoGbKUPVqqzqjjJ7ACUHCCc ---- 5eJlsZeXReu93xYN6WLtKfFycFyTZyrt0aMYgERe9ME -"4XtQqw(޸3.JI6-),ղq I~b \ No newline at end of file diff --git a/secrets/borgbackup-server-onsite.age b/secrets/borgbackup-server-onsite.age deleted file mode 100644 index baf9047..0000000 --- a/secrets/borgbackup-server-onsite.age +++ /dev/null @@ -1,9 +0,0 @@ -age-encryption.org/v1 --> ssh-ed25519 LtK9yQ klX5fjSXRPWV/ALNcTZ8UIVFEftuS0bMx0oZ0jZDSBQ -swtF1Mvup7JZszfPgXwZ2363Qrt3oUdP1AWfd0Je8h0 --> ssh-ed25519 qLT+DQ IN4GfoKDEtcs/lbobggKfdbFn8EdqpBv7KRJqs0nxg8 -X+hti2ZVCqZPHV54QzwZN1nQTdBbU/ZaF7iz1QspIW4 --> ssh-ed25519 7+xRyQ TFU9KepaxamXUcwNrwDv368JvfmLb0Aq1oeuQoX3A2g -XQZxEmfduYOcDoXZuL9ywH2UdJmFsM6mQDqX5SBkvko ---- ud8jMRGHEN6/q5o0GhZdt+Nh38Bhg6nh/ugTPTJFYtI -uI,mWJzP/.]m㶁kbh+JXZ/qX Qa./9 \ No newline at end of file diff --git a/secrets/borgmatic-pg.age b/secrets/borgmatic-pg.age new file mode 100644 index 0000000..33e1118 --- /dev/null +++ b/secrets/borgmatic-pg.age @@ -0,0 +1,9 @@ +age-encryption.org/v1 +-> ssh-ed25519 qLT+DQ C3A3TKOyIWzbW8JupvhTmLKetnr+0uzkPq985NA0DCs +ahrHVR7WadjOfOXBWOqBAf9L0UdCNeD0Ynk6sKDF7WM +-> ssh-ed25519 7+xRyQ evZ6zSS3olbORnqiCnEAL68D1FNPgg2oBoJSaquLAAA +BYoo9AVOHsRsTbXkRQdS/7WN25vBuJOAb0YfnSY+hGQ +-> ssh-ed25519 LtK9yQ jLIdKPvVhPsRIJevWLmads3P2hM29c0B143OWoINzlY +ziCUQ1TtB6BUgbNZ/zFXoaOtpxyrbKobsTvXo/dSpSA +--- Q6JHS+5vuYLIqyIb6x3qCbIJvsjk2++ovL1zkVGs69o +쇽NM1WByM.-|Gl]8Z,(5豲P!pmpEa;(tq!KU4m \ No newline at end of file diff --git a/secrets/borgmatic.age b/secrets/borgmatic.age new file mode 100644 index 0000000..fca1c53 --- /dev/null +++ b/secrets/borgmatic.age @@ -0,0 +1,9 @@ +age-encryption.org/v1 +-> ssh-ed25519 qLT+DQ zfLZc8A30KjoMrhUSl4OgTp+Yg11fmVjDioxtIYMqDU +URhJwUCElaJcSd+k5wBQAXvdC/68ZcCA5WbHGAJTYfY +-> ssh-ed25519 7+xRyQ mrGrjW0fQIRNMDdw4Hoc9N/xAEm1P0IFukShfeVdKE8 +yLUmj7LBfHQ/i4buBB57ktNUOnHpoC8NYTQUnK5e5y4 +-> ssh-ed25519 LtK9yQ THjOsSIr/DQTulFlwd4r5DYb73VQ0vWgyDHkfJV3NR0 +Dl8FwK1WciiEMs5MdrFcUIOFGmlbZf3APOWzLN6rkOE +--- 3mjYPT9APy0F5NNbbCIQhzZ0XjKBtB9YGGS3t37eoRU +T^vU{>[dhPC6Z|K|~lݝbDt΄]1P$10 A$ \ No newline at end of file diff --git a/secrets/secrets.nix b/secrets/secrets.nix index b4ef8ab..181d565 100644 --- a/secrets/secrets.nix +++ b/secrets/secrets.nix @@ -15,8 +15,8 @@ let in { # keep-sorted start - "borgbackup-server-offsite.age".publicKeys = users; - "borgbackup-server-onsite.age".publicKeys = users; + "borgmatic.age".publicKeys = users; + "borgmatic-pg.age".publicKeys = users; "copyparty-will.age".publicKeys = users; "immich.age".publicKeys = users; "jellyfin.age".publicKeys = users; -- 2.53.0 From 649f6d048b654ff155c0ac06adc95f34007ebd2e Mon Sep 17 00:00:00 2001 From: wi11-holdsworth <83637728+wi11-holdsworth@users.noreply.github.com> Date: Wed, 1 Oct 2025 00:18:48 +1000 Subject: [PATCH 2/2] feat: utilise borgmatic to back up several services /srv folder immich database miniflux database paperless database syncthing database --- modules/nixos/bundles/server.nix | 12 +----------- modules/nixos/features/immich.nix | 12 ++++++++++++ modules/nixos/features/miniflux.nix | 12 ++++++++++++ modules/nixos/features/paperless.nix | 12 ++++++++++++ modules/nixos/features/syncthing.nix | 24 +++++++----------------- 5 files changed, 44 insertions(+), 28 deletions(-) diff --git a/modules/nixos/bundles/server.nix b/modules/nixos/bundles/server.nix index 7e71c78..9c9c846 100644 --- a/modules/nixos/bundles/server.nix +++ b/modules/nixos/bundles/server.nix @@ -1,7 +1,6 @@ { config, lib, - pkgs, ... }: let @@ -32,16 +31,7 @@ in users.groups.media = { }; - services.borgbackup.jobs = - import ../backup.nix "srv" - { - paths = [ "/srv" ]; - } - { - inherit config; - inherit lib; - inherit pkgs; - }; + services.borgmatic.settings.source_directories = [ "/srv" ]; }; imports = [ ]; diff --git a/modules/nixos/features/immich.nix b/modules/nixos/features/immich.nix index 9ab2e83..ab72dee 100644 --- a/modules/nixos/features/immich.nix +++ b/modules/nixos/features/immich.nix @@ -16,6 +16,18 @@ in mediaLocation = "/srv/immich"; }; + # database backup + borgmatic.settings = { + postgresql_databases = [ + { + name = "immich"; + hostname = "localhost"; + username = "root"; + password = "{credential systemd borgmatic-pg}"; + } + ]; + }; + nginx = { clientMaxBodySize = "50000M"; virtualHosts."${feature}.fi33.buzz" = { diff --git a/modules/nixos/features/miniflux.nix b/modules/nixos/features/miniflux.nix index b27615f..59bbcbd 100644 --- a/modules/nixos/features/miniflux.nix +++ b/modules/nixos/features/miniflux.nix @@ -20,6 +20,18 @@ in }; }; + # database backup + borgmatic.settings = { + postgresql_databases = [ + { + name = "miniflux"; + hostname = "localhost"; + username = "root"; + password = "{credential systemd borgmatic-pg}"; + } + ]; + }; + # reverse proxy nginx = { virtualHosts."${feature}.fi33.buzz" = { diff --git a/modules/nixos/features/paperless.nix b/modules/nixos/features/paperless.nix index 0474247..e6ea41d 100644 --- a/modules/nixos/features/paperless.nix +++ b/modules/nixos/features/paperless.nix @@ -22,6 +22,18 @@ in }; }; + # database backup + borgmatic.settings = { + postgresql_databases = [ + { + name = "paperless"; + hostname = "localhost"; + username = "root"; + password = "{credential systemd borgmatic-pg}"; + } + ]; + }; + # reverse proxy nginx = { virtualHosts."${feature}.fi33.buzz" = { diff --git a/modules/nixos/features/syncthing.nix b/modules/nixos/features/syncthing.nix index 4f74eea..cd66ad3 100644 --- a/modules/nixos/features/syncthing.nix +++ b/modules/nixos/features/syncthing.nix @@ -63,24 +63,14 @@ in }; }; - # backup - borgbackup.jobs = - # we only need one syncthing host to be backed up - # choose server because borgbackup is the most fleshed out - # on srv currently + borgmatic.settings = if userName == "srv" then - import ../backup.nix feature - { - paths = [ - "/home/srv/.config/syncthing" - "/home/srv/Sync" - ]; - } - { - inherit config; - inherit lib; - inherit pkgs; - } + { + source_directories = [ + "/home/srv/.config/syncthing" + "/home/srv/Sync" + ]; + } else null; -- 2.53.0