This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

superconfig / machines / atlas / physical.nix
7.9 kB 196 lines
1{ 2 modulesPath, 3 pkgs, 4 lib, 5 ... 6}: 7{ 8 imports = [ 9 ./config.nix 10 (modulesPath + "/installer/scan/not-detected.nix") 11 # Two boot media from one config. Every entry in image.modules is applied 12 # to this config through its own extendModules, so the iso and netboot 13 # variants never see each other's fileSystems / bootloader definitions — 14 # no disabledModules or mkForce juggling needed. 15 # 16 # nixos-rebuild build-image --flake .#atlas --image-variant iso 17 # nix build .#nixosConfigurations.atlas.config.system.build.images.iso 18 # nix build .#atlas-netboot-root (kernel+initrd+ipxe for PXE) 19 (modulesPath + "/image/images.nix") 20 ]; 21 22 # Deliberately no image module at the toplevel: nixpkgs warns that doing so 23 # defines system.build.image and leaks the medium into every variant. That 24 # leaves the base config without a real boot medium, so these two 25 # placeholders exist only to let it evaluate; both image variants override 26 # the root with mkImageMediaOverride (priority 60), which wins over these. 27 # The base toplevel itself is never booted or deployed. 28 fileSystems."/" = { 29 device = "tmpfs"; 30 fsType = "tmpfs"; 31 }; 32 boot.loader.grub.enable = lib.mkDefault false; 33 34 # Live USB stick: store is a squashfs on the stick, root a tmpfs overlay on 35 # top. Stateless, nothing installed — dd it and boot. 36 # 37 # The built-in `iso` variant is iso-image.nix (not installation-cd-base): 38 # no nixos channel, no installer profile, no `nixos` autologin to fight 39 # greetd or clash with 2configs/pinned-registry.nix. Settings here merge 40 # into it, since image.modules is an attrsOf deferredModule. 41 image.modules.iso = { 42 # zstd keeps the squashfs small without a slow xz build. 43 isoImage.squashfsCompression = "zstd -Xcompression-level 6"; 44 isoImage.makeEfiBootable = true; 45 isoImage.makeUsbBootable = true; 46 image.baseName = lib.mkForce "atlas"; 47 image.fileName = lib.mkForce "atlas.iso"; 48 }; 49 50 # PXE/netboot: iPXE pulls only bzImage + a ~11 MB initrd, so nothing has to 51 # be flashed to iterate. 52 # 53 # The store is NOT embedded in the initrd the way upstream netboot.nix does 54 # it. iPXE has to hold whatever it downloads in EfiBootServicesData, and 55 # firmware caps that well below installed RAM — a 2.8 GB initrd died with 56 # "No space left on device" (ipxe.org/34182006) on a 16 GB machine. So stage 57 # 1 brings up the network itself and fetches the squashfs, which lands in 58 # kernel-managed memory where the whole 16 GB is actually usable. 59 # 60 # The file is fetched to exactly the path netboot.nix already mounts from 61 # ("../nix-store.squashfs", i.e. /nix-store.squashfs in the initrd root), so 62 # the mount itself is upstream's, unmodified. It survives switch_root 63 # because the loop device keeps the inode open after the old root is wiped. 64 image.modules.netboot = 65 { config, lib, ... }: 66 { 67 imports = [ (modulesPath + "/installer/netboot/netboot.nix") ]; 68 netboot.squashfsCompression = "zstd -Xcompression-level 6"; 69 70 # Ship the initrd without the store; pxe-serve serves squashfsStore 71 # separately over HTTP. 72 system.build.netbootRamdisk = lib.mkForce config.system.build.initialRamdisk; 73 74 # DHCP in stage 1 (runs in preLVMCommands, before postDeviceCommands). 75 boot.initrd.network.enable = true; 76 boot.initrd.network.udhcpc.enable = true; 77 78 # hardware.enableAllHardware is storage-only — virtio_net is the single 79 # network driver in its 89 modules — so wired NICs have to be listed by 80 # hand. availableKernelModules only makes them available; udev loads just 81 # the ones matching present PCI/USB IDs, so unused entries cost bytes. 82 boot.initrd.availableKernelModules = [ 83 "e1000e" 84 "e1000" 85 "igb" 86 "igc" 87 "ixgbe" 88 "r8169" 89 "alx" 90 "atl1c" 91 "tg3" 92 "bnx2" 93 "bnx2x" 94 "sky2" 95 "forcedeth" 96 "atlantic" 97 # USB NICs (docks, adapters) 98 "r8152" 99 "cdc_ether" 100 "cdc_ncm" 101 "asix" 102 "ax88179_178a" 103 "virtio_net" 104 ]; 105 106 # wget is busybox's, already present in the scripted initrd's 107 # extra-utils. The URL comes from the kernel command line rather than 108 # being baked in, so the image doesn't go stale when the serving address 109 # changes (pxe-serve passes store.url=). 110 boot.initrd.postDeviceCommands = '' 111 store_url= 112 for o in $(cat /proc/cmdline); do 113 case $o in 114 store.url=*) store_url=''${o#store.url=} ;; 115 esac 116 done 117 if [ -z "$store_url" ]; then 118 echo "netboot: no store.url= on the kernel command line" 119 fail 120 fi 121 echo "netboot: fetching nix store from $store_url" 122 if ! wget -O /nix-store.squashfs "$store_url"; then 123 echo "netboot: failed to fetch $store_url" 124 fail 125 fi 126 ''; 127 }; 128 129 nixpkgs.hostPlatform = "x86_64-linux"; 130 131 boot.kernelPackages = pkgs.linuxPackages_latest; 132 133 # AMD Radeon (Navi 14 / RX 5500-class, PCI 1002:7340) -> amdgpu. 134 # 135 # amdgpu is deliberately NOT in boot.initrd.kernelModules: early-loading it 136 # tears down efifb before the GPU firmware is available in stage-1, which 137 # black-screens this card from the moment the kernel starts (measured: ~5min 138 # to reach systemd). Let udev load amdgpu in stage-2, where the firmware is 139 # present. hardware.amdgpu.initrd.enable is the same trap — it only adds the 140 # module and handles no firmware. 141 hardware.graphics.enable = true; 142 hardware.enableRedistributableFirmware = true; 143 144 # No 32-bit graphics stack: it drags in a second mesa plus a second LLVM 145 # (~840 MB uncompressed) and is only needed for Steam/Wine, which this 146 # stateless box doesn't run. Both image variants pay for it otherwise, and 147 # the netboot initrd has to fit under iPXE's sub-4GB allocation limit. 148 hardware.graphics.enable32Bit = false; 149 150 # nixpkgs' graphical-desktop.nix turns on speech-dispatcher for any 151 # graphical session, which pulls espeak and 676 MB of mbrola TTS voices. 152 # Nothing here speaks. 153 services.speechd.enable = lib.mkForce false; 154 services.xserver.videoDrivers = [ "amdgpu" ]; 155 boot.kernelModules = [ "kvm-intel" ]; 156 157 # Boot the live image off a USB mass-storage device. (Inert for netboot, 158 # where iPXE has already fetched kernel+initrd before the kernel starts.) 159 boot.initrd.availableKernelModules = [ 160 "xhci_pci" 161 "ehci_pci" 162 "ahci" 163 "usb_storage" 164 "uas" 165 "usbhid" 166 "sd_mod" 167 ]; 168 169 # Initrd size dominates boot for both media: GRUB reads it off USB at 170 # roughly 1 MB/s (measured: 59s loader phase vs 6.5s kernel + 4.5s initrd + 171 # 10s userspace), and for netboot it travels with the store image. 172 # 173 # It was 29 MB compressed / 83 MB unpacked, of which only 1.8 MB was kernel 174 # modules — the rest was the systemd-initrd closure (openssl, lvm2, 175 # cryptsetup, tpm2-tss, curl, krb5, bash-interactive). Stage 1 only has to 176 # find the boot medium and mount squashfs+overlay: no LUKS, no LVM, no TPM, 177 # no network. The scripted initrd drops that closure: 29 MB -> 11 MB. 178 boot.initrd.systemd.enable = lib.mkForce false; 179 boot.initrd.systemd.emergencyAccess = lib.mkForce false; 180 boot.initrd.services.lvm.enable = lib.mkForce false; 181 182 # Name the onboard Intel NIC deterministically. 183 services.udev.extraRules = '' 184 SUBSYSTEM=="net", ATTR{address}=="70:85:c2:0e:ea:3c", NAME="et0" 185 ''; 186 187 # Stateless box: no clan secrets are deployed, so don't try to load an 188 # openssh host key from a vars path that will never exist on the live 189 # system. Let sshd generate an ephemeral key at boot instead. 190 services.openssh.hostKeys = lib.mkForce [ 191 { 192 path = "/etc/ssh/ssh_host_ed25519_key"; 193 type = "ed25519"; 194 } 195 ]; 196}