{ disko, myvars, ... }: ############################################################# # # Aquamarine - headless AI inference server. Hardware, install and runbook: # ./README.md. # ############################################################# let hostName = "aquamarine"; # Define your hostname. inherit (myvars.networking) proxyGateway proxyGateway6 nameservers; inherit (myvars.networking.hostsAddr.${hostName}) ipv4; ipv4WithMask = "${ipv4}/24"; in { imports = [ disko.nixosModules.default ../../modules/nixos/power.nix # disks ./disko-fs.nix # hardware ./hardware-configuration.nix ./hardware-intel-cpu.nix ./hardware-amd-gpu.nix ./hardware-intel-igpu.nix ./preservation.nix ./secureboot.nix # services ./asr ./idle-suspend.nix ]; # Bind the board's NCT6798D SuperIO, otherwise fan RPM and board temperatures # are missing. boot.kernelModules = [ "nct6775" ]; # Zram consumes physical memory for compression, which deadlocks when the # model being loaded approaches the physical memory limit — exactly the # workload this host exists for. Use the disk swapfile that disko creates at # /swap instead, and keep zswap as a compressed cache in front of it so cold # anonymous pages stay in RAM rather than hitting the SSD. modules.zram.enable = false; boot.zswap = { enable = true; compressor = "zstd"; # 10% of 96G; the module default 25% would compete with the page cache that # holds the model weights being read in. maxPoolPercent = 10; }; # Local btrfs snapshots of @persistent (SSH host keys, /etc/secureboot, the # NixOS state). Same layout as the other physical hosts; no off-host target. modules.btrbk.enable = true; modules.security.audit.enable = true; # smartd autodetects devices and logs to the journal; the smartctl exporter # (modules/nixos/base/monitoring.nix) is what feeds wear and media errors to # VictoriaMetrics. services.smartd.enable = true; # The inference engine ships as an OCI image and runs under the agent # profile's rootless Podman (modules/nixos/agent.nix), built from the `~/src` # checkout that ./preservation.nix keeps. # The daemons of the hosts that build here (modules/nixos/base/remote-builders.nix). # Their host keys have no passphrase, so they only get the daemon protocol, as # nix.sshServe does. `--store daemon` hands builds to the system daemon instead # of running them inside this audited login session (modules/nixos/base/auditd.nix). users.users.root.openssh.authorizedKeys.keys = map ( key: ''restrict,command="nix-daemon --stdio --store daemon" ${key}'' ) myvars.remoteBuilderClientKeys; # systemd-journal - cap disk usage # https://www.freedesktop.org/software/systemd/man/latest/journald.conf.html services.journald.settings.Journal = { SystemMaxUse = "10G"; RuntimeMaxUse = "256M"; }; networking = { inherit hostName; # off: this host uses networkd (below). networkmanager.enable = false; useDHCP = false; }; # A `boot.kernel.sysctl` that disabled IPv6 was removed on 2026-10-14: networkd # re-enables it on the wired link for the `DHCP = "ipv6"`/`IPv6AcceptRA` settings # below, so it never applied. The gateway now hands out fake-IP AAAA records too. networking.useNetworkd = true; systemd.network.enable = true; # Rootless Podman's user units wait for the system network-online.target before # starting containers. Nothing else starts that target on this networkd host # since the LAN exporters moved to FreeBind sockets, so the user wait unit timed # out after 90s and held llama-swap and magpie back on every boot. systemd.targets.network-online.wantedBy = [ "multi-user.target" ]; # Predictable names follow the PCIe topology, so match the `en*` prefix instead of # a name; one wired port, so one link. # `Name=` is not a valid [Match] key in systemd.link; systemd 262 ignores # the whole file with "Unknown key 'Name'". Match the kernel name instead. systemd.network.links."40-wake-on-lan" = { matchConfig.OriginalName = "en*"; linkConfig.WakeOnLan = "magic"; }; systemd.network.networks."10-lan" = { matchConfig.Name = [ "en*" ]; networkConfig = { Address = [ ipv4WithMask ]; # DNS goes to the proxy gateway, which resolves through the proxy; # `nameservers` is the plain upstream-DNS alternative. # DNS = nameservers; DNS = [ proxyGateway ]; DHCP = "ipv6"; # enable DHCPv6 only, so we can get a GUA. IPv6AcceptRA = true; # for Stateless IPv6 Autoconfiguration (SLAAC) LinkLocalAddressing = "ipv6"; # The RTL8125BG flaps carrier on link re-training; without this networkd # tears the static address and route down and the host drops off the LAN. IgnoreCarrierLoss = "10s"; }; routes = [ { Destination = "0.0.0.0/0"; Gateway = proxyGateway; } { Destination = "::/0"; Gateway = proxyGateway6; GatewayOnLink = true; # it's a gateway on local link. } ]; linkConfig.RequiredForOnline = "routable"; }; # This value determines the NixOS release from which the default # settings for stateful data (file locations, database versions) are taken. # It is the release this host was installed on. system.stateVersion = "26.11"; }