From 26c08000a024db986d48e4c692a3677e7143dee5 Mon Sep 17 00:00:00 2001 From: jasmine Date: Wed, 8 Oct 2025 15:53:15 +0800 Subject: [PATCH 1/3] refactor(borgbackup): use visible directories with semantic subvolume names Changes staging directories from hidden to visible and aligns backup paths with actual BTRFS subvolume naming conventions for better clarity when browsing archives. --- nixos/fuchsia/services/borgbackup/offsite.nix | 28 +++++++++---------- nixos/fuchsia/services/borgbackup/onsite.nix | 28 +++++++++---------- .../viridian/services/borgbackup/offsite.nix | 28 +++++++++---------- nixos/viridian/services/borgbackup/onsite.nix | 28 +++++++++---------- 4 files changed, 56 insertions(+), 56 deletions(-) diff --git a/nixos/fuchsia/services/borgbackup/offsite.nix b/nixos/fuchsia/services/borgbackup/offsite.nix index 35720cb..bc35f49 100644 --- a/nixos/fuchsia/services/borgbackup/offsite.nix +++ b/nixos/fuchsia/services/borgbackup/offsite.nix @@ -10,35 +10,35 @@ # Create staging directory before borg service starts systemd.tmpfiles.rules = [ - "d /.staging-offsite 0755 root root -" + "d /subvolumes-offsite 0755 root root -" ]; services.borgbackup.jobs."offsite" = { # Allow writing to staging directory - readWritePaths = [ "/.staging-offsite" ]; + readWritePaths = [ "/subvolumes-offsite" ]; # Create staging snapshots before backup (independent from onsite) preHook = '' # Create read-only staging snapshots for home directory ${pkgs.btrfs-progs}/bin/btrfs subvolume snapshot -r \ - "/home/sajenim" "/.staging-offsite/home" + "/home/sajenim" "/subvolumes-offsite/hm-sajenim" ''; # Backup explicit home directories and persistent files paths = [ # Home directories (valuable user data only) - "/.staging-offsite/home/Documents" - "/.staging-offsite/home/Pictures" - "/.staging-offsite/home/Videos" - "/.staging-offsite/home/Music" - "/.staging-offsite/home/Downloads" - "/.staging-offsite/home/Academics" - "/.staging-offsite/home/Notes" - "/.staging-offsite/home/Library" + "/subvolumes-offsite/hm-sajenim/Documents" + "/subvolumes-offsite/hm-sajenim/Pictures" + "/subvolumes-offsite/hm-sajenim/Videos" + "/subvolumes-offsite/hm-sajenim/Music" + "/subvolumes-offsite/hm-sajenim/Downloads" + "/subvolumes-offsite/hm-sajenim/Academics" + "/subvolumes-offsite/hm-sajenim/Notes" + "/subvolumes-offsite/hm-sajenim/Library" # Dotfiles (critical user configuration) - "/.staging-offsite/home/.ssh" - "/.staging-offsite/home/.gnupg" + "/subvolumes-offsite/hm-sajenim/.ssh" + "/subvolumes-offsite/hm-sajenim/.gnupg" # Files from persist.nix (restore to /persist) "/etc/machine-id" @@ -57,7 +57,7 @@ # Remove staging snapshots after backup completes postHook = '' ${pkgs.btrfs-progs}/bin/btrfs subvolume delete \ - "/.staging-offsite/home" + "/subvolumes-offsite/hm-sajenim" ''; # Remote repository configuration diff --git a/nixos/fuchsia/services/borgbackup/onsite.nix b/nixos/fuchsia/services/borgbackup/onsite.nix index 507d17b..0d0820c 100644 --- a/nixos/fuchsia/services/borgbackup/onsite.nix +++ b/nixos/fuchsia/services/borgbackup/onsite.nix @@ -8,35 +8,35 @@ in { # Create staging directory before borg service starts systemd.tmpfiles.rules = [ - "d /.staging-onsite 0755 root root -" + "d /subvolumes-onsite 0755 root root -" ]; services.borgbackup.jobs."onsite" = { # Allow writing to staging directory - readWritePaths = [ "/.staging-onsite" ]; + readWritePaths = [ "/subvolumes-onsite" ]; # Create staging snapshots before backup (independent from offsite) preHook = '' # Create read-only staging snapshots for home directory ${pkgs.btrfs-progs}/bin/btrfs subvolume snapshot -r \ - "/home/sajenim" "/.staging-onsite/home" + "/home/sajenim" "/subvolumes-onsite/hm-sajenim" ''; # Backup explicit home directories and persistent files paths = [ # Home directories (valuable user data only) - "/.staging-onsite/home/Documents" - "/.staging-onsite/home/Pictures" - "/.staging-onsite/home/Videos" - "/.staging-onsite/home/Music" - "/.staging-onsite/home/Downloads" - "/.staging-onsite/home/Academics" - "/.staging-onsite/home/Notes" - "/.staging-onsite/home/Library" + "/subvolumes-onsite/hm-sajenim/Documents" + "/subvolumes-onsite/hm-sajenim/Pictures" + "/subvolumes-onsite/hm-sajenim/Videos" + "/subvolumes-onsite/hm-sajenim/Music" + "/subvolumes-onsite/hm-sajenim/Downloads" + "/subvolumes-onsite/hm-sajenim/Academics" + "/subvolumes-onsite/hm-sajenim/Notes" + "/subvolumes-onsite/hm-sajenim/Library" # Dotfiles (critical user configuration) - "/.staging-onsite/home/.ssh" - "/.staging-onsite/home/.gnupg" + "/subvolumes-onsite/hm-sajenim/.ssh" + "/subvolumes-onsite/hm-sajenim/.gnupg" # Files from persist.nix (restore to /persist) "/etc/machine-id" @@ -55,7 +55,7 @@ in { # Remove staging snapshots after backup completes postHook = '' ${pkgs.btrfs-progs}/bin/btrfs subvolume delete \ - "/.staging-onsite/home" + "/subvolumes-onsite/hm-sajenim" ''; # Onsite repository configuration (backup to viridian over SSH) diff --git a/nixos/viridian/services/borgbackup/offsite.nix b/nixos/viridian/services/borgbackup/offsite.nix index 173bd75..e690ef7 100644 --- a/nixos/viridian/services/borgbackup/offsite.nix +++ b/nixos/viridian/services/borgbackup/offsite.nix @@ -10,35 +10,35 @@ # Create staging directory before borg service starts systemd.tmpfiles.rules = [ - "d /.staging-offsite 0755 root root -" + "d /subvolumes-offsite 0755 root root -" ]; services.borgbackup.jobs."offsite" = { # Allow writing to staging directory - readWritePaths = [ "/.staging-offsite" ]; + readWritePaths = [ "/subvolumes-offsite" ]; # Create staging snapshots before backup (independent from onsite) preHook = '' # Create read-only staging snapshots for each service - for subvol in containers forgejo lighttpd minecraft opengist; do - # Map config names to actual subvolume paths + for subvol in srv-containers srv-forgejo srv-lighttpd srv-minecraft srv-opengist; do + # Map subvolume names to actual paths case "$subvol" in - containers) src="/srv/multimedia/containers" ;; - *) src="/srv/$subvol" ;; + srv-containers) src="/srv/multimedia/containers" ;; + srv-*) src="/srv/''${subvol#srv-}" ;; esac ${pkgs.btrfs-progs}/bin/btrfs subvolume snapshot -r \ - "$src" "/.staging-offsite/$subvol" + "$src" "/subvolumes-offsite/$subvol" done ''; # Backup staging snapshots and explicit persistent files paths = [ - "/.staging-offsite/containers" - "/.staging-offsite/forgejo" - "/.staging-offsite/lighttpd" - "/.staging-offsite/minecraft" - "/.staging-offsite/opengist" + "/subvolumes-offsite/srv-containers" + "/subvolumes-offsite/srv-forgejo" + "/subvolumes-offsite/srv-lighttpd" + "/subvolumes-offsite/srv-minecraft" + "/subvolumes-offsite/srv-opengist" # Files from persist.nix (restore to /persist) "/etc/machine-id" @@ -56,9 +56,9 @@ # Remove staging snapshots after backup completes postHook = '' - for subvol in containers forgejo lighttpd minecraft opengist; do + for subvol in srv-containers srv-forgejo srv-lighttpd srv-minecraft srv-opengist; do ${pkgs.btrfs-progs}/bin/btrfs subvolume delete \ - "/.staging-offsite/$subvol" + "/subvolumes-offsite/$subvol" done ''; diff --git a/nixos/viridian/services/borgbackup/onsite.nix b/nixos/viridian/services/borgbackup/onsite.nix index 7993489..61407e8 100644 --- a/nixos/viridian/services/borgbackup/onsite.nix +++ b/nixos/viridian/services/borgbackup/onsite.nix @@ -17,35 +17,35 @@ in { # Create staging directory before borg service starts systemd.tmpfiles.rules = [ - "d /.staging-onsite 0755 root root -" + "d /subvolumes-onsite 0755 root root -" ]; services.borgbackup.jobs."onsite" = { # Allow writing to staging directory - readWritePaths = [ "/.staging-onsite" ]; + readWritePaths = [ "/subvolumes-onsite" ]; # Create staging snapshots before backup (independent from offsite) preHook = '' # Create read-only staging snapshots for each service - for subvol in containers forgejo lighttpd minecraft opengist; do - # Map config names to actual subvolume paths + for subvol in srv-containers srv-forgejo srv-lighttpd srv-minecraft srv-opengist; do + # Map subvolume names to actual paths case "$subvol" in - containers) src="/srv/multimedia/containers" ;; - *) src="/srv/$subvol" ;; + srv-containers) src="/srv/multimedia/containers" ;; + srv-*) src="/srv/''${subvol#srv-}" ;; esac ${pkgs.btrfs-progs}/bin/btrfs subvolume snapshot -r \ - "$src" "/.staging-onsite/$subvol" + "$src" "/subvolumes-onsite/$subvol" done ''; # Backup staging snapshots and explicit persistent files paths = [ - "/.staging-onsite/containers" - "/.staging-onsite/forgejo" - "/.staging-onsite/lighttpd" - "/.staging-onsite/minecraft" - "/.staging-onsite/opengist" + "/subvolumes-onsite/srv-containers" + "/subvolumes-onsite/srv-forgejo" + "/subvolumes-onsite/srv-lighttpd" + "/subvolumes-onsite/srv-minecraft" + "/subvolumes-onsite/srv-opengist" # Files from persist.nix (restore to /persist) "/etc/machine-id" @@ -63,9 +63,9 @@ in { # Remove staging snapshots after backup completes postHook = '' - for subvol in containers forgejo lighttpd minecraft opengist; do + for subvol in srv-containers srv-forgejo srv-lighttpd srv-minecraft srv-opengist; do ${pkgs.btrfs-progs}/bin/btrfs subvolume delete \ - "/.staging-onsite/$subvol" + "/subvolumes-onsite/$subvol" done ''; From 37924375a20c449f7e6ba1d947e4145f34a8ae60 Mon Sep 17 00:00:00 2001 From: jasmine Date: Wed, 8 Oct 2025 15:58:23 +0800 Subject: [PATCH 2/3] refactor(borgbackup): backup from /persist paths instead of bind mounts Update backup paths to use actual persistent storage locations (/persist/*) rather than bind-mounted paths, making it clear where data truly resides and simplifying restore operations. --- nixos/fuchsia/services/borgbackup/offsite.nix | 22 +++++++++---------- nixos/fuchsia/services/borgbackup/onsite.nix | 22 +++++++++---------- .../viridian/services/borgbackup/offsite.nix | 22 +++++++++---------- nixos/viridian/services/borgbackup/onsite.nix | 22 +++++++++---------- 4 files changed, 44 insertions(+), 44 deletions(-) diff --git a/nixos/fuchsia/services/borgbackup/offsite.nix b/nixos/fuchsia/services/borgbackup/offsite.nix index bc35f49..7c4355f 100644 --- a/nixos/fuchsia/services/borgbackup/offsite.nix +++ b/nixos/fuchsia/services/borgbackup/offsite.nix @@ -40,18 +40,18 @@ "/subvolumes-offsite/hm-sajenim/.ssh" "/subvolumes-offsite/hm-sajenim/.gnupg" - # Files from persist.nix (restore to /persist) - "/etc/machine-id" - "/etc/ssh/ssh_host_rsa_key" - "/etc/ssh/ssh_host_rsa_key.pub" - "/etc/ssh/ssh_host_ed25519_key" - "/etc/ssh/ssh_host_ed25519_key.pub" + # Persistent files (actual storage location) + "/persist/etc/machine-id" + "/persist/etc/ssh/ssh_host_rsa_key" + "/persist/etc/ssh/ssh_host_rsa_key.pub" + "/persist/etc/ssh/ssh_host_ed25519_key" + "/persist/etc/ssh/ssh_host_ed25519_key.pub" - # Directories from persist.nix (restore to /persist) - "/var/lib/bluetooth" - "/var/lib/nixos" - "/var/lib/private" - "/etc/NetworkManager/system-connections" + # Persistent directories (actual storage location) + "/persist/var/lib/bluetooth" + "/persist/var/lib/nixos" + "/persist/var/lib/private" + "/persist/etc/NetworkManager/system-connections" ]; # Remove staging snapshots after backup completes diff --git a/nixos/fuchsia/services/borgbackup/onsite.nix b/nixos/fuchsia/services/borgbackup/onsite.nix index 0d0820c..d4f7afc 100644 --- a/nixos/fuchsia/services/borgbackup/onsite.nix +++ b/nixos/fuchsia/services/borgbackup/onsite.nix @@ -38,18 +38,18 @@ in { "/subvolumes-onsite/hm-sajenim/.ssh" "/subvolumes-onsite/hm-sajenim/.gnupg" - # Files from persist.nix (restore to /persist) - "/etc/machine-id" - "/etc/ssh/ssh_host_rsa_key" - "/etc/ssh/ssh_host_rsa_key.pub" - "/etc/ssh/ssh_host_ed25519_key" - "/etc/ssh/ssh_host_ed25519_key.pub" + # Persistent files (actual storage location) + "/persist/etc/machine-id" + "/persist/etc/ssh/ssh_host_rsa_key" + "/persist/etc/ssh/ssh_host_rsa_key.pub" + "/persist/etc/ssh/ssh_host_ed25519_key" + "/persist/etc/ssh/ssh_host_ed25519_key.pub" - # Directories from persist.nix (restore to /persist) - "/var/lib/bluetooth" - "/var/lib/nixos" - "/var/lib/private" - "/etc/NetworkManager/system-connections" + # Persistent directories (actual storage location) + "/persist/var/lib/bluetooth" + "/persist/var/lib/nixos" + "/persist/var/lib/private" + "/persist/etc/NetworkManager/system-connections" ]; # Remove staging snapshots after backup completes diff --git a/nixos/viridian/services/borgbackup/offsite.nix b/nixos/viridian/services/borgbackup/offsite.nix index e690ef7..9d0db54 100644 --- a/nixos/viridian/services/borgbackup/offsite.nix +++ b/nixos/viridian/services/borgbackup/offsite.nix @@ -40,18 +40,18 @@ "/subvolumes-offsite/srv-minecraft" "/subvolumes-offsite/srv-opengist" - # Files from persist.nix (restore to /persist) - "/etc/machine-id" - "/etc/ssh/ssh_host_rsa_key" - "/etc/ssh/ssh_host_rsa_key.pub" - "/etc/ssh/ssh_host_ed25519_key" - "/etc/ssh/ssh_host_ed25519_key.pub" + # Persistent files (actual storage location) + "/persist/etc/machine-id" + "/persist/etc/ssh/ssh_host_rsa_key" + "/persist/etc/ssh/ssh_host_rsa_key.pub" + "/persist/etc/ssh/ssh_host_ed25519_key" + "/persist/etc/ssh/ssh_host_ed25519_key.pub" - # Directories from persist.nix (restore to /persist) - "/var/lib/bluetooth" - "/var/lib/nixos" - "/var/lib/private" - "/etc/NetworkManager/system-connections" + # Persistent directories (actual storage location) + "/persist/var/lib/bluetooth" + "/persist/var/lib/nixos" + "/persist/var/lib/private" + "/persist/etc/NetworkManager/system-connections" ]; # Remove staging snapshots after backup completes diff --git a/nixos/viridian/services/borgbackup/onsite.nix b/nixos/viridian/services/borgbackup/onsite.nix index 61407e8..7203828 100644 --- a/nixos/viridian/services/borgbackup/onsite.nix +++ b/nixos/viridian/services/borgbackup/onsite.nix @@ -47,18 +47,18 @@ in { "/subvolumes-onsite/srv-minecraft" "/subvolumes-onsite/srv-opengist" - # Files from persist.nix (restore to /persist) - "/etc/machine-id" - "/etc/ssh/ssh_host_rsa_key" - "/etc/ssh/ssh_host_rsa_key.pub" - "/etc/ssh/ssh_host_ed25519_key" - "/etc/ssh/ssh_host_ed25519_key.pub" + # Persistent files (actual storage location) + "/persist/etc/machine-id" + "/persist/etc/ssh/ssh_host_rsa_key" + "/persist/etc/ssh/ssh_host_rsa_key.pub" + "/persist/etc/ssh/ssh_host_ed25519_key" + "/persist/etc/ssh/ssh_host_ed25519_key.pub" - # Directories from persist.nix (restore to /persist) - "/var/lib/bluetooth" - "/var/lib/nixos" - "/var/lib/private" - "/etc/NetworkManager/system-connections" + # Persistent directories (actual storage location) + "/persist/var/lib/bluetooth" + "/persist/var/lib/nixos" + "/persist/var/lib/private" + "/persist/etc/NetworkManager/system-connections" ]; # Remove staging snapshots after backup completes From 15b4851e8e848ef6bcda5f07eda8eaae2c72e532 Mon Sep 17 00:00:00 2001 From: jasmine Date: Wed, 8 Oct 2025 18:46:50 +0800 Subject: [PATCH 3/3] refactor(borgbackup): implement shared staging with defense-in-depth MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Major improvements to borgbackup configuration for better reliability and maintainability: **Shared staging directory:** - Use single /btrfs-subvolumes directory (was /subvolumes-{onsite,offsite}) - Eliminates redundant path suffixes in archive structure - Archive paths now semantic: /btrfs-subvolumes/srv-forgejo clearly indicates BTRFS subvolume content without redundant backup job metadata **Defense-in-depth protection:** - Layer 1: Systemd ordering - offsite waits for onsite completion - Layer 2: Self-healing preHook - auto-cleanup orphaned snapshots from crashes/power loss - Prevents cascading failures from race conditions or abnormal terminations **Code quality improvements:** - Extract subvolume lists to reduce duplication (DRY principle) - Add /* sh */ syntax hints for proper editor highlighting - Silent operation for consistency with existing hooks - Improved readability with clearer comments and formatting - All lines ≤ 100 characters **Timing:** - Offsite: *-*-* 00:15:00 (daily at 12:15 AM, waits for onsite) - Onsite: hourly (unchanged) --- nixos/fuchsia/services/borgbackup/offsite.nix | 49 +++++++++------ nixos/fuchsia/services/borgbackup/onsite.nix | 42 +++++++------ .../viridian/services/borgbackup/offsite.nix | 62 +++++++++++++------ nixos/viridian/services/borgbackup/onsite.nix | 55 +++++++++++----- 4 files changed, 134 insertions(+), 74 deletions(-) diff --git a/nixos/fuchsia/services/borgbackup/offsite.nix b/nixos/fuchsia/services/borgbackup/offsite.nix index 7c4355f..ed0d181 100644 --- a/nixos/fuchsia/services/borgbackup/offsite.nix +++ b/nixos/fuchsia/services/borgbackup/offsite.nix @@ -10,35 +10,44 @@ # Create staging directory before borg service starts systemd.tmpfiles.rules = [ - "d /subvolumes-offsite 0755 root root -" + "d /btrfs-subvolumes 0755 root root -" ]; + # Wait for onsite backup to complete before starting offsite + systemd.services."borgbackup-job-offsite" = { + after = ["borgbackup-job-onsite.service"]; + }; + services.borgbackup.jobs."offsite" = { # Allow writing to staging directory - readWritePaths = [ "/subvolumes-offsite" ]; + readWritePaths = [ "/btrfs-subvolumes" ]; - # Create staging snapshots before backup (independent from onsite) - preHook = '' - # Create read-only staging snapshots for home directory + preHook = /* sh */ '' + # Clean up orphaned snapshots from failed runs (crash/power loss) + [ -d "/btrfs-subvolumes/hm-sajenim" ] && \ + ${pkgs.btrfs-progs}/bin/btrfs subvolume delete \ + "/btrfs-subvolumes/hm-sajenim" 2>/dev/null || true + + # Create read-only BTRFS snapshot for backup ${pkgs.btrfs-progs}/bin/btrfs subvolume snapshot -r \ - "/home/sajenim" "/subvolumes-offsite/hm-sajenim" + "/home/sajenim" "/btrfs-subvolumes/hm-sajenim" ''; # Backup explicit home directories and persistent files paths = [ # Home directories (valuable user data only) - "/subvolumes-offsite/hm-sajenim/Documents" - "/subvolumes-offsite/hm-sajenim/Pictures" - "/subvolumes-offsite/hm-sajenim/Videos" - "/subvolumes-offsite/hm-sajenim/Music" - "/subvolumes-offsite/hm-sajenim/Downloads" - "/subvolumes-offsite/hm-sajenim/Academics" - "/subvolumes-offsite/hm-sajenim/Notes" - "/subvolumes-offsite/hm-sajenim/Library" + "/btrfs-subvolumes/hm-sajenim/Documents" + "/btrfs-subvolumes/hm-sajenim/Pictures" + "/btrfs-subvolumes/hm-sajenim/Videos" + "/btrfs-subvolumes/hm-sajenim/Music" + "/btrfs-subvolumes/hm-sajenim/Downloads" + "/btrfs-subvolumes/hm-sajenim/Academics" + "/btrfs-subvolumes/hm-sajenim/Notes" + "/btrfs-subvolumes/hm-sajenim/Library" # Dotfiles (critical user configuration) - "/subvolumes-offsite/hm-sajenim/.ssh" - "/subvolumes-offsite/hm-sajenim/.gnupg" + "/btrfs-subvolumes/hm-sajenim/.ssh" + "/btrfs-subvolumes/hm-sajenim/.gnupg" # Persistent files (actual storage location) "/persist/etc/machine-id" @@ -54,10 +63,10 @@ "/persist/etc/NetworkManager/system-connections" ]; - # Remove staging snapshots after backup completes - postHook = '' + postHook = /* sh */ '' + # Clean up snapshots after successful backup ${pkgs.btrfs-progs}/bin/btrfs subvolume delete \ - "/subvolumes-offsite/hm-sajenim" + "/btrfs-subvolumes/hm-sajenim" ''; # Remote repository configuration @@ -70,7 +79,7 @@ environment.BORG_RSH = "ssh -i /etc/ssh/ssh_host_ed25519_key"; compression = "zstd,9"; - startAt = "daily"; + startAt = "*-*-* 00:15:00"; # Daily at 12:15 AM # Ensure backup runs on next boot if system was asleep persistentTimer = true; diff --git a/nixos/fuchsia/services/borgbackup/onsite.nix b/nixos/fuchsia/services/borgbackup/onsite.nix index d4f7afc..e8ec62b 100644 --- a/nixos/fuchsia/services/borgbackup/onsite.nix +++ b/nixos/fuchsia/services/borgbackup/onsite.nix @@ -8,35 +8,39 @@ in { # Create staging directory before borg service starts systemd.tmpfiles.rules = [ - "d /subvolumes-onsite 0755 root root -" + "d /btrfs-subvolumes 0755 root root -" ]; services.borgbackup.jobs."onsite" = { # Allow writing to staging directory - readWritePaths = [ "/subvolumes-onsite" ]; + readWritePaths = [ "/btrfs-subvolumes" ]; - # Create staging snapshots before backup (independent from offsite) - preHook = '' - # Create read-only staging snapshots for home directory + preHook = /* sh */ '' + # Clean up orphaned snapshots from failed runs (crash/power loss) + [ -d "/btrfs-subvolumes/hm-sajenim" ] && \ + ${pkgs.btrfs-progs}/bin/btrfs subvolume delete \ + "/btrfs-subvolumes/hm-sajenim" 2>/dev/null || true + + # Create read-only BTRFS snapshot for backup ${pkgs.btrfs-progs}/bin/btrfs subvolume snapshot -r \ - "/home/sajenim" "/subvolumes-onsite/hm-sajenim" + "/home/sajenim" "/btrfs-subvolumes/hm-sajenim" ''; # Backup explicit home directories and persistent files paths = [ # Home directories (valuable user data only) - "/subvolumes-onsite/hm-sajenim/Documents" - "/subvolumes-onsite/hm-sajenim/Pictures" - "/subvolumes-onsite/hm-sajenim/Videos" - "/subvolumes-onsite/hm-sajenim/Music" - "/subvolumes-onsite/hm-sajenim/Downloads" - "/subvolumes-onsite/hm-sajenim/Academics" - "/subvolumes-onsite/hm-sajenim/Notes" - "/subvolumes-onsite/hm-sajenim/Library" + "/btrfs-subvolumes/hm-sajenim/Documents" + "/btrfs-subvolumes/hm-sajenim/Pictures" + "/btrfs-subvolumes/hm-sajenim/Videos" + "/btrfs-subvolumes/hm-sajenim/Music" + "/btrfs-subvolumes/hm-sajenim/Downloads" + "/btrfs-subvolumes/hm-sajenim/Academics" + "/btrfs-subvolumes/hm-sajenim/Notes" + "/btrfs-subvolumes/hm-sajenim/Library" # Dotfiles (critical user configuration) - "/subvolumes-onsite/hm-sajenim/.ssh" - "/subvolumes-onsite/hm-sajenim/.gnupg" + "/btrfs-subvolumes/hm-sajenim/.ssh" + "/btrfs-subvolumes/hm-sajenim/.gnupg" # Persistent files (actual storage location) "/persist/etc/machine-id" @@ -52,10 +56,10 @@ in { "/persist/etc/NetworkManager/system-connections" ]; - # Remove staging snapshots after backup completes - postHook = '' + postHook = /* sh */ '' + # Clean up snapshots after successful backup ${pkgs.btrfs-progs}/bin/btrfs subvolume delete \ - "/subvolumes-onsite/hm-sajenim" + "/btrfs-subvolumes/hm-sajenim" ''; # Onsite repository configuration (backup to viridian over SSH) diff --git a/nixos/viridian/services/borgbackup/offsite.nix b/nixos/viridian/services/borgbackup/offsite.nix index 9d0db54..f36f5a1 100644 --- a/nixos/viridian/services/borgbackup/offsite.nix +++ b/nixos/viridian/services/borgbackup/offsite.nix @@ -10,35 +10,53 @@ # Create staging directory before borg service starts systemd.tmpfiles.rules = [ - "d /subvolumes-offsite 0755 root root -" + "d /btrfs-subvolumes 0755 root root -" ]; + # Wait for onsite backup to complete before starting offsite + systemd.services."borgbackup-job-offsite" = { + after = ["borgbackup-job-onsite.service"]; + }; + services.borgbackup.jobs."offsite" = { # Allow writing to staging directory - readWritePaths = [ "/subvolumes-offsite" ]; + readWritePaths = [ "/btrfs-subvolumes" ]; - # Create staging snapshots before backup (independent from onsite) - preHook = '' - # Create read-only staging snapshots for each service - for subvol in srv-containers srv-forgejo srv-lighttpd srv-minecraft srv-opengist; do - # Map subvolume names to actual paths + preHook = let + subvolumes = [ + "srv-containers" + "srv-forgejo" + "srv-lighttpd" + "srv-minecraft" + "srv-opengist" + ]; + in /* sh */ '' + # Clean up orphaned snapshots from failed runs (crash/power loss) + for subvol in ${toString subvolumes}; do + [ -d "/btrfs-subvolumes/$subvol" ] && \ + ${pkgs.btrfs-progs}/bin/btrfs subvolume delete \ + "/btrfs-subvolumes/$subvol" 2>/dev/null || true + done + + # Create read-only BTRFS snapshots for backup + for subvol in ${toString subvolumes}; do case "$subvol" in srv-containers) src="/srv/multimedia/containers" ;; srv-*) src="/srv/''${subvol#srv-}" ;; esac ${pkgs.btrfs-progs}/bin/btrfs subvolume snapshot -r \ - "$src" "/subvolumes-offsite/$subvol" + "$src" "/btrfs-subvolumes/$subvol" done ''; # Backup staging snapshots and explicit persistent files paths = [ - "/subvolumes-offsite/srv-containers" - "/subvolumes-offsite/srv-forgejo" - "/subvolumes-offsite/srv-lighttpd" - "/subvolumes-offsite/srv-minecraft" - "/subvolumes-offsite/srv-opengist" + "/btrfs-subvolumes/srv-containers" + "/btrfs-subvolumes/srv-forgejo" + "/btrfs-subvolumes/srv-lighttpd" + "/btrfs-subvolumes/srv-minecraft" + "/btrfs-subvolumes/srv-opengist" # Persistent files (actual storage location) "/persist/etc/machine-id" @@ -54,11 +72,19 @@ "/persist/etc/NetworkManager/system-connections" ]; - # Remove staging snapshots after backup completes - postHook = '' - for subvol in srv-containers srv-forgejo srv-lighttpd srv-minecraft srv-opengist; do + postHook = let + subvolumes = [ + "srv-containers" + "srv-forgejo" + "srv-lighttpd" + "srv-minecraft" + "srv-opengist" + ]; + in /* sh */ '' + # Clean up snapshots after successful backup + for subvol in ${toString subvolumes}; do ${pkgs.btrfs-progs}/bin/btrfs subvolume delete \ - "/subvolumes-offsite/$subvol" + "/btrfs-subvolumes/$subvol" done ''; @@ -72,7 +98,7 @@ environment.BORG_RSH = "ssh -i /etc/ssh/ssh_host_ed25519_key"; compression = "zstd,9"; - startAt = "daily"; + startAt = "*-*-* 00:15:00"; # Daily at 12:15 AM # Ensure backup runs on next boot if system was asleep persistentTimer = true; diff --git a/nixos/viridian/services/borgbackup/onsite.nix b/nixos/viridian/services/borgbackup/onsite.nix index 7203828..fd7d09c 100644 --- a/nixos/viridian/services/borgbackup/onsite.nix +++ b/nixos/viridian/services/borgbackup/onsite.nix @@ -17,35 +17,48 @@ in { # Create staging directory before borg service starts systemd.tmpfiles.rules = [ - "d /subvolumes-onsite 0755 root root -" + "d /btrfs-subvolumes 0755 root root -" ]; services.borgbackup.jobs."onsite" = { # Allow writing to staging directory - readWritePaths = [ "/subvolumes-onsite" ]; + readWritePaths = [ "/btrfs-subvolumes" ]; - # Create staging snapshots before backup (independent from offsite) - preHook = '' - # Create read-only staging snapshots for each service - for subvol in srv-containers srv-forgejo srv-lighttpd srv-minecraft srv-opengist; do - # Map subvolume names to actual paths + preHook = let + subvolumes = [ + "srv-containers" + "srv-forgejo" + "srv-lighttpd" + "srv-minecraft" + "srv-opengist" + ]; + in /* sh */ '' + # Clean up orphaned snapshots from failed runs (crash/power loss) + for subvol in ${toString subvolumes}; do + [ -d "/btrfs-subvolumes/$subvol" ] && \ + ${pkgs.btrfs-progs}/bin/btrfs subvolume delete \ + "/btrfs-subvolumes/$subvol" 2>/dev/null || true + done + + # Create read-only BTRFS snapshots for backup + for subvol in ${toString subvolumes}; do case "$subvol" in srv-containers) src="/srv/multimedia/containers" ;; srv-*) src="/srv/''${subvol#srv-}" ;; esac ${pkgs.btrfs-progs}/bin/btrfs subvolume snapshot -r \ - "$src" "/subvolumes-onsite/$subvol" + "$src" "/btrfs-subvolumes/$subvol" done ''; # Backup staging snapshots and explicit persistent files paths = [ - "/subvolumes-onsite/srv-containers" - "/subvolumes-onsite/srv-forgejo" - "/subvolumes-onsite/srv-lighttpd" - "/subvolumes-onsite/srv-minecraft" - "/subvolumes-onsite/srv-opengist" + "/btrfs-subvolumes/srv-containers" + "/btrfs-subvolumes/srv-forgejo" + "/btrfs-subvolumes/srv-lighttpd" + "/btrfs-subvolumes/srv-minecraft" + "/btrfs-subvolumes/srv-opengist" # Persistent files (actual storage location) "/persist/etc/machine-id" @@ -61,11 +74,19 @@ in { "/persist/etc/NetworkManager/system-connections" ]; - # Remove staging snapshots after backup completes - postHook = '' - for subvol in srv-containers srv-forgejo srv-lighttpd srv-minecraft srv-opengist; do + postHook = let + subvolumes = [ + "srv-containers" + "srv-forgejo" + "srv-lighttpd" + "srv-minecraft" + "srv-opengist" + ]; + in /* sh */ '' + # Clean up snapshots after successful backup + for subvol in ${toString subvolumes}; do ${pkgs.btrfs-progs}/bin/btrfs subvolume delete \ - "/subvolumes-onsite/$subvol" + "/btrfs-subvolumes/$subvol" done '';