···1-# darwin.builder {#sec-darwin-builder}
23-`darwin.builder` provides a way to bootstrap a Linux builder on a macOS machine.
45This requires macOS version 12.4 or later.
67-This also requires that port 22 on your machine is free (since Nix does not
8-permit specifying a non-default SSH port for builders).
0910You will also need to be a trusted user for your Nix installation. In other
11words, your `/etc/nix/nix.conf` should have something like:
···17To launch the builder, run the following flake:
1819```ShellSession
20-$ nix run nixpkgs#darwin.builder
21```
2223That will prompt you to enter your `sudo` password:
···50```
51# - Replace ${ARCH} with either aarch64 or x86_64 to match your host machine
52# - Replace ${MAX_JOBS} with the maximum number of builds (pick 4 if you're not sure)
53-builders = ssh-ng://builder@localhost ${ARCH}-linux /etc/nix/builder_ed25519 ${MAX_JOBS} - - - c3NoLWVkMjU1MTkgQUFBQUMzTnphQzFsWkRJMU5URTVBQUFBSUpCV2N4Yi9CbGFxdDFhdU90RStGOFFVV3JVb3RpQzVxQkorVXVFV2RWQ2Igcm9vdEBuaXhvcwo=
5455# Not strictly necessary, but this will reduce your disk utilization
56builders-use-substitutes = true
00000000057```
5859… and then restart your Nix daemon to apply the change:
···1+# darwin.linux-builder {#sec-darwin-builder}
23+`darwin.linux-builder` provides a way to bootstrap a Linux builder on a macOS machine.
45This requires macOS version 12.4 or later.
67+The builder runs on host port 31022 by default.
8+You can change it by overriding `virtualisation.darwin-builder.hostPort`.
9+See the [example](#sec-darwin-builder-example-flake).
1011You will also need to be a trusted user for your Nix installation. In other
12words, your `/etc/nix/nix.conf` should have something like:
···18To launch the builder, run the following flake:
1920```ShellSession
21+$ nix run nixpkgs#darwin.linux-builder
22```
2324That will prompt you to enter your `sudo` password:
···51```
52# - Replace ${ARCH} with either aarch64 or x86_64 to match your host machine
53# - Replace ${MAX_JOBS} with the maximum number of builds (pick 4 if you're not sure)
54+builders = ssh-ng://builder@linux-builder ${ARCH}-linux /etc/nix/builder_ed25519 ${MAX_JOBS} - - - c3NoLWVkMjU1MTkgQUFBQUMzTnphQzFsWkRJMU5URTVBQUFBSUpCV2N4Yi9CbGFxdDFhdU90RStGOFFVV3JVb3RpQzVxQkorVXVFV2RWQ2Igcm9vdEBuaXhvcwo=
5556# Not strictly necessary, but this will reduce your disk utilization
57builders-use-substitutes = true
58+```
59+60+To allow Nix to connect to a builder not running on port 22, you will also need to create a new file at `/etc/ssh/ssh_config.d/100-linux-builder.conf`:
61+62+```
63+Host linux-builder
64+ Hostname localhost
65+ HostKeyAlias linux-builder
66+ Port 31022
67```
6869… and then restart your Nix daemon to apply the change:
+11-7
nixos/modules/profiles/macos-builder.nix
···1-{ config, lib, pkgs, ... }:
23let
4 keysDirectory = "/var/keys";
···67 '';
68 };
69 hostPort = mkOption {
70- default = 22;
71 type = types.int;
72- example = 31022;
73 description = ''
74 The localhost host port to forward TCP to the guest port.
75 '';
···139140 hostPkgs = config.virtualisation.host.pkgs;
141142- script = hostPkgs.writeShellScriptBin "create-builder" (
143 # When running as non-interactively as part of a DarwinConfiguration the working directory
144 # must be set to a writeable directory.
145 (if cfg.workingDirectory != "." then ''
146 ${hostPkgs.coreutils}/bin/mkdir --parent "${cfg.workingDirectory}"
147 cd "${cfg.workingDirectory}"
148- '' else "") + ''
149 KEYS="''${KEYS:-./keys}"
150 ${hostPkgs.coreutils}/bin/mkdir --parent "''${KEYS}"
151 PRIVATE_KEY="''${KEYS}/${user}_${keyType}"
···157 if ! ${hostPkgs.diffutils}/bin/cmp "''${PUBLIC_KEY}" ${publicKey}; then
158 (set -x; sudo --reset-timestamp ${installCredentials} "''${KEYS}")
159 fi
160- KEYS="$(${hostPkgs.nix}/bin/nix-store --add "$KEYS")" ${config.system.build.vm}/bin/run-nixos-vm
161 '');
162163 in
···177 Please inspect the trace of the following command to figure out which module
178 has a dependency on stateVersion.
179180- nix-instantiate --attr darwin.builder --show-trace
181 '');
182 };
183···234 # This ensures that anything built on the guest isn't lost when the guest is
235 # restarted.
236 writableStoreUseTmpfs = false;
0000237 };
238 };
239}
···1+{ config, lib, ... }:
23let
4 keysDirectory = "/var/keys";
···67 '';
68 };
69 hostPort = mkOption {
70+ default = 31022;
71 type = types.int;
72+ example = 22;
73 description = ''
74 The localhost host port to forward TCP to the guest port.
75 '';
···139140 hostPkgs = config.virtualisation.host.pkgs;
141142+ script = hostPkgs.writeShellScriptBin "create-builder" (
143 # When running as non-interactively as part of a DarwinConfiguration the working directory
144 # must be set to a writeable directory.
145 (if cfg.workingDirectory != "." then ''
146 ${hostPkgs.coreutils}/bin/mkdir --parent "${cfg.workingDirectory}"
147 cd "${cfg.workingDirectory}"
148+ '' else "") + ''
149 KEYS="''${KEYS:-./keys}"
150 ${hostPkgs.coreutils}/bin/mkdir --parent "''${KEYS}"
151 PRIVATE_KEY="''${KEYS}/${user}_${keyType}"
···157 if ! ${hostPkgs.diffutils}/bin/cmp "''${PUBLIC_KEY}" ${publicKey}; then
158 (set -x; sudo --reset-timestamp ${installCredentials} "''${KEYS}")
159 fi
160+ KEYS="$(${hostPkgs.nix}/bin/nix-store --add "$KEYS")" ${lib.getExe config.system.build.vm}
161 '');
162163 in
···177 Please inspect the trace of the following command to figure out which module
178 has a dependency on stateVersion.
179180+ nix-instantiate --attr darwin.linux-builder --show-trace
181 '');
182 };
183···234 # This ensures that anything built on the guest isn't lost when the guest is
235 # restarted.
236 writableStoreUseTmpfs = false;
237+238+ # Pass certificates from host to the guest otherwise when custom CA certificates
239+ # are required we can't use the cached builder.
240+ useHostCerts = true;
241 };
242 };
243}
···166 # Create a directory for exchanging data with the VM.
167 mkdir -p "$TMPDIR/xchg"
1680000000000169 ${lib.optionalString cfg.useEFIBoot
170 ''
171 # Expose EFI variables, it's useful even when we are not using a bootloader (!).
···877 '';
878 };
879880-881 virtualisation.bios =
882 mkOption {
883 type = types.nullOr types.package;
···887 An alternate BIOS (such as `qboot`) with which to start the VM.
888 Should contain a file named `bios.bin`.
889 If `null`, QEMU's builtin SeaBIOS will be used.
00000000000890 '';
891 };
892···1024 source = ''"''${SHARED_DIR:-$TMPDIR/xchg}"'';
1025 target = "/tmp/shared";
1026 };
00001027 };
0010281029 virtualisation.qemu.networkingOptions =
1030 let
···166 # Create a directory for exchanging data with the VM.
167 mkdir -p "$TMPDIR/xchg"
168169+ ${lib.optionalString cfg.useHostCerts
170+ ''
171+ mkdir -p "$TMPDIR/certs"
172+ if [ -e "$NIX_SSL_CERT_FILE" ]; then
173+ cp -L "$NIX_SSL_CERT_FILE" "$TMPDIR"/certs/ca-certificates.crt
174+ else
175+ echo \$NIX_SSL_CERT_FILE should point to a valid file if virtualisation.useHostCerts is enabled.
176+ fi
177+ ''}
178+179 ${lib.optionalString cfg.useEFIBoot
180 ''
181 # Expose EFI variables, it's useful even when we are not using a bootloader (!).
···887 '';
888 };
8890890 virtualisation.bios =
891 mkOption {
892 type = types.nullOr types.package;
···896 An alternate BIOS (such as `qboot`) with which to start the VM.
897 Should contain a file named `bios.bin`.
898 If `null`, QEMU's builtin SeaBIOS will be used.
899+ '';
900+ };
901+902+ virtualisation.useHostCerts =
903+ mkOption {
904+ type = types.bool;
905+ default = false;
906+ description =
907+ lib.mdDoc ''
908+ If enabled, when `NIX_SSL_CERT_FILE` is set on the host,
909+ pass the CA certificates from the host to the VM.
910 '';
911 };
912···1044 source = ''"''${SHARED_DIR:-$TMPDIR/xchg}"'';
1045 target = "/tmp/shared";
1046 };
1047+ certs = mkIf cfg.useHostCerts {
1048+ source = ''"$TMPDIR"/certs'';
1049+ target = "/etc/ssl/certs";
1050+ };
1051 };
1052+1053+ security.pki.installCACerts = mkIf cfg.useHostCerts false;
10541055 virtualisation.qemu.networkingOptions =
1056 let