{ preservation, lib, pkgs, myvars, ... }: let inherit (myvars) username; in { imports = [ preservation.nixosModules.default ]; preservation.enable = true; # pverservation required initrd using systemd. boot.initrd.systemd.enable = true; environment.systemPackages = [ # `sudo ncdu -x /` pkgs.ncdu ]; # There are two ways to clear the root filesystem on every boot: ## 1. use tmpfs for / ## 2. (btrfs/zfs only)take a blank snapshot of the root filesystem and revert to it on every boot via: ## boot.initrd.postDeviceCommands = '' ## mkdir -p /run/mymount ## mount -o subvol=/ /dev/disk/by-uuid/UUID /run/mymount ## btrfs subvolume delete /run/mymount ## btrfs subvolume snapshot / /run/mymount ## ''; # # See also https://grahamc.com/blog/erase-your-darlings/ # NOTE: preservation only mounts the directory/file list below to /persistent # If the directory/file already exists in the root filesystem you should # move those files/directories to /persistent first! preservation.preserveAt."/persistent" = { directories = [ "/etc/NetworkManager/system-connections" "/etc/ssh" "/etc/nix/inputs" "/etc/secureboot" # lanzaboote - secure boot # my secrets "/etc/agenix/" "/var/log" # preserve davfs2 driver's cache to avoid large memory usage "/var/cache/davfs2" # system-core "/var/lib/nixos" "/var/lib/systemd" { directory = "/var/lib/private"; mode = "0700"; } # containers # "/var/lib/docker" "/var/lib/cni" "/var/lib/containers" # other data "/var/lib/flatpak" # virtualisation "/var/lib/libvirt" "/var/lib/lxc" "/var/lib/lxd" "/var/lib/qemu" # "/var/lib/waydroid" # network "/var/lib/bluetooth" "/var/lib/NetworkManager" "/var/lib/iwd" "/var/lib/tailscale" "/var/lib/netbird-homelab" # netbird's homelab client "/etc/netbird-homelab" ]; files = [ # auto-generated machine ID { file = "/etc/machine-id"; inInitrd = true; } ]; # the following directories will be passed to /persistent/home/$USER users.${username} = { commonMountOptions = [ "x-gvfs-hide" ]; directories = [ # ====================================== # XDG Directories # ====================================== "Desktop" "Downloads" "Music" "Pictures" "Documents" "Videos" # Keep .cache off tmpfs to avoid high RAM usage; many apps use it and it is storage-heavy. ".cache" # ====================================== # Codes / Work / Playground # ====================================== "codes" # for personal code "work" # for work contains a .gitconfig with my work email. "nix-config" "tmp" # ====================================== # Nix / Home Manager Profiles # ====================================== ".local/state/home-manager" ".local/state/nix/profiles" ".local/share/nix" # ====================================== # IDE / Editors # ====================================== # neovim plugins ".wakatime" # vscode ".vscode" ".config/Code" # cursor ai editor ".cursor" ".config/Cursor" # ai agents ".agents" # skills for all agents ".gemini" ".codex" ".config/opencode" ".local/share/opencode" ".kimi" # kimi-cli ".context7" # up-to-date docs and code examples for for LLMs & agents # nvim ".local/share/nvim" ".local/state/nvim" # helix & steel ".local/share/steel" # Joplin ".config/joplin" # tui client ".config/Joplin" # joplin-desktop ".local/share/jupyter" ".ipython" # ====================================== # Cloud Native # ====================================== { # pulumi - infrastructure as code directory = ".pulumi"; mode = "0700"; } { directory = ".aws"; mode = "0700"; } { directory = ".aliyun"; mode = "0700"; } { directory = ".config/gcloud"; mode = "0700"; } { directory = ".docker"; mode = "0700"; } { directory = ".kube"; mode = "0700"; } ".terraform.d/plugin-cache" # terraform's plugin cache # ====================================== # language package managers # ====================================== ".npm" # typsescript/javascript "go" ".cargo" # rust ".m2" # java maven ".gradle" # java gradle ".conda" # python generated by `conda-shell` # python pipx ".local/pipx" ".local/bin" # python uv ".local/share/uv" # ====================================== # Security # ====================================== { directory = ".gnupg"; mode = "0700"; } { directory = ".ssh"; mode = "0700"; } { directory = ".pki"; mode = "0700"; } { directory = ".local/share/password-store"; mode = "0700"; } { # gnmome keyrings directory = ".local/share/keyrings"; mode = "0700"; } # ====================================== # Games / Media # ====================================== "Games" ".steam" ".config/blender" ".config/LDtk" ".config/heroic" ".config/lutris" ".local/share/umu" ".local/share/Steam" ".local/state/Heroic" ".local/share/lutris" ".local/share/tiled" ".local/share/GOG.com" ".local/share/StardewValley" ".local/share/feral-interactive" # ====================================== # Meeting / Remote Desktop / Recording # ====================================== ".zoom" ".config/obs-studio" ".config/sunshine" ".config/freerdp" ".config/remmina" ".local/share/remmina" # ====================================== # browsers # ====================================== ".mozilla" ".config/google-chrome" ".config/chromium" # ====================================== # CLI data # ====================================== ".local/share/atuin" ".local/share/zoxide" ".local/share/direnv" ".local/share/k9s" # ====================================== # Containers # ====================================== ".local/share/containers" ".local/share/flatpak" # flatpak/nixpak app's data { directory = ".var"; mode = "0700"; } # ====================================== # Misc # ====================================== # Clash Verge Rev ".local/share/io.github.clash-verge-rev.clash-verge-rev" ".local/share/clash-verge" # Audio ".config/pulse" ".local/state/wireplumber" # Digital Painting ".local/share/krita" # Japanese IME ".config/mozc" # used by fcitx5-mozc ".config/nushell" ]; files = [ { file = ".wakatime.cfg"; how = "symlink"; } { file = ".config/zoomus.conf"; how = "symlink"; } { file = ".config/zoom.conf"; how = "symlink"; } ]; }; }; # Create some directories with custom permissions. # # In this configuration the path `/home/butz/.local` is not an immediate parent # of any persisted file so it would be created with the systemd-tmpfiles default # ownership `root:root` and mode `0755`. This would mean that the user `butz` # could not create other files or directories inside `/home/butz/.local`. # # Therefore systemd-tmpfiles is used to prepare such directories with # appropriate permissions. # # Note that immediate parent directories of persisted files can also be # configured with ownership and permissions from the `parent` settings if # `configureParent = true` is set for the file. systemd.tmpfiles.settings.preservation = let permission = { user = username; group = lib.mkForce username; mode = lib.mkForce "0750"; }; in { "/home/${username}/.config".d = permission; "/home/${username}/.local".d = permission; "/home/${username}/.local/share".d = permission; "/home/${username}/.local/state".d = permission; "/home/${username}/.local/state/nix".d = permission; "/home/${username}/.terraform.d".d = permission; }; # systemd-machine-id-commit.service would fail but it is not relevant # in this specific setup for a persistent machine-id so we disable it # # see the firstboot example below for an alternative approach systemd.suppressedSystemUnits = [ "systemd-machine-id-commit.service" ]; # let the service commit the transient ID to the persistent volume systemd.services.systemd-machine-id-commit = { unitConfig.ConditionPathIsMountPoint = [ "" "/persistent/etc/machine-id" ]; serviceConfig.ExecStart = [ "" "systemd-machine-id-setup --commit --root /persistent" ]; }; }