# Legacy storage configuration for defiant # This file manually defines ZFS datasets matching the existing on-disk layout # to allow incremental migration to the new storage module (generateBase = true). # # ============================================================================ # INCREMENTAL MIGRATION PLAN # ============================================================================ # # Current disk usage (for reference): # rpool/local/system/nix ~26G (renamed in place, no copy) # rpool/local/system/sops ~328K (renamed in place, no copy) # rpool/persist/system/jellyfin ~32T (renamed in place, no copy) # rpool/persist/system/qbittorrent ~6.5T (copied into media dataset, ~6.5T temp) # rpool free space ~30T # # Phase 1: Migrate base datasets on disk (boot from live USB or rescue) # All operations in this phase are instant renames -- no data is copied. # # Unlock the pool: # zfs load-key -a # # Step 1a: Move nix and sops out of local/ (they go to persist/local/) # The -p flag auto-creates the parent datasets. # # zfs rename -p rpool/local/system/nix rpool/persist/local/nix # zfs rename -p rpool/local/system/sops rpool/persist/local/system/sops # # Step 1b: Rename local/ -> ephemeral/ (takes remaining children with it) # zfs rename rpool/local rpool/ephemeral # # This moves: local/system/root -> ephemeral/system/root # # local/home/leyla -> ephemeral/home/leyla # # Step 1c: Recreate blank snapshots on ephemeral datasets # zfs destroy rpool/ephemeral/system/root@blank # zfs snapshot rpool/ephemeral/system/root@blank # zfs destroy rpool/ephemeral/home/leyla@blank # zfs snapshot rpool/ephemeral/home/leyla@blank # # Step 1d: Move persist/ children under persist/replicate/ # zfs create -o canmount=off rpool/persist/replicate # zfs create -o canmount=off rpool/persist/replicate/system # zfs rename rpool/persist/system/root rpool/persist/replicate/system/root # zfs rename rpool/persist/system/var rpool/persist/replicate/system/var # zfs rename rpool/persist/home/leyla rpool/persist/replicate/home # # Clean up the now-empty home parent # zfs destroy rpool/persist/home # # NOTE: Do NOT destroy rpool/persist/system -- it still contains # # persist/system/jellyfin and persist/system/qbittorrent which are # # migrated in Phase 2. # # Verify the new layout: # zfs list -r rpool -o name,used,mountpoint # # Phase 2: Merge media into a single dataset (do this last) # Strategy: Rename the jellyfin dataset to become the shared media dataset # (zero copy, instant), then copy qbittorrent data into it (~6.5T copy). # This avoids duplicating the 32T jellyfin dataset. # # Step 2a: Rename jellyfin dataset to the shared media name # zfs rename rpool/persist/system/jellyfin rpool/persist/replicate/system/media # # Step 2b: Copy qbittorrent data into the media dataset # This copies ~6.5T and may take several hours/days depending on disk speed. # The qbittorrent data is not critical to back up so no snapshot needed. # # systemctl stop qbittorrent # rsync -avPHAX /persist/system/qbittorrent/ /persist/replicate/system/media/ # # Step 2c: Verify the data and clean up # ls -la /persist/replicate/system/media/ # zfs destroy rpool/persist/system/qbittorrent # # persist/system should now be empty, clean it up: # zfs destroy rpool/persist/system # # Phase 3: Enable generateBase # In the nix config: # - Delete this file (legacy-storage.nix) and remove its import from default.nix # - Remove [PHASE 3] entries from legacy-impermanence.nix: # - var-lib-private-permissions activation script # - /etc/machine-id, SSH host keys (files block) # - /var/lib/nixos, /var/lib/systemd/coredump (directories) # - /persist/system/var/log persistence block # These are now handled automatically by storage.nix and ssh.nix. # Rebuild and verify: # sudo nixos-rebuild switch --flake .#defiant # # Verify mounts: findmnt -t fuse.bindfs,fuse # # Verify persist: ls /persist/replicate/system/root/var/lib/nixos # # Verify boot: reboot and confirm system comes up cleanly # # Phase 4: Migrate services (one at a time, any order) # For each service (except jellyfin/qbittorrent): # 1. Remove the service's [PHASE 4] section from legacy-impermanence.nix # 2. Remove `impermanence.enable = false` for that service in configuration.nix # 3. Rebuild: sudo nixos-rebuild switch --flake .#defiant # 4. Verify: systemctl status , check the service's data is intact # No data migration is needed -- the data already lives on the renamed # dataset at the new path. # # Migrate jellyfin and qbittorrent LAST (after Phase 2 media merge): # 1. Remove [PHASE 4 - LAST] jellyfin entries from legacy-impermanence.nix # 2. Remove [PHASE 4 - LAST] qbittorrent entries from legacy-impermanence.nix # 3. Remove `impermanence.enable = false` for both in configuration.nix # 4. Rebuild: sudo nixos-rebuild switch --flake .#defiant # 5. Verify: systemctl status jellyfin qbittorrent # # Phase 5: Cleanup # Once all services are migrated and legacy-impermanence.nix is empty: # - Delete legacy-impermanence.nix and remove its import from default.nix # - Rebuild: sudo nixos-rebuild switch --flake .#defiant # # ============================================================================ # # Current on-disk dataset layout: # rpool/local/ - ephemeral parent # rpool/local/home/leyla - ephemeral user home (rolled back on boot) # rpool/local/system/nix - nix store # rpool/local/system/root - root filesystem (rolled back on boot) # rpool/local/system/sops - sops age key # rpool/persist/ - persistent parent # rpool/persist/home/leyla - persistent user home # rpool/persist/system/jellyfin - jellyfin media # rpool/persist/system/qbittorrent - qbittorrent media # rpool/persist/system/root - persistent root data # rpool/persist/system/var/log - log persistence {lib, ...}: { # Disable automatic base dataset generation so we can define them manually storage.generateBase = false; # Manually define ZFS datasets matching main's structure storage.zfs.datasets = { # Ephemeral datasets (local/) "local" = { type = "zfs_fs"; mount = null; }; "local/home/leyla" = { type = "zfs_fs"; mount = "/home/leyla"; snapshot = { blankSnapshot = true; }; }; "local/system/nix" = { type = "zfs_fs"; mount = "/nix"; atime = "off"; relatime = "off"; snapshot = { autoSnapshot = false; }; }; "local/system/root" = { type = "zfs_fs"; mount = "/"; snapshot = { blankSnapshot = true; }; }; "local/system/sops" = { type = "zfs_fs"; mount = "/var/lib/sops-nix"; }; # Persistent datasets (persist/) "persist" = { type = "zfs_fs"; mount = null; }; "persist/home/leyla" = { type = "zfs_fs"; mount = "/persist/home/leyla"; snapshot = { autoSnapshot = true; }; }; "persist/system/jellyfin" = { type = "zfs_fs"; mount = "/persist/system/jellyfin"; atime = "off"; relatime = "off"; }; "persist/system/qbittorrent" = { type = "zfs_fs"; mount = "/persist/system/qbittorrent"; atime = "off"; relatime = "off"; }; "persist/system/root" = { type = "zfs_fs"; mount = "/persist/system/root"; snapshot = { autoSnapshot = true; }; }; "persist/system/var/log" = { type = "zfs_fs"; mount = "/persist/system/var/log"; }; }; # Boot commands to rollback ephemeral root and user homes on boot boot.initrd.postResumeCommands = lib.mkAfter '' zfs rollback -r rpool/local/system/root@blank zfs rollback -r rpool/local/home/leyla@blank ''; # FileSystems needed for boot fileSystems = { "/".neededForBoot = true; "/persist/system/root".neededForBoot = true; "/persist/system/var/log".neededForBoot = true; "/persist/system/jellyfin".neededForBoot = true; "/persist/system/qbittorrent".neededForBoot = true; "/var/lib/sops-nix".neededForBoot = true; "/persist/home/leyla".neededForBoot = true; "/home/leyla".neededForBoot = true; }; }