Using nix without root
The nix package manager is a purely functional package manager that enforces a declarative and hermetic style of building packages. I wanted to use nix to create per project development environments and what I learned is conventional nix installs come in two flavors.
- Via NixOS where it is the default and only package manager.
- Via an installer script which requires root access on Linux or macOS to create the
/nixfolder and in mutli-user situations a persistent daemon.
NixOS is a non starter for creating per project development environments and requiring root to create a development environment is not ideal. Instead I discovered it’s possible to setup nix as a non root user and the rest of the post outlines how to do that.
Getting the binary
The first problem to solve is getting the
nix binary. The easiest way to get a
nix static build from the hydra CI system1. A fully static binary is available for the
2.14 branch of the
nix command by running:
Setting up the /nix directory
The next problem is ensuring the
nix binary has access to
/nix directory for storage. Although
nix can be configured to use any directory for storage, the official hydra CI system build all nix packages with the nix store in
/nix. Using the same directory allows
nix to download cached artifacts instead of re-building every package locally. There are two options to setup the
Option 1: Using the built in chroot
The first option is to use the built in logic that creates
~/.local/share/nix/root and uses linux namespaces to bind mount that as
/nix. This means simply running the following will build GNU Hello and re-use cached artifacts if available.
Running the above for the first time
nix will output.
warning: ‘/nix/var/nix’ does not exist, so Nix will use ‘/home/zmanji/.local/share/nix/root’ as a chroot store
Subsequent commands will reuse that folder as the
nix store and
nix will use user namespaces to mount that directory as
/nix for each command.
nix store ls also work as expected as well:
The drawback to this option is the directory is not customizable.
Option 2: Running with bubblewrap
The other option use to use the bubblewrap tool to setup the mounts instead of relying on the built in features of
nix. This allows customization of the underlying directory for the
/nix mount and can also prevent
nix from accessing certain directories as a security measure.
This can be done with the following command.
This creates the
/nix store under
./mynixroot and bind mounts most of the system as read only.
nix will use the
./mynixroot for the nix store. This can be useful in select environments where using
~/.local/share/nix/root is not appropriate.
One alternative is the nix-user-chroot tool which also uses user namespaces to setup the
/nix directory. However at the time of writing it has a bug which prevents strict sandboxing which means there is no guarantee builds will be hermetic. I think the built in chroot functionality or relying on bubblewrap is superior as it still allows
nix to enable strict sandboxing for builds.
It’s very easy to setup
nix without switching to NixOS or without root access. Just with one static binary it’s possible to use
nix for a specific project.
Strangely enough this is not mentioned on the download page at all↩︎