{ config, lib, namespace, ... }: with lib; let cfg = config.${namespace}.impermanence; in { imports = [ ./options.nix ]; config = mkIf cfg.enable { environment.persistence."/nix/persist/system" = { hideMounts = true; directories = [ "/var/lib/bluetooth" "/var/lib/iwd" "/var/lib/nixos" "/var/lib/libvirt" "/var/lib/waydroid" "/var/lib/systemd/coredump" "/etc/NetworkManager/system-connections" "/var/lib/tailscale" "/var/lib/homeassistant" "/var/lib/mosquitto" "/var/lib/music-assistant" "/var/lib/postgresql" "/var/lib/zigbee2mqtt" { directory = "/var/lib/colord"; user = "colord"; group = "colord"; mode = "u=rwx,g=rx,o="; } { directory = "/etc/nix"; user = "root"; group = "root"; mode = "u=rwx,g=rx,o=rx"; } { directory = "/var/lib/private/authentik/media"; user = "authentik"; group = "authentik"; mode = "u=rwx,g=,o="; } { directory = "/var/lib/private"; mode = "u=rwx,g=rx,o="; } { directory = "/media/nas"; user = "nas-apps"; group = "jallen-nas"; mode = "u=rwx,g=rx,o=rx"; } { directory = "/var/lib/crowdsec"; user = "crowdsec"; group = "crowdsec"; mode = "u=rwx,g=rwx,o=rx"; } { directory = "/plugins-storage"; user = "traefik"; group = "traefik"; mode = "u=rwx,g=rwx,o=rx"; } ]; files = [ "/etc/machine-id" ]; }; security.sudo.extraConfig = '' # rollback results in sudo lectures after each reboot Defaults lecture = never ''; # system.activationScripts = { # "var-lib-private-permissions" = { # deps = [ "createPersistentStorageDirs" ]; # text = '' # mkdir -p /var/lib/private # chmod 0700 /var/lib/private # ''; # }; # }; # boot.initrd.systemd.services.rootfs-cleanup = { # description = "Clean file system root"; # wantedBy = [ # "initrd.target" # ]; # after = [ # "initrd-root-device.target" # ]; # before = [ # "sysroot.mount" # ]; # unitConfig.DefaultDependencies = "no"; # serviceConfig.Type = "oneshot"; # script = # if (hasAttr "/" config.fileSystems) && (config.fileSystems."/".fsType == "btrfs") then # '' # # workaround for machines without working rtc battery # # The time may not yet be correctly set, so wait until it is # if [[ $(date '+%s') -lt 1730469314 ]]; then # sleep 30 # this should hopefully be enough # fi # mkdir /btrfs_tmp # mount ${config.fileSystems."/".device} -t btrfs /btrfs_tmp # if [[ -e /btrfs_tmp/root ]]; then # mkdir -p /btrfs_tmp/old_roots # timestamp=$(date --date="@$(stat -c %X /btrfs_tmp/root)" "+%Y-%m-%d_%H:%M:%S") # mv /btrfs_tmp/root "/btrfs_tmp/old_roots/$timestamp" # fi # delete_subvolume_recursively() { # IFS=$'\n' # for i in $(btrfs subvolume list -o "$1" | cut -f 9- -d ' '); do # delete_subvolume_recursively "/btrfs_tmp/$i" # done # btrfs subvolume delete "$1" || rm -rf "$1" # } # for i in $(find /btrfs_tmp/old_roots/ -maxdepth 1 -atime +30); do # delete_subvolume_recursively "$i" # done # btrfs subvolume create /btrfs_tmp/root # umount /btrfs_tmp # '' # else if (hasAttr "/" config.fileSystems) && (config.fileSystems."/".fsType == "bcachefs") then # '' # # workaround for machines without working rtc battery # # The time may not yet be correctly set, so wait until it is # if [[ $(date '+%s') -lt 1730469314 ]]; then # sleep 30 # this should hopefully be enough # fi # if [[ -e /root_tmp/root ]]; then # mkdir -p /root_tmp/old_roots # timestamp=$(date --date="@$(stat -c %X /root_tmp/root)" "+%Y-%m-%d_%H:%M:%S") # mv /root_tmp/root "/root_tmp/old_roots/$timestamp" # fi # for i in $(find /root_tmp/old_roots/ -maxdepth 1 -atime +30); do # bcachefs subvolume delete $i # done # bcachefs subvolume create /root_tmp/root # '' # else # # For tmpfs or other filesystems, do nothing # ""; # }; # assertions = [ # { # assertion = hasAttr "/" config.fileSystems; # message = "To use impermanence, you need to define a root volume"; # } # { # assertion = # if hasAttr "/" config.fileSystems then # config.fileSystems."/".fsType == "btrfs" # || config.fileSystems."/".fsType == "bcachefs" # || config.fileSystems."/".fsType == "tmpfs" # else # false; # message = "rootfs must be btrfs, bcachefs, or tmpfs; not " + config.fileSystems."/".fsType; # } # { # assertion = # if # hasAttr "/" config.fileSystems # && (config.fileSystems."/".fsType == "btrfs" || config.fileSystems."/".fsType == "bcachefs") # then # any ( # t: t == "subvol=root" || t == "subvol=/root" || t == "X-mount.subdir=root" # ) config.fileSystems."/".options # else # true; # message = "btrfs or bcachefs rootfs must mount subvolume root"; # } # { # assertion = !config.boot.isContainer; # message = "impermanence is not supported in containers"; # } # ]; # environment.persistence.${cfg.persistencePath} = { # hideMounts = true; # directories = [ # "/var/lib/bluetooth" # "/var/lib/iwd" # "/var/lib/nixos" # "/var/lib/libvirt" # "/var/lib/waydroid" # "/var/lib/systemd/coredump" # "/etc/NetworkManager/system-connections" # "/var/lib/tailscale" # "/var/lib/homeassistant" # "/var/lib/mosquitto" # "/var/lib/music-assistant" # "/var/lib/postgresql" # "/var/lib/zigbee2mqtt" # { # directory = "/var/lib/colord"; # user = "colord"; # group = "colord"; # mode = "u=rwx,g=rx,o="; # } # { # directory = "/etc/nix"; # user = "root"; # group = "root"; # mode = "u=rwx,g=rx,o=rx"; # } # { # directory = "/var/lib/private/authentik/media"; # user = "authentik"; # group = "authentik"; # mode = "u=rwx,g=,o="; # } # { # directory = "/var/lib/private"; # mode = "u=rwx,g=rx,o="; # } # { # directory = "/media/nas"; # user = "nas-apps"; # group = "jallen-nas"; # mode = "u=rwx,g=rx,o=rx"; # } # { # directory = "/var/lib/crowdsec"; # user = "crowdsec"; # group = "crowdsec"; # mode = "u=rwx,g=rwx,o=rx"; # } # { # directory = "/plugins-storage"; # user = "traefik"; # group = "traefik"; # mode = "u=rwx,g=rwx,o=rx"; # } # ]; # files = [ # "/etc/machine-id" # ]; # }; }; }