1/*
2 Manages /etc/nix/nix.conf.
3
4 See also
5 - ./nix-channel.nix
6 - ./nix-flakes.nix
7 - ./nix-remote-build.nix
8 - nixos/modules/services/system/nix-daemon.nix
9 */
10{ config, lib, pkgs, ... }:
11
12let
13 inherit (lib)
14 concatStringsSep
15 boolToString
16 escape
17 filterAttrs
18 floatToString
19 getVersion
20 hasPrefix
21 isBool
22 isDerivation
23 isFloat
24 isInt
25 isList
26 isString
27 literalExpression
28 mapAttrsToList
29 mkAfter
30 mkDefault
31 mkIf
32 mkOption
33 mkRenamedOptionModuleWith
34 optionalString
35 optionals
36 strings
37 systems
38 toPretty
39 types
40 versionAtLeast
41 ;
42
43 cfg = config.nix;
44
45 nixPackage = cfg.package.out;
46
47 isNixAtLeast = versionAtLeast (getVersion nixPackage);
48
49 legacyConfMappings = {
50 useSandbox = "sandbox";
51 buildCores = "cores";
52 maxJobs = "max-jobs";
53 sandboxPaths = "extra-sandbox-paths";
54 binaryCaches = "substituters";
55 trustedBinaryCaches = "trusted-substituters";
56 binaryCachePublicKeys = "trusted-public-keys";
57 autoOptimiseStore = "auto-optimise-store";
58 requireSignedBinaryCaches = "require-sigs";
59 trustedUsers = "trusted-users";
60 allowedUsers = "allowed-users";
61 systemFeatures = "system-features";
62 };
63
64 semanticConfType = with types;
65 let
66 confAtom = nullOr
67 (oneOf [
68 bool
69 int
70 float
71 str
72 path
73 package
74 ]) // {
75 description = "Nix config atom (null, bool, int, float, str, path or package)";
76 };
77 in
78 attrsOf (either confAtom (listOf confAtom));
79
80 nixConf =
81 assert isNixAtLeast "2.2";
82 let
83
84 mkValueString = v:
85 if v == null then ""
86 else if isInt v then toString v
87 else if isBool v then boolToString v
88 else if isFloat v then floatToString v
89 else if isList v then toString v
90 else if isDerivation v then toString v
91 else if builtins.isPath v then toString v
92 else if isString v then v
93 else if strings.isConvertibleWithToString v then toString v
94 else abort "The nix conf value: ${toPretty {} v} can not be encoded";
95
96 mkKeyValue = k: v: "${escape [ "=" ] k} = ${mkValueString v}";
97
98 mkKeyValuePairs = attrs: concatStringsSep "\n" (mapAttrsToList mkKeyValue attrs);
99
100 isExtra = key: hasPrefix "extra-" key;
101
102 in
103 pkgs.writeTextFile {
104 name = "nix.conf";
105 # workaround for https://github.com/NixOS/nix/issues/9487
106 # extra-* settings must come after their non-extra counterpart
107 text = ''
108 # WARNING: this file is generated from the nix.* options in
109 # your NixOS configuration, typically
110 # /etc/nixos/configuration.nix. Do not edit it!
111 ${mkKeyValuePairs (filterAttrs (key: value: !(isExtra key)) cfg.settings)}
112 ${mkKeyValuePairs (filterAttrs (key: value: isExtra key) cfg.settings)}
113 ${cfg.extraOptions}
114 '';
115 checkPhase = lib.optionalString cfg.checkConfig (
116 if pkgs.stdenv.hostPlatform != pkgs.stdenv.buildPlatform then ''
117 echo "Ignoring validation for cross-compilation"
118 ''
119 else
120 let
121 showCommand = if isNixAtLeast "2.20pre" then "config show" else "show-config";
122 in
123 ''
124 echo "Validating generated nix.conf"
125 ln -s $out ./nix.conf
126 set -e
127 set +o pipefail
128 NIX_CONF_DIR=$PWD \
129 ${cfg.package}/bin/nix ${showCommand} ${optionalString (isNixAtLeast "2.3pre") "--no-net"} \
130 ${optionalString (isNixAtLeast "2.4pre") "--option experimental-features nix-command"} \
131 |& sed -e 's/^warning:/error:/' \
132 | (! grep '${if cfg.checkAllErrors then "^error:" else "^error: unknown setting"}')
133 set -o pipefail
134 '');
135 };
136
137in
138{
139 imports = [
140 (mkRenamedOptionModuleWith { sinceRelease = 2003; from = [ "nix" "useChroot" ]; to = [ "nix" "useSandbox" ]; })
141 (mkRenamedOptionModuleWith { sinceRelease = 2003; from = [ "nix" "chrootDirs" ]; to = [ "nix" "sandboxPaths" ]; })
142 ] ++
143 mapAttrsToList
144 (oldConf: newConf:
145 mkRenamedOptionModuleWith {
146 sinceRelease = 2205;
147 from = [ "nix" oldConf ];
148 to = [ "nix" "settings" newConf ];
149 })
150 legacyConfMappings;
151
152 options = {
153 nix = {
154 checkConfig = mkOption {
155 type = types.bool;
156 default = true;
157 description = ''
158 If enabled, checks that Nix can parse the generated nix.conf.
159 '';
160 };
161
162 checkAllErrors = mkOption {
163 type = types.bool;
164 default = true;
165 description = ''
166 If enabled, checks the nix.conf parsing for any kind of error. When disabled, checks only for unknown settings.
167 '';
168 };
169
170 extraOptions = mkOption {
171 type = types.lines;
172 default = "";
173 example = ''
174 keep-outputs = true
175 keep-derivations = true
176 '';
177 description = "Additional text appended to {file}`nix.conf`.";
178 };
179
180 settings = mkOption {
181 type = types.submodule {
182 freeformType = semanticConfType;
183
184 options = {
185 max-jobs = mkOption {
186 type = types.either types.int (types.enum [ "auto" ]);
187 default = "auto";
188 example = 64;
189 description = ''
190 This option defines the maximum number of jobs that Nix will try to
191 build in parallel. The default is auto, which means it will use all
192 available logical cores. It is recommend to set it to the total
193 number of logical cores in your system (e.g., 16 for two CPUs with 4
194 cores each and hyper-threading).
195 '';
196 };
197
198 auto-optimise-store = mkOption {
199 type = types.bool;
200 default = false;
201 example = true;
202 description = ''
203 If set to true, Nix automatically detects files in the store that have
204 identical contents, and replaces them with hard links to a single copy.
205 This saves disk space. If set to false (the default), you can still run
206 nix-store --optimise to get rid of duplicate files.
207 '';
208 };
209
210 cores = mkOption {
211 type = types.int;
212 default = 0;
213 example = 64;
214 description = ''
215 This option defines the maximum number of concurrent tasks during
216 one build. It affects, e.g., -j option for make.
217 The special value 0 means that the builder should use all
218 available CPU cores in the system. Some builds may become
219 non-deterministic with this option; use with care! Packages will
220 only be affected if enableParallelBuilding is set for them.
221 '';
222 };
223
224 sandbox = mkOption {
225 type = types.either types.bool (types.enum [ "relaxed" ]);
226 default = true;
227 description = ''
228 If set, Nix will perform builds in a sandboxed environment that it
229 will set up automatically for each build. This prevents impurities
230 in builds by disallowing access to dependencies outside of the Nix
231 store by using network and mount namespaces in a chroot environment.
232
233 This is enabled by default even though it has a possible performance
234 impact due to the initial setup time of a sandbox for each build. It
235 doesn't affect derivation hashes, so changing this option will not
236 trigger a rebuild of packages.
237
238 When set to "relaxed", this option permits derivations that set
239 `__noChroot = true;` to run outside of the sandboxed environment.
240 Exercise caution when using this mode of operation! It is intended to
241 be a quick hack when building with packages that are not easily setup
242 to be built reproducibly.
243 '';
244 };
245
246 extra-sandbox-paths = mkOption {
247 type = types.listOf types.str;
248 default = [ ];
249 example = [ "/dev" "/proc" ];
250 description = ''
251 Directories from the host filesystem to be included
252 in the sandbox.
253 '';
254 };
255
256 substituters = mkOption {
257 type = types.listOf types.str;
258 description = ''
259 List of binary cache URLs used to obtain pre-built binaries
260 of Nix packages.
261
262 By default https://cache.nixos.org/ is added.
263 '';
264 };
265
266 trusted-substituters = mkOption {
267 type = types.listOf types.str;
268 default = [ ];
269 example = [ "https://hydra.nixos.org/" ];
270 description = ''
271 List of binary cache URLs that non-root users can use (in
272 addition to those specified using
273 {option}`nix.settings.substituters`) by passing
274 `--option binary-caches` to Nix commands.
275 '';
276 };
277
278 require-sigs = mkOption {
279 type = types.bool;
280 default = true;
281 description = ''
282 If enabled (the default), Nix will only download binaries from binary caches if
283 they are cryptographically signed with any of the keys listed in
284 {option}`nix.settings.trusted-public-keys`. If disabled, signatures are neither
285 required nor checked, so it's strongly recommended that you use only
286 trustworthy caches and https to prevent man-in-the-middle attacks.
287 '';
288 };
289
290 trusted-public-keys = mkOption {
291 type = types.listOf types.str;
292 example = [ "hydra.nixos.org-1:CNHJZBh9K4tP3EKF6FkkgeVYsS3ohTl+oS0Qa8bezVs=" ];
293 description = ''
294 List of public keys used to sign binary caches. If
295 {option}`nix.settings.trusted-public-keys` is enabled,
296 then Nix will use a binary from a binary cache if and only
297 if it is signed by *any* of the keys
298 listed here. By default, only the key for
299 `cache.nixos.org` is included.
300 '';
301 };
302
303 trusted-users = mkOption {
304 type = types.listOf types.str;
305 default = [ "root" ];
306 example = [ "root" "alice" "@wheel" ];
307 description = ''
308 A list of names of users that have additional rights when
309 connecting to the Nix daemon, such as the ability to specify
310 additional binary caches, or to import unsigned NARs. You
311 can also specify groups by prefixing them with
312 `@`; for instance,
313 `@wheel` means all users in the wheel
314 group.
315 '';
316 };
317
318 system-features = mkOption {
319 type = types.listOf types.str;
320 example = [ "kvm" "big-parallel" "gccarch-skylake" ];
321 description = ''
322 The set of features supported by the machine. Derivations
323 can express dependencies on system features through the
324 `requiredSystemFeatures` attribute.
325
326 By default, pseudo-features `nixos-test`, `benchmark`,
327 and `big-parallel` used in Nixpkgs are set, `kvm`
328 is also included if it is available.
329 '';
330 };
331
332 allowed-users = mkOption {
333 type = types.listOf types.str;
334 default = [ "*" ];
335 example = [ "@wheel" "@builders" "alice" "bob" ];
336 description = ''
337 A list of names of users (separated by whitespace) that are
338 allowed to connect to the Nix daemon. As with
339 {option}`nix.settings.trusted-users`, you can specify groups by
340 prefixing them with `@`. Also, you can
341 allow all users by specifying `*`. The
342 default is `*`. Note that trusted users are
343 always allowed to connect.
344 '';
345 };
346 };
347 };
348 default = { };
349 example = literalExpression ''
350 {
351 use-sandbox = true;
352 show-trace = true;
353
354 system-features = [ "big-parallel" "kvm" "recursive-nix" ];
355 sandbox-paths = [ "/bin/sh=''${pkgs.busybox-sandbox-shell.out}/bin/busybox" ];
356 }
357 '';
358 description = ''
359 Configuration for Nix, see
360 <https://nixos.org/manual/nix/stable/command-ref/conf-file.html> or
361 {manpage}`nix.conf(5)` for available options.
362 The value declared here will be translated directly to the key-value pairs Nix expects.
363
364 You can use {command}`nix-instantiate --eval --strict '<nixpkgs/nixos>' -A config.nix.settings`
365 to view the current value. By default it is empty.
366
367 Nix configurations defined under {option}`nix.*` will be translated and applied to this
368 option. In addition, configuration specified in {option}`nix.extraOptions` will be appended
369 verbatim to the resulting config file.
370 '';
371 };
372 };
373 };
374
375 config = mkIf cfg.enable {
376 environment.etc."nix/nix.conf".source = nixConf;
377 nix.settings = {
378 trusted-public-keys = [ "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=" ];
379 substituters = mkAfter [ "https://cache.nixos.org/" ];
380 system-features = mkDefault (
381 [ "nixos-test" "benchmark" "big-parallel" "kvm" ] ++
382 optionals (pkgs.stdenv.hostPlatform ? gcc.arch) (
383 # a builder can run code for `gcc.arch` and inferior architectures
384 [ "gccarch-${pkgs.stdenv.hostPlatform.gcc.arch}" ] ++
385 map (x: "gccarch-${x}") (systems.architectures.inferiors.${pkgs.stdenv.hostPlatform.gcc.arch} or [])
386 )
387 );
388 };
389 };
390}