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
/nix
folder 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 /nix
directory.
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.
Commands like 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.
Other Alternatives
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.
Conclusion
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.