September 2, 2018·4 min read·engineeringnixinstallationlinuxevaluator

Nix 2.1 brings the multi-user installer to systemd Linux

Nix 2.1 adds a systemd Linux multi-user installation route and extends the evaluator and cache implementation.

A shared package store needs a boundary between the users requesting builds and the accounts allowed to modify the store. Nix already has a multi-user design for that boundary. The Nix 2.1 release notes, dated September 2, add installer support for that arrangement on Linux systems running systemd. The change makes an existing operating mode easier to install on a named class of host.

The installer selects multi-user operation through --daemon. The release explicitly excludes systems with SELinux from that installer path and points them towards single-user installation. It also changes macOS installation so multi-user mode is no longer the default there, while remaining selectable. These are installer capabilities and defaults, rather than a claim that the underlying multi-user design has only just appeared.

I am interested in Nix because a machine configuration can state how software should be assembled. The ownership of the store is part of that operational model. A repeatable package description does not remove the need to control which account can alter the shared results used by other people.

Why the daemon owns the operation

The multi-user documentation at the release tag explains the problem directly. If ordinary users could run builders that modified the shared store or its database arbitrarily, they could interfere with builds requested by another user or insert a compromised package. Shared writable package state requires stronger control than each user merely agreeing to behave.

The design assigns the store and database to a privileged owner, usually root. A daemon running under that owner performs store operations requested by unprivileged users. Builders execute under separate build accounts, commonly named nixbld1 and similar. Requesting the build, managing the store, and running the builder are consequently different roles.

The documentation says the build-user group should have no unrelated members, and the build accounts should not belong to other groups. The accounts exist to constrain the identities under which builds execute. They are not ordinary interactive users that happen to share a package directory.

The number of build accounts also constrains concurrency. The manual says simultaneous builds cannot exceed the available build users. That is an operational property of the multi-user arrangement, separate from how many builds a user asks Nix to start. The installer has to establish the accounts and daemon integration needed for that mode to work.

This explains why the Linux installer addition matters without overstating its novelty. Manually assembling a privileged daemon and build users is administrative work. A supported installation route can make the same separation available through a defined procedure, while retaining the host restrictions documented by the release.

Multi-user access is not unrestricted trust

The manual also distinguishes evaluating arbitrary expressions from choosing arbitrary binary caches. It says only root and configured trusted users can specify arbitrary caches in multi-user mode. An unprivileged user can request a package described by an expression without thereby acquiring authority to nominate every source of prebuilt results for the shared store.

That distinction follows the shared-state problem. A daemon serving several users needs an acceptance policy for results introduced into the common store. The right to ask for a build and the right to determine that policy need not belong to the same set of users. Multi-user installation establishes a service arrangement in which those permissions can differ.

Socket access provides another control. The documented daemon socket directory can use filesystem permissions to restrict which users connect. Limiting access to a group prevents other accounts from performing Nix operations through that socket. It controls entry to the daemon, while trusted-user configuration controls an additional level of authority for clients that can connect.

I find those distinctions useful when describing a shared installation. Saying that everybody uses the same store is incomplete without explaining who accepts requests, who runs builders, and which clients can change trust-related choices. The installer makes the mode available, but the meaning of the mode comes from those responsibilities.

Evaluator additions preserve structure

Nix 2.1 also introduces builtins for bitwise operations, TOML parsing, attribute mapping, and concatenating mapping. These are additions to the evaluator rather than daemon installation settings. Their presence in the same release should not imply that they require a multi-user installation to be useful.

The evaluator source makes the behaviour of mapAttrs concrete. It retains each attribute name and applies the supplied function to that name and its value. This differs from mapping only an anonymous list of values, because the transformation can depend on the attribute identity while preserving the attribute set structure.

The same source describes concatMap as mapping a function over a list and concatenating the resulting lists. Its implementation calls the function for each input element and checks that the result is a list before constructing the combined result. The bitwise builtins force integer arguments before applying AND, OR, or XOR. Those checks define what kind of values each operation expects.

Cache repairs address different limits

The release expands S3 cache uploading to NARs larger than 5 GiB and adds an endpoint option for S3-compatible services. One change concerns object size support, while the other concerns which compatible service receives the upload. Neither is a new evaluator function or a different daemon ownership model.

Recovery from disappeared NARs in a binary cache no longer requires --fallback. The notes also say nix-daemon now respects --store, and nix run respects propagated user-environment packages. These are focused changes to existing operations, consistent with the release description of 2.1 as primarily a bug-fix release.

The systemd Linux installer addition therefore arrives alongside repairs to the tools it installs. Its practical contribution is a defined route into a shared-store operating mode. The documentation explains that mode through privileged store ownership, isolated build accounts, and distinct client permissions, which remain the relevant mechanisms after the installer finishes.