1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6
7 cfg = config.nix;
8
9 nixPackage = cfg.package.out;
10
11 isNixAtLeast = versionAtLeast (getVersion nixPackage);
12
13 makeNixBuildUser = nr: {
14 name = "nixbld${toString nr}";
15 value = {
16 description = "Nix build user ${toString nr}";
17
18 /*
19 For consistency with the setgid(2), setuid(2), and setgroups(2)
20 calls in `libstore/build.cc', don't add any supplementary group
21 here except "nixbld".
22 */
23 uid = builtins.add config.ids.uids.nixbld nr;
24 isSystemUser = true;
25 group = "nixbld";
26 extraGroups = [ "nixbld" ];
27 };
28 };
29
30 nixbldUsers = listToAttrs (map makeNixBuildUser (range 1 cfg.nrBuildUsers));
31
32 nixConf =
33 assert isNixAtLeast "2.2";
34 let
35
36 mkValueString = v:
37 if v == null then ""
38 else if isInt v then toString v
39 else if isBool v then boolToString v
40 else if isFloat v then floatToString v
41 else if isList v then toString v
42 else if isDerivation v then toString v
43 else if builtins.isPath v then toString v
44 else if isString v then v
45 else if strings.isConvertibleWithToString v then toString v
46 else abort "The nix conf value: ${toPretty {} v} can not be encoded";
47
48 mkKeyValue = k: v: "${escape [ "=" ] k} = ${mkValueString v}";
49
50 mkKeyValuePairs = attrs: concatStringsSep "\n" (mapAttrsToList mkKeyValue attrs);
51
52 in
53 pkgs.writeTextFile {
54 name = "nix.conf";
55 text = ''
56 # WARNING: this file is generated from the nix.* options in
57 # your NixOS configuration, typically
58 # /etc/nixos/configuration.nix. Do not edit it!
59 ${mkKeyValuePairs cfg.settings}
60 ${cfg.extraOptions}
61 '';
62 checkPhase = lib.optionalString cfg.checkConfig (
63 if pkgs.stdenv.hostPlatform != pkgs.stdenv.buildPlatform then ''
64 echo "Ignoring validation for cross-compilation"
65 ''
66 else ''
67 echo "Validating generated nix.conf"
68 ln -s $out ./nix.conf
69 set -e
70 set +o pipefail
71 NIX_CONF_DIR=$PWD \
72 ${cfg.package}/bin/nix show-config ${optionalString (isNixAtLeast "2.3pre") "--no-net"} \
73 ${optionalString (isNixAtLeast "2.4pre") "--option experimental-features nix-command"} \
74 |& sed -e 's/^warning:/error:/' \
75 | (! grep '${if cfg.checkAllErrors then "^error:" else "^error: unknown setting"}')
76 set -o pipefail
77 '');
78 };
79
80 legacyConfMappings = {
81 useSandbox = "sandbox";
82 buildCores = "cores";
83 maxJobs = "max-jobs";
84 sandboxPaths = "extra-sandbox-paths";
85 binaryCaches = "substituters";
86 trustedBinaryCaches = "trusted-substituters";
87 binaryCachePublicKeys = "trusted-public-keys";
88 autoOptimiseStore = "auto-optimise-store";
89 requireSignedBinaryCaches = "require-sigs";
90 trustedUsers = "trusted-users";
91 allowedUsers = "allowed-users";
92 systemFeatures = "system-features";
93 };
94
95 semanticConfType = with types;
96 let
97 confAtom = nullOr
98 (oneOf [
99 bool
100 int
101 float
102 str
103 path
104 package
105 ]) // {
106 description = "Nix config atom (null, bool, int, float, str, path or package)";
107 };
108 in
109 attrsOf (either confAtom (listOf confAtom));
110
111in
112
113{
114 imports = [
115 (mkRenamedOptionModuleWith { sinceRelease = 2003; from = [ "nix" "useChroot" ]; to = [ "nix" "useSandbox" ]; })
116 (mkRenamedOptionModuleWith { sinceRelease = 2003; from = [ "nix" "chrootDirs" ]; to = [ "nix" "sandboxPaths" ]; })
117 (mkRenamedOptionModuleWith { sinceRelease = 2205; from = [ "nix" "daemonIONiceLevel" ]; to = [ "nix" "daemonIOSchedPriority" ]; })
118 (mkRenamedOptionModuleWith { sinceRelease = 2211; from = [ "nix" "readOnlyStore" ]; to = [ "boot" "readOnlyNixStore" ]; })
119 (mkRemovedOptionModule [ "nix" "daemonNiceLevel" ] "Consider nix.daemonCPUSchedPolicy instead.")
120 ] ++ mapAttrsToList (oldConf: newConf: mkRenamedOptionModuleWith { sinceRelease = 2205; from = [ "nix" oldConf ]; to = [ "nix" "settings" newConf ]; }) legacyConfMappings;
121
122 ###### interface
123
124 options = {
125
126 nix = {
127
128 enable = mkOption {
129 type = types.bool;
130 default = true;
131 description = lib.mdDoc ''
132 Whether to enable Nix.
133 Disabling Nix makes the system hard to modify and the Nix programs and configuration will not be made available by NixOS itself.
134 '';
135 };
136
137 package = mkOption {
138 type = types.package;
139 default = pkgs.nix;
140 defaultText = literalExpression "pkgs.nix";
141 description = lib.mdDoc ''
142 This option specifies the Nix package instance to use throughout the system.
143 '';
144 };
145
146 distributedBuilds = mkOption {
147 type = types.bool;
148 default = false;
149 description = lib.mdDoc ''
150 Whether to distribute builds to the machines listed in
151 {option}`nix.buildMachines`.
152 '';
153 };
154
155 daemonCPUSchedPolicy = mkOption {
156 type = types.enum [ "other" "batch" "idle" ];
157 default = "other";
158 example = "batch";
159 description = lib.mdDoc ''
160 Nix daemon process CPU scheduling policy. This policy propagates to
161 build processes. `other` is the default scheduling
162 policy for regular tasks. The `batch` policy is
163 similar to `other`, but optimised for
164 non-interactive tasks. `idle` is for extremely
165 low-priority tasks that should only be run when no other task
166 requires CPU time.
167
168 Please note that while using the `idle` policy may
169 greatly improve responsiveness of a system performing expensive
170 builds, it may also slow down and potentially starve crucial
171 configuration updates during load.
172
173 `idle` may therefore be a sensible policy for
174 systems that experience only intermittent phases of high CPU load,
175 such as desktop or portable computers used interactively. Other
176 systems should use the `other` or
177 `batch` policy instead.
178
179 For more fine-grained resource control, please refer to
180 {manpage}`systemd.resource-control(5)` and adjust
181 {option}`systemd.services.nix-daemon` directly.
182 '';
183 };
184
185 daemonIOSchedClass = mkOption {
186 type = types.enum [ "best-effort" "idle" ];
187 default = "best-effort";
188 example = "idle";
189 description = lib.mdDoc ''
190 Nix daemon process I/O scheduling class. This class propagates to
191 build processes. `best-effort` is the default
192 class for regular tasks. The `idle` class is for
193 extremely low-priority tasks that should only perform I/O when no
194 other task does.
195
196 Please note that while using the `idle` scheduling
197 class can improve responsiveness of a system performing expensive
198 builds, it might also slow down or starve crucial configuration
199 updates during load.
200
201 `idle` may therefore be a sensible class for
202 systems that experience only intermittent phases of high I/O load,
203 such as desktop or portable computers used interactively. Other
204 systems should use the `best-effort` class.
205 '';
206 };
207
208 daemonIOSchedPriority = mkOption {
209 type = types.int;
210 default = 4;
211 example = 1;
212 description = lib.mdDoc ''
213 Nix daemon process I/O scheduling priority. This priority propagates
214 to build processes. The supported priorities depend on the
215 scheduling policy: With idle, priorities are not used in scheduling
216 decisions. best-effort supports values in the range 0 (high) to 7
217 (low).
218 '';
219 };
220
221 buildMachines = mkOption {
222 type = types.listOf (types.submodule {
223 options = {
224 hostName = mkOption {
225 type = types.str;
226 example = "nixbuilder.example.org";
227 description = lib.mdDoc ''
228 The hostname of the build machine.
229 '';
230 };
231 protocol = mkOption {
232 type = types.enum [ null "ssh" "ssh-ng" ];
233 default = "ssh";
234 example = "ssh-ng";
235 description = lib.mdDoc ''
236 The protocol used for communicating with the build machine.
237 Use `ssh-ng` if your remote builder and your
238 local Nix version support that improved protocol.
239
240 Use `null` when trying to change the special localhost builder
241 without a protocol which is for example used by hydra.
242 '';
243 };
244 system = mkOption {
245 type = types.nullOr types.str;
246 default = null;
247 example = "x86_64-linux";
248 description = lib.mdDoc ''
249 The system type the build machine can execute derivations on.
250 Either this attribute or {var}`systems` must be
251 present, where {var}`system` takes precedence if
252 both are set.
253 '';
254 };
255 systems = mkOption {
256 type = types.listOf types.str;
257 default = [ ];
258 example = [ "x86_64-linux" "aarch64-linux" ];
259 description = lib.mdDoc ''
260 The system types the build machine can execute derivations on.
261 Either this attribute or {var}`system` must be
262 present, where {var}`system` takes precedence if
263 both are set.
264 '';
265 };
266 sshUser = mkOption {
267 type = types.nullOr types.str;
268 default = null;
269 example = "builder";
270 description = lib.mdDoc ''
271 The username to log in as on the remote host. This user must be
272 able to log in and run nix commands non-interactively. It must
273 also be privileged to build derivations, so must be included in
274 {option}`nix.settings.trusted-users`.
275 '';
276 };
277 sshKey = mkOption {
278 type = types.nullOr types.str;
279 default = null;
280 example = "/root/.ssh/id_buildhost_builduser";
281 description = lib.mdDoc ''
282 The path to the SSH private key with which to authenticate on
283 the build machine. The private key must not have a passphrase.
284 If null, the building user (root on NixOS machines) must have an
285 appropriate ssh configuration to log in non-interactively.
286
287 Note that for security reasons, this path must point to a file
288 in the local filesystem, *not* to the nix store.
289 '';
290 };
291 maxJobs = mkOption {
292 type = types.int;
293 default = 1;
294 description = lib.mdDoc ''
295 The number of concurrent jobs the build machine supports. The
296 build machine will enforce its own limits, but this allows hydra
297 to schedule better since there is no work-stealing between build
298 machines.
299 '';
300 };
301 speedFactor = mkOption {
302 type = types.int;
303 default = 1;
304 description = lib.mdDoc ''
305 The relative speed of this builder. This is an arbitrary integer
306 that indicates the speed of this builder, relative to other
307 builders. Higher is faster.
308 '';
309 };
310 mandatoryFeatures = mkOption {
311 type = types.listOf types.str;
312 default = [ ];
313 example = [ "big-parallel" ];
314 description = lib.mdDoc ''
315 A list of features mandatory for this builder. The builder will
316 be ignored for derivations that don't require all features in
317 this list. All mandatory features are automatically included in
318 {var}`supportedFeatures`.
319 '';
320 };
321 supportedFeatures = mkOption {
322 type = types.listOf types.str;
323 default = [ ];
324 example = [ "kvm" "big-parallel" ];
325 description = lib.mdDoc ''
326 A list of features supported by this builder. The builder will
327 be ignored for derivations that require features not in this
328 list.
329 '';
330 };
331 publicHostKey = mkOption {
332 type = types.nullOr types.str;
333 default = null;
334 description = lib.mdDoc ''
335 The (base64-encoded) public host key of this builder. The field
336 is calculated via {command}`base64 -w0 /etc/ssh/ssh_host_type_key.pub`.
337 If null, SSH will use its regular known-hosts file when connecting.
338 '';
339 };
340 };
341 });
342 default = [ ];
343 description = lib.mdDoc ''
344 This option lists the machines to be used if distributed builds are
345 enabled (see {option}`nix.distributedBuilds`).
346 Nix will perform derivations on those machines via SSH by copying the
347 inputs to the Nix store on the remote machine, starting the build,
348 then copying the output back to the local Nix store.
349 '';
350 };
351
352 # Environment variables for running Nix.
353 envVars = mkOption {
354 type = types.attrs;
355 internal = true;
356 default = { };
357 description = lib.mdDoc "Environment variables used by Nix.";
358 };
359
360 nrBuildUsers = mkOption {
361 type = types.int;
362 description = lib.mdDoc ''
363 Number of `nixbld` user accounts created to
364 perform secure concurrent builds. If you receive an error
365 message saying that “all build users are currently in use”,
366 you should increase this value.
367 '';
368 };
369
370 nixPath = mkOption {
371 type = types.listOf types.str;
372 default = [
373 "nixpkgs=/nix/var/nix/profiles/per-user/root/channels/nixos"
374 "nixos-config=/etc/nixos/configuration.nix"
375 "/nix/var/nix/profiles/per-user/root/channels"
376 ];
377 description = lib.mdDoc ''
378 The default Nix expression search path, used by the Nix
379 evaluator to look up paths enclosed in angle brackets
380 (e.g. `<nixpkgs>`).
381 '';
382 };
383
384 checkConfig = mkOption {
385 type = types.bool;
386 default = true;
387 description = lib.mdDoc ''
388 If enabled, checks that Nix can parse the generated nix.conf.
389 '';
390 };
391
392 checkAllErrors = mkOption {
393 type = types.bool;
394 default = true;
395 description = lib.mdDoc ''
396 If enabled, checks the nix.conf parsing for any kind of error. When disabled, checks only for unknown settings.
397 '';
398 };
399
400 registry = mkOption {
401 type = types.attrsOf (types.submodule (
402 let
403 referenceAttrs = with types; attrsOf (oneOf [
404 str
405 int
406 bool
407 path
408 package
409 ]);
410 in
411 { config, name, ... }:
412 {
413 options = {
414 from = mkOption {
415 type = referenceAttrs;
416 example = { type = "indirect"; id = "nixpkgs"; };
417 description = lib.mdDoc "The flake reference to be rewritten.";
418 };
419 to = mkOption {
420 type = referenceAttrs;
421 example = { type = "github"; owner = "my-org"; repo = "my-nixpkgs"; };
422 description = lib.mdDoc "The flake reference {option}`from` is rewritten to.";
423 };
424 flake = mkOption {
425 type = types.nullOr types.attrs;
426 default = null;
427 example = literalExpression "nixpkgs";
428 description = lib.mdDoc ''
429 The flake input {option}`from` is rewritten to.
430 '';
431 };
432 exact = mkOption {
433 type = types.bool;
434 default = true;
435 description = lib.mdDoc ''
436 Whether the {option}`from` reference needs to match exactly. If set,
437 a {option}`from` reference like `nixpkgs` does not
438 match with a reference like `nixpkgs/nixos-20.03`.
439 '';
440 };
441 };
442 config = {
443 from = mkDefault { type = "indirect"; id = name; };
444 to = mkIf (config.flake != null) (mkDefault (
445 {
446 type = "path";
447 path = config.flake.outPath;
448 } // filterAttrs
449 (n: _: n == "lastModified" || n == "rev" || n == "revCount" || n == "narHash")
450 config.flake
451 ));
452 };
453 }
454 ));
455 default = { };
456 description = lib.mdDoc ''
457 A system-wide flake registry.
458 '';
459 };
460
461 extraOptions = mkOption {
462 type = types.lines;
463 default = "";
464 example = ''
465 keep-outputs = true
466 keep-derivations = true
467 '';
468 description = lib.mdDoc "Additional text appended to {file}`nix.conf`.";
469 };
470
471 settings = mkOption {
472 type = types.submodule {
473 freeformType = semanticConfType;
474
475 options = {
476 max-jobs = mkOption {
477 type = types.either types.int (types.enum [ "auto" ]);
478 default = "auto";
479 example = 64;
480 description = lib.mdDoc ''
481 This option defines the maximum number of jobs that Nix will try to
482 build in parallel. The default is auto, which means it will use all
483 available logical cores. It is recommend to set it to the total
484 number of logical cores in your system (e.g., 16 for two CPUs with 4
485 cores each and hyper-threading).
486 '';
487 };
488
489 auto-optimise-store = mkOption {
490 type = types.bool;
491 default = false;
492 example = true;
493 description = lib.mdDoc ''
494 If set to true, Nix automatically detects files in the store that have
495 identical contents, and replaces them with hard links to a single copy.
496 This saves disk space. If set to false (the default), you can still run
497 nix-store --optimise to get rid of duplicate files.
498 '';
499 };
500
501 cores = mkOption {
502 type = types.int;
503 default = 0;
504 example = 64;
505 description = lib.mdDoc ''
506 This option defines the maximum number of concurrent tasks during
507 one build. It affects, e.g., -j option for make.
508 The special value 0 means that the builder should use all
509 available CPU cores in the system. Some builds may become
510 non-deterministic with this option; use with care! Packages will
511 only be affected if enableParallelBuilding is set for them.
512 '';
513 };
514
515 sandbox = mkOption {
516 type = types.either types.bool (types.enum [ "relaxed" ]);
517 default = true;
518 description = lib.mdDoc ''
519 If set, Nix will perform builds in a sandboxed environment that it
520 will set up automatically for each build. This prevents impurities
521 in builds by disallowing access to dependencies outside of the Nix
522 store by using network and mount namespaces in a chroot environment.
523 This is enabled by default even though it has a possible performance
524 impact due to the initial setup time of a sandbox for each build. It
525 doesn't affect derivation hashes, so changing this option will not
526 trigger a rebuild of packages.
527 '';
528 };
529
530 extra-sandbox-paths = mkOption {
531 type = types.listOf types.str;
532 default = [ ];
533 example = [ "/dev" "/proc" ];
534 description = lib.mdDoc ''
535 Directories from the host filesystem to be included
536 in the sandbox.
537 '';
538 };
539
540 substituters = mkOption {
541 type = types.listOf types.str;
542 description = lib.mdDoc ''
543 List of binary cache URLs used to obtain pre-built binaries
544 of Nix packages.
545
546 By default https://cache.nixos.org/ is added.
547 '';
548 };
549
550 trusted-substituters = mkOption {
551 type = types.listOf types.str;
552 default = [ ];
553 example = [ "https://hydra.nixos.org/" ];
554 description = lib.mdDoc ''
555 List of binary cache URLs that non-root users can use (in
556 addition to those specified using
557 {option}`nix.settings.substituters`) by passing
558 `--option binary-caches` to Nix commands.
559 '';
560 };
561
562 require-sigs = mkOption {
563 type = types.bool;
564 default = true;
565 description = lib.mdDoc ''
566 If enabled (the default), Nix will only download binaries from binary caches if
567 they are cryptographically signed with any of the keys listed in
568 {option}`nix.settings.trusted-public-keys`. If disabled, signatures are neither
569 required nor checked, so it's strongly recommended that you use only
570 trustworthy caches and https to prevent man-in-the-middle attacks.
571 '';
572 };
573
574 trusted-public-keys = mkOption {
575 type = types.listOf types.str;
576 example = [ "hydra.nixos.org-1:CNHJZBh9K4tP3EKF6FkkgeVYsS3ohTl+oS0Qa8bezVs=" ];
577 description = lib.mdDoc ''
578 List of public keys used to sign binary caches. If
579 {option}`nix.settings.trusted-public-keys` is enabled,
580 then Nix will use a binary from a binary cache if and only
581 if it is signed by *any* of the keys
582 listed here. By default, only the key for
583 `cache.nixos.org` is included.
584 '';
585 };
586
587 trusted-users = mkOption {
588 type = types.listOf types.str;
589 default = [ "root" ];
590 example = [ "root" "alice" "@wheel" ];
591 description = lib.mdDoc ''
592 A list of names of users that have additional rights when
593 connecting to the Nix daemon, such as the ability to specify
594 additional binary caches, or to import unsigned NARs. You
595 can also specify groups by prefixing them with
596 `@`; for instance,
597 `@wheel` means all users in the wheel
598 group.
599 '';
600 };
601
602 system-features = mkOption {
603 type = types.listOf types.str;
604 example = [ "kvm" "big-parallel" "gccarch-skylake" ];
605 description = lib.mdDoc ''
606 The set of features supported by the machine. Derivations
607 can express dependencies on system features through the
608 `requiredSystemFeatures` attribute.
609
610 By default, pseudo-features `nixos-test`, `benchmark`,
611 and `big-parallel` used in Nixpkgs are set, `kvm`
612 is also included if it is available.
613 '';
614 };
615
616 allowed-users = mkOption {
617 type = types.listOf types.str;
618 default = [ "*" ];
619 example = [ "@wheel" "@builders" "alice" "bob" ];
620 description = lib.mdDoc ''
621 A list of names of users (separated by whitespace) that are
622 allowed to connect to the Nix daemon. As with
623 {option}`nix.settings.trusted-users`, you can specify groups by
624 prefixing them with `@`. Also, you can
625 allow all users by specifying `*`. The
626 default is `*`. Note that trusted users are
627 always allowed to connect.
628 '';
629 };
630 };
631 };
632 default = { };
633 example = literalExpression ''
634 {
635 use-sandbox = true;
636 show-trace = true;
637
638 system-features = [ "big-parallel" "kvm" "recursive-nix" ];
639 sandbox-paths = { "/bin/sh" = "''${pkgs.busybox-sandbox-shell.out}/bin/busybox"; };
640 }
641 '';
642 description = lib.mdDoc ''
643 Configuration for Nix, see
644 <https://nixos.org/manual/nix/stable/#sec-conf-file> or
645 {manpage}`nix.conf(5)` for available options.
646 The value declared here will be translated directly to the key-value pairs Nix expects.
647
648 You can use {command}`nix-instantiate --eval --strict '<nixpkgs/nixos>' -A config.nix.settings`
649 to view the current value. By default it is empty.
650
651 Nix configurations defined under {option}`nix.*` will be translated and applied to this
652 option. In addition, configuration specified in {option}`nix.extraOptions` which will be appended
653 verbatim to the resulting config file.
654 '';
655 };
656 };
657 };
658
659
660 ###### implementation
661
662 config = mkIf cfg.enable {
663 environment.systemPackages =
664 [
665 nixPackage
666 pkgs.nix-info
667 ]
668 ++ optional (config.programs.bash.enableCompletion) pkgs.nix-bash-completions;
669
670 environment.etc."nix/nix.conf".source = nixConf;
671
672 environment.etc."nix/registry.json".text = builtins.toJSON {
673 version = 2;
674 flakes = mapAttrsToList (n: v: { inherit (v) from to exact; }) cfg.registry;
675 };
676
677 # List of machines for distributed Nix builds in the format
678 # expected by build-remote.pl.
679 environment.etc."nix/machines" = mkIf (cfg.buildMachines != [ ]) {
680 text =
681 concatMapStrings
682 (machine:
683 (concatStringsSep " " ([
684 "${optionalString (machine.protocol != null) "${machine.protocol}://"}${optionalString (machine.sshUser != null) "${machine.sshUser}@"}${machine.hostName}"
685 (if machine.system != null then machine.system else if machine.systems != [ ] then concatStringsSep "," machine.systems else "-")
686 (if machine.sshKey != null then machine.sshKey else "-")
687 (toString machine.maxJobs)
688 (toString machine.speedFactor)
689 (let res = (machine.supportedFeatures ++ machine.mandatoryFeatures);
690 in if (res == []) then "-" else (concatStringsSep "," res))
691 (let res = machine.mandatoryFeatures;
692 in if (res == []) then "-" else (concatStringsSep "," machine.mandatoryFeatures))
693 ]
694 ++ optional (isNixAtLeast "2.4pre") (if machine.publicHostKey != null then machine.publicHostKey else "-")))
695 + "\n"
696 )
697 cfg.buildMachines;
698 };
699
700 assertions =
701 let badMachine = m: m.system == null && m.systems == [ ];
702 in
703 [
704 {
705 assertion = !(any badMachine cfg.buildMachines);
706 message = ''
707 At least one system type (via <varname>system</varname> or
708 <varname>systems</varname>) must be set for every build machine.
709 Invalid machine specifications:
710 '' + " " +
711 (concatStringsSep "\n "
712 (map (m: m.hostName)
713 (filter (badMachine) cfg.buildMachines)));
714 }
715 ];
716
717 systemd.packages = [ nixPackage ];
718
719 # Will only work once https://github.com/NixOS/nix/pull/6285 is merged
720 # systemd.tmpfiles.packages = [ nixPackage ];
721
722 # Can be dropped for Nix > https://github.com/NixOS/nix/pull/6285
723 systemd.tmpfiles.rules = [
724 "d /nix/var/nix/daemon-socket 0755 root root - -"
725 ];
726
727 systemd.sockets.nix-daemon.wantedBy = [ "sockets.target" ];
728
729 systemd.services.nix-daemon =
730 {
731 path = [ nixPackage pkgs.util-linux config.programs.ssh.package ]
732 ++ optionals cfg.distributedBuilds [ pkgs.gzip ];
733
734 environment = cfg.envVars
735 // { CURL_CA_BUNDLE = "/etc/ssl/certs/ca-certificates.crt"; }
736 // config.networking.proxy.envVars;
737
738 unitConfig.RequiresMountsFor = "/nix/store";
739
740 serviceConfig =
741 {
742 CPUSchedulingPolicy = cfg.daemonCPUSchedPolicy;
743 IOSchedulingClass = cfg.daemonIOSchedClass;
744 IOSchedulingPriority = cfg.daemonIOSchedPriority;
745 LimitNOFILE = 1048576;
746 };
747
748 restartTriggers = [ nixConf ];
749
750 # `stopIfChanged = false` changes to switch behavior
751 # from stop -> update units -> start
752 # to update units -> restart
753 #
754 # The `stopIfChanged` setting therefore controls a trade-off between a
755 # more predictable lifecycle, which runs the correct "version" of
756 # the `ExecStop` line, and on the other hand the availability of
757 # sockets during the switch, as the effectiveness of the stop operation
758 # depends on the socket being stopped as well.
759 #
760 # As `nix-daemon.service` does not make use of `ExecStop`, we prefer
761 # to keep the socket up and available. This is important for machines
762 # that run Nix-based services, such as automated build, test, and deploy
763 # services, that expect the daemon socket to be available at all times.
764 #
765 # Notably, the Nix client does not retry on failure to connect to the
766 # daemon socket, and the in-process RemoteStore instance will disable
767 # itself. This makes retries infeasible even for services that are
768 # aware of the issue. Failure to connect can affect not only new client
769 # processes, but also new RemoteStore instances in existing processes,
770 # as well as existing RemoteStore instances that have not saturated
771 # their connection pool.
772 #
773 # Also note that `stopIfChanged = true` does not kill existing
774 # connection handling daemons, as one might wish to happen before a
775 # breaking Nix upgrade (which is rare). The daemon forks that handle
776 # the individual connections split off into their own sessions, causing
777 # them not to be stopped by systemd.
778 # If a Nix upgrade does require all existing daemon processes to stop,
779 # nix-daemon must do so on its own accord, and only when the new version
780 # starts and detects that Nix's persistent state needs an upgrade.
781 stopIfChanged = false;
782
783 };
784
785 # Set up the environment variables for running Nix.
786 environment.sessionVariables = cfg.envVars // { NIX_PATH = cfg.nixPath; };
787
788 environment.extraInit =
789 ''
790 if [ -e "$HOME/.nix-defexpr/channels" ]; then
791 export NIX_PATH="$HOME/.nix-defexpr/channels''${NIX_PATH:+:$NIX_PATH}"
792 fi
793 '';
794
795 nix.nrBuildUsers = mkDefault (
796 if cfg.settings.auto-allocate-uids or false then 0
797 else max 32 (if cfg.settings.max-jobs == "auto" then 0 else cfg.settings.max-jobs)
798 );
799
800 users.users = nixbldUsers;
801
802 services.xserver.displayManager.hiddenUsers = attrNames nixbldUsers;
803
804 system.activationScripts.nix = stringAfter [ "etc" "users" ]
805 ''
806 install -m 0755 -d /nix/var/nix/{gcroots,profiles}/per-user
807
808 # Subscribe the root user to the NixOS channel by default.
809 if [ ! -e "/root/.nix-channels" ]; then
810 echo "${config.system.defaultChannel} nixos" > "/root/.nix-channels"
811 fi
812 '';
813
814 # Legacy configuration conversion.
815 nix.settings = mkMerge [
816 {
817 trusted-public-keys = [ "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=" ];
818 substituters = mkAfter [ "https://cache.nixos.org/" ];
819
820 system-features = mkDefault (
821 [ "nixos-test" "benchmark" "big-parallel" "kvm" ] ++
822 optionals (pkgs.stdenv.hostPlatform ? gcc.arch) (
823 # a builder can run code for `gcc.arch` and inferior architectures
824 [ "gccarch-${pkgs.stdenv.hostPlatform.gcc.arch}" ] ++
825 map (x: "gccarch-${x}") (systems.architectures.inferiors.${pkgs.stdenv.hostPlatform.gcc.arch} or [])
826 )
827 );
828 }
829
830 (mkIf (!cfg.distributedBuilds) { builders = null; })
831
832 (mkIf (isNixAtLeast "2.3pre") { sandbox-fallback = false; })
833 ];
834
835 };
836
837}