impermanence
impermanence copied to clipboard
Modules to help you handle persistent state on systems with ephemeral root storage [maintainer=@talyz]
-
Impermanence
Modules to help you handle persistent state on systems with ephemeral root storage.
The premises of the modules are that you
-
have a root filesystem which somehow gets wiped on reboot - e.g. using tmpfs on /
-
have a mount point where state is kept between reboots
-
want to create links from temporary storage to persistent storage, so that specified files and folders persist between reboots
There are currently two modules: one for ~NixOS~ and one for ~home-manager~.
-
*** NixOS
To use the module, import it into your configuration with
#+begin_src nix
{
imports = [ /path/to/impermanence/nixos.nix ];
}
#+end_src
This adds the ~environment.persistence~ option, which is an
attribute set of submodules, where the attribute name is the path
to persistent storage.
Usage is shown best with an example:
#+begin_src nix
{
environment.persistence."/persistent" = {
hideMounts = true;
directories = [
"/var/log"
"/var/lib/bluetooth"
"/var/lib/systemd/coredump"
"/etc/NetworkManager/system-connections"
{ directory = "/var/lib/colord"; user = "colord"; group = "colord"; mode = "u=rwx,g=rx,o="; }
];
files = [
"/etc/machine-id"
{ file = "/etc/nix/id_rsa"; parentDirectory = { mode = "u=rwx,g=,o="; }; }
];
users.talyz = {
directories = [
"Downloads"
"Music"
"Pictures"
"Documents"
"Videos"
"VirtualBox VMs"
{ directory = ".gnupg"; mode = "0700"; }
{ directory = ".ssh"; mode = "0700"; }
{ directory = ".nixops"; mode = "0700"; }
{ directory = ".local/share/keyrings"; mode = "0700"; }
".local/share/direnv"
];
files = [
".screenrc"
];
};
};
}
#+end_src
- ~"/persistent"~ is the path to your persistent storage location
This allows for multiple different persistent storage
locations. If you, for example, have one location you back up
and one you don't, you can use both by defining two separate
attributes under ~environment.persistence~.
- ~directories~ are all directories you want to bind mount to
persistent storage. A directory can be represented either as a
string, simply denoting its path, or as a submodule. The
submodule representation is useful when the default assumptions,
mainly regarding permissions, are incorrect. The available
options are:
- ~directory~, the path to the directory you want to bind mount
to persistent storage. Only setting this option is
equivalent to the string representation.
- ~persistentStoragePath~, the path to persistent
storage. Defaults to the ~environment.persistence~ submodule
name, i.e. ~"/persistent"~ in the example. This should most
likely be left to its default value - don't change it unless
you're certain you really need to.
- ~user~, the user who should own the directory. If the directory
doesn't already exist in persistent storage, it will be
created and this user will be its owner. This also applies to
any parent directories which don't yet exist. Changing this
once the directory has been created has no effect.
- ~group~, the group who should own the directory. If the
directory doesn't already exist in persistent storage, it will
be created and this group will be its owner. This also applies
to any parent directories which don't yet exist. Changing this
once the directory has been created has no effect.
- ~mode~, the permissions to set for the directory. If the
directory doesn't already exist in persistent storage, it will
be created with this mode. Can be either an octal mode
(e.g. ~0700~) or a symbolic mode (e.g. ~u=rwx,g=,o=~). This also
applies to any parent directories which don't yet exist.
Changing this once the directory has been created has no
effect.
- ~files~ are all files you want to link or bind to persistent
storage. A file can be represented either as a string, simply
denoting its path, or as a submodule. The submodule
representation is useful when the default assumptions, mainly
regarding the permissions of its parent directory, are
incorrect. The available options are:
- ~file~, the path to the file you want to bind mount to
persistent storage. Only setting this option is equivalent to
the string representation.
- ~persistentStoragePath~, the path to persistent
storage. Defaults to the ~environment.persistence~ submodule
name, i.e. ~"/persistent"~ in the example. This should most
likely be left to its default value - don't change it unless
you're certain you really need to.
- ~parentDirectory~, the permissions that should be applied to the
file's parent directory, if it doesn't already
exist. Available options are ~user~, ~group~ and ~mode~. See their
definition in ~directories~ above.
If the file exists in persistent storage, it will be bind
mounted to the target path; otherwise it will be symlinked.
- ~hideMounts~ allows you to specify whether to hide the
bind mounts from showing up as mounted drives in the file
manager. If enabled, it sets the mount option ~x-gvfs-hide~
on all the bind mounts.
- ~users.talyz~ handles files and directories in ~talyz~'s home
directory
The ~users~ option defines a set of submodules which correspond to
the users' names. The ~directories~ and ~files~ options of each
submodule work like their root counterparts, but the paths are
automatically prefixed with with the user's home directory.
If the user has a non-standard home directory (i.e. not
~/home/<username>~), the ~users.<username>.home~ option has to be
set to this path - it can't currently be automatically deduced
due to a limitation in ~nixpkgs~.
/Important note:/ Make sure your persistent volumes are marked with
~neededForBoot~, otherwise you will run into problems.
*** home-manager
Usage of the ~home-manager~ module is very similar to the one of the
~NixOS~ module - the key differences are that the ~persistence~ option
is now under ~home~, rather than ~environment~, and the addition of
the submodule option ~removePrefixDirectory~.
/Important note:/ You have to use the ~home-manager~ ~NixOS~ module (in
the ~nixos~ directory of ~home-manager~'s repo) in order for this
module to work as intended.
To use the module, import it into your configuration with
#+begin_src nix
{
imports = [ /path/to/impermanence/home-manager.nix ];
}
#+end_src
This adds the ~home.persistence~ option, which is an attribute set
of submodules, where the attribute name is the path to persistent
storage.
Usage is shown best with an example:
#+begin_src nix
{
home.persistence."/persistent/home/talyz" = {
directories = [
"Downloads"
"Music"
"Pictures"
"Documents"
"Videos"
"VirtualBox VMs"
".gnupg"
".ssh"
".nixops"
".local/share/keyrings"
".local/share/direnv"
];
files = [
".screenrc"
];
allowOther = true;
};
}
#+end_src
- ~"/persistent/home/talyz"~ is the path to your persistent storage location
- ~directories~ are all directories you want to link to persistent storage
- ~files~ are all files you want to link to persistent storage
- ~allowOther~ allows other users, such as ~root~, to access files
through the bind mounted directories listed in
~directories~. Useful for ~sudo~ operations, Docker, etc. Requires
the NixOS configuration ~programs.fuse.userAllowOther = true~.
Additionally, the ~home-manager~ module allows for compatibility
with ~dotfiles~ repos structured for use with [[https://www.gnu.org/software/stow/][GNU Stow]], where the
files linked to are one level deeper than where they should end
up. This can be achieved by setting ~removePrefixDirectory~ to ~true~:
#+begin_src nix
{
home.persistence."/etc/nixos/home-talyz-nixpkgs/dotfiles" = {
removePrefixDirectory = true;
files = [
"screen/.screenrc"
];
directories = [
"fish/.config/fish"
];
};
}
#+end_src
In the example, the ~.screenrc~ file and ~.config/fish~ directory
should be linked to from the home directory; ~removePrefixDirectory~
removes the first part of the path when deciding where to put the
links.
/Note:/ Since this module uses the ~bindfs~ fuse filesystem for
directories, the names of the directories you add will be visible
in the ~/etc/mtab~ file and in the output of ~mount~ to all users.
** Further reading The following blog posts provide more information on the concept of ephemeral roots:
- https://elis.nu/blog/2020/05/nixos-tmpfs-as-root/ --- [[https://github.com/etu/][@etu]]'s blog post walks the reader through a NixOS-on-tmpfs installation.
- https://grahamc.com/blog/erase-your-darlings --- [[https://github.com/grahamc/][@grahamc]]'s blog post details why one would want to erase their state at every boot, as well as how to achieve this using ZFS snapshots.
** About the name : Impermanence, also known as the philosophical problem of change, is a : philosophical concept that is addressed in a variety of religions and : philosophies. In Eastern philosophy it is best known for its role in the : Buddhist three marks of existence. It also is an element of Hinduism.