CCE

NixOS Host Definitions

Contents

Each host heading produces a nixosSystem declaration that is shoved in to Arroyo System Flake Generator via ARROYO_OUTPUT metadata. The shared host-modules Lua block resolves role-filtered NixOS modules from the Arroyo DB.

Deploying My Laptops and Desktop

My laptops are installed through my NixOS Automatic Partitioning Installer and carry My NixOS configuration for laptops, the "endpoint configuration".

Virtuous Cassette

Virtuous Cassette is my Framework 12 Laptop. It was a Framework 13 for quite some years, but that chassis is my computer for my job now.

nix:tangle ~/nix/snippets/virtuous-cassette.nix:noweb yes
nixosConfigurations.virtuous-cassette = mkHost {
  name = "virtuous-cassette";
  roleModules = [
    <<host-modules("endpoint")>>
  ];
};
nix:tangle ~/nix/hosts/virtuous-cassette/default.nix:mkdirp yes
{ config, pkgs, lib, ... }:
{
  imports = [
    ../../nixos/framework-laptop-12.nix
  ];
  system.stateVersion = "23.11";
  sops.age.keyFile = "/home/rrix/.config/sops/age/keys.txt";

  networking.hostName = "virtuous-cassette";

  boot.loader.grub.efiSupport = true;
  boot.loader.grub.device = "nodev";
  boot.loader.efi.canTouchEfiVariables = true;
  boot.loader.grub.enable = true;
  boot.loader.systemd-boot.enable = false;

  boot.initrd.luks.devices = {
    "swap" = {
      name = "swap"; device = "/dev/nvme0n1p2"; preLVM = true;
    };
    "root" = {
      name = "root"; device = "/dev/nvme0n1p3"; preLVM = true;
    };
  };

  boot.initrd.availableKernelModules = [ "xhci_pci" "thunderbolt" "nvme" "usb_storage" "sd_mod" ];
  boot.initrd.kernelModules = [ ];
  boot.kernelModules = [ "kvm-intel" ];
  boot.extraModulePackages = [ ];

  powerManagement.cpuFreqGovernor = "powersave";
  hardware.enableRedistributableFirmware = true;

  services.udev.extraRules = ''
    KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="18d1|096e", ATTRS{idProduct}=="5026|0858|085b", TAG+="uaccess", GROUP="plugdev"
    KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0407", TAG+="uaccess", GROUP="plugdev", MODE="0660"
  '';
  services.udev.packages = with pkgs; [ platformio-core.udev ];

  programs.nix-ld.enable = true;
  programs.nix-ld.libraries = with pkgs; [
    pkgs.udev
    pkgs.SDL2
    pkgs.libpng
    pkgs.libz
  ];

  hardware.sensor.iio.enable = true;
  environment.systemPackages = [
    pkgs.maliit-framework
    pkgs.maliit-keyboard
    pkgs.wl-clipboard
  ];

  sops.secrets.tailscale_virtuous_cassette.owner = "root";
  services.tailscale.authKeyFile = config.sops.secrets.tailscale_virtuous_cassette.path;

  networking.hostId = "291fe33d"; # required for zfs use

  fileSystems."/" =
    { device = "host/root";
      fsType = "zfs";
    };

  fileSystems."/home" =
    { device = "host/home";
      fsType = "zfs";
    };

  fileSystems."/media" =
    { device = "host/landfill";
      fsType = "zfs";
    };

  fileSystems."/nix" =
    { device = "host/nix";
      fsType = "zfs";
    };

  fileSystems."/boot" =
    { device = "/dev/disk/by-uuid/CD54-B840";
      fsType = "vfat";
    };

  swapDevices =
    [ { device = "/dev/disk/by-uuid/ddfce221-2d29-4882-9c66-1669ea60bc49"; }
    ];
}

Rose Quine

Rose Quine is my GPD Pocket 3. Right now I use it to contain my microvm for langlemangling.

nix:tangle ~/nix/snippets/rose-quine.nix:noweb yes
nixosConfigurations.rose-quine = mkHost {
  name = "rose-quine";
  roleModules = [
    <<host-modules("endpoint")>>
  ];
};
nix:tangle ~/nix/hosts/rose-quine/default.nix:mkdirp yes
{ config, pkgs, lib, ... }:
{
  imports = [ ../../nixos/gpd-pocket-3.nix ];

  networking.hostName = "rose-quine";
  system.stateVersion = "23.05";

  services.xserver.dpi = 280;

  sops.secrets.tailscale_rose_quine.owner = "root";
  services.tailscale.authKeyFile = config.sops.secrets.tailscale_rose_quine.path;

  boot.loader.efi.canTouchEfiVariables = true;
  boot.loader.grub.efiSupport = true;
  boot.loader.grub.device = "nodev";
  boot.loader.grub.enable = true;
  boot.loader.grub.gfxmodeBios = "1200x1920x32";
  boot.loader.systemd-boot.enable = lib.mkForce false;

  networking.hostId = "3f5dbbf9"; # required for zfs use
  boot.zfs.devNodes = "/dev/mapper";                          # (ref:devNodes)

  boot.initrd.luks.devices = {
    "swap" = {
      name = "swap"; device = "/dev/nvme0n1p2"; preLVM = true;
    };
    "root" = {
      name = "root"; device = "/dev/nvme0n1p3"; preLVM = true;
    };
  };

  boot.initrd.availableKernelModules = [ "xhci_pci" "thunderbolt" "nvme" "usbhid" "usb_storage" "sd_mod" ];
  boot.initrd.kernelModules = [ ];
  boot.kernelModules = [ "kvm-intel" ];
  boot.extraModulePackages = [ ];

  fileSystems."/" =
    { device = "tank/root";
      fsType = "zfs";
    };

  fileSystems."/home" =
    { device = "tank/home";
      fsType = "zfs";
    };

  fileSystems."/nix" =
    { device = "tank/nix";
      fsType = "zfs";
    };

  fileSystems."/boot" =
    { device = "/dev/disk/by-uuid/9FDC-2C40";
      fsType = "vfat";
    };

  swapDevices =
    [ { device = "/dev/disk/by-uuid/455bbc40-e01c-4137-b593-a05b6220ce6b"; }
    ];

  networking.useDHCP = lib.mkDefault true;

  nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
  powerManagement.cpuFreqGovernor = lib.mkDefault "powersave";
}

NEXT derivation for umpc-display-rotate.c

NEXT split and document all this out in to an import on GPD Pocket 3 Support page

Window Smoke

: :ARROYO_SYSTEM_ROLE: endpoint : :ARROYO_AGE_RECIPIENT: age1<PLACEHOLDER_WINDOW_SMOKE> : #+ARROYO_OUTPUT: snippets/window-smoke.nix

Window Smoke is my desktop. It runs my Endpoint Configuration and some of My NixOS Tower Customizations. These days I just boot it into steam big picture mode and rdp in over Tailscale.

nix:tangle ~/nix/snippets/window-smoke.nix:noweb yes
nixosConfigurations.window-smoke = mkHost {
  name = "window-smoke";
  roleModules = [
    <<host-modules("endpoint")>>
  ];
};
nix:tangle ~/nix/hosts/window-smoke/default.nix:mkdirp yes
{ lib, config, ... }:
{
  imports = [ ./hardware-configuration.nix ../../roles/desktop ];

  boot.enableVFIO = false;

  networking.hostName = "window-smoke";
  system.stateVersion = "22.11";
  boot.loader.efi.canTouchEfiVariables = true;
  boot.loader.systemd-boot.enable = true;
  services.xserver.dpi = 110;

  boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "nvme" "usbhid" "usb_storage" "sd_mod" "sr_mod" ];
  boot.initrd.kernelModules = [ ];
  boot.kernelModules = [ "kvm-intel" "wl" ];
  boot.extraModulePackages = [ config.boot.kernelPackages.broadcom_sta ];

  sops.secrets.tailscale_window_smoke.owner = "root";
  services.tailscale.authKeyFile = config.sops.secrets.tailscale_window_smoke.path;

  networking.hostId = "141e1b4f"; # required for zfs use
  boot.zfs.devNodes = lib.mkForce "/dev/disk/by-id/";
  boot.initrd.luks.devices = {
    "swap" = { name = "swap"; device = "/dev/nvme0n1p2"; preLVM = true; };
    "root" = { name = "root"; device = "/dev/nvme0n1p3"; preLVM = true; };
  };

  fileSystems."/" =
    { device = "window-smoke/root";
      fsType = "zfs";
    };

  fileSystems."/home" =
    { device = "window-smoke/home";
      fsType = "zfs";
    };

  fileSystems."/nix" =
    { device = "window-smoke/nix";
      fsType = "zfs";
    };

  fileSystems."/boot" =
    { device = "/dev/disk/by-uuid/12CA-451F";
      fsType = "vfat";
    };

  fileSystems."/media" =
    { device = "tank/media";
      fsType = "zfs";
    };


  swapDevices =
    [ { device = "/dev/disk/by-uuid/26776a6d-4e53-4e39-b0e5-5a540ce78406"; }
    ];
}

Meadow Crush

: :ARROYO_SYSTEM_ROLE: endpoint : :ARROYO_AGE_RECIPIENT: age1<PLACEHOLDER_MEADOW_CRUSH> : #+ARROYO_OUTPUT: snippets/meadow-crush.nix

Meadow Crush is my GPD Pocket 2; I don't use this right now but it's still running a viable NixOS if I need it in a Situation.

nix:tangle ~/nix/snippets/meadow-crush.nix:noweb yes
nixosConfigurations.meadow-crush = mkHost {
  name = "meadow-crush";
  roleModules = [
    <<host-modules("endpoint")>>
  ];
};
nix:tangle ~/nix/hosts/meadow-crush/default.nix:mkdirp yes
{ config, ... }:
{
  imports = [ ./hardware-configuration.nix ../../nixos/gpd-pocket.nix ];

  networking.hostName = "meadow-crush";
  boot.loader.systemd-boot.enable = true;
  boot.loader.efi.canTouchEfiVariables = true;

  sops.secrets.tailscale_meadow_crush.owner = "root";
  services.tailscale.authKeyFile = config.sops.secrets.tailscale_meadow_crush.path;

  networking.hostId = "c9ec7cad"; # required for zfs use
  boot.initrd.luks.devices = {
    "swap" = { name = "swap"; device = "/dev/mmcblk0p2"; preLVM = true; };
    "root" = { name = "root"; device = "/dev/mmcblk0p3"; preLVM = true; };
  };

  fileSystems."/mnt/music" =
    { device = "/dev/disk/by-label/muzak";
      fsType = "ext4";
      noCheck = true;
    };
}

NEXT implement nixos encrypted secrets and make these safe!

Deploying My NixOS Set Top Box

Tres Ebow

: :ARROYO_SYSTEM_ROLE: settop : :ARROYO_AGE_RECIPIENT: age1<PLACEHOLDER_TRES_EBOW> : #+ARROYO_OUTPUT: snippets/tres-ebow.nix

Tres Ebow is my Thinkpad Yoga gen 3 -- a decent 2-in-1 with very un-Lenovo serviceability, and due to ordering error and soldered RAM, only 4 GiB of RAM. awkward. it'll be a fine kodi box.

nix:tangle ~/nix/snippets/tres-ebow.nix:noweb yes
nixosConfigurations.tres-ebow = mkHost {
  name = "tres-ebow";
  roleModules = [
    <<host-modules("settop")>>
  ];
};
nix:tangle ~/nix/hosts/tres-ebow/default.nix:mkdirp yes
{ config, lib, ... }:

{
  networking.hostName = "tres-ebow";
  boot.loader.grub.efiSupport = true;
  boot.loader.grub.device = "nodev";
  boot.loader.efi.canTouchEfiVariables = true;
  boot.loader.grub.enable = true;
  boot.loader.systemd-boot.enable = false;
  services.xserver.dpi = 207;

  networking.hostId = "389acda5"; # required for zfs use
  boot.zfs.devNodes = lib.mkForce "/dev/disk/by-uuid";                          # (ref:devNodes)

  sops.secrets.tailscale_tres_ebow.owner = "root";
  services.tailscale.authKeyFile = config.sops.secrets.tailscale_tres_ebow.path;

  boot.initrd.availableKernelModules = [ "xhci_pci" "nvme" "usb_storage" "sd_mod" ];
  boot.initrd.kernelModules = [ ];
  boot.kernelModules = [ "kvm-intel" ];
  boot.extraModulePackages = [ ];

  fileSystems."/" =
    { device = "host/root";
      fsType = "zfs";
    };

  fileSystems."/home" =
    { device = "host/home";
      fsType = "zfs";
    };

  fileSystems."/nix" =
    { device = "host/nix";
      fsType = "zfs";
    };

  fileSystems."/boot" =
    { device = "/dev/disk/by-uuid/CB62-8263";
      fsType = "vfat";
    };

  swapDevices =
    [ { device = "/dev/disk/by-uuid/4f1751ef-0ddd-4005-b69c-daafc518e9df"; }
    ];

  networking.useDHCP = lib.mkDefault true;

  nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
  powerManagement.cpuFreqGovernor = lib.mkDefault "balanced";
  hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
  hardware.enableRedistributableFirmware = true;
}

Deploying The Wobserver

Last Bank

Last Bank is my New Homelab Build, a living-room server that will be proxied through Wobscale Technologies in Seattle, WA. It's going to replace terra-firma.

nix:tangle ~/nix/snippets/last-bank.nix:noweb yes
nixosConfigurations.last-bank = mkHost {
  name = "last-bank";
  homeManager = false;
  roleModules = [
    <<host-modules("server")>>
  ];
  extraModules = [
    ./nixos/home-manager-server.nix
  ];
};
nix:tangle ~/nix/hosts/last-bank/default.nix:mkdirp yes
{ lib, config, ... }:

let
in {
#  imports = [ ../../roles/desktop ];
#  boot.enableVFIO = true;

  networking.hostName = "last-bank";
  system.stateVersion = "23.05";

  boot.loader.grub.enable = true;
  boot.loader.grub.device = "/dev/disk/by-id/ata-Samsung_SSD_870_EVO_1TB_S75BNL0WA24883N";
  sops.secrets.tailscale_last_bank.owner = "root";
  services.tailscale.authKeyFile = config.sops.secrets.tailscale_last_bank.path;

  networking.hostId = "56c334f2"; # required for zfs use
  boot.zfs.devNodes = "/dev/disk/by-id";                          # (ref:devNodes)

  boot.initrd.availableKernelModules = [ "ehci_pci" "ahci" "isci" "usbhid" "usb_storage" "sd_mod" "igb" ];
  boot.initrd.kernelModules = [ ];
  boot.kernelModules = [ "kvm-intel" ];
  boot.extraModulePackages = [ ];

  fileSystems."/" =
    { device = "host/root";
      fsType = "zfs";
    };

  fileSystems."/nix" =
    { device = "host/nix";
      fsType = "zfs";
    };

  fileSystems."/home" =
    { device = "tank/home";
      fsType = "zfs";
    };

  fileSystems."/media" =
    { device = "tank/media";
      fsType = "zfs";
    };

  fileSystems."/srv" =
    { device = "tank/srv";
      fsType = "zfs";
    };

  fileSystems."/boot" =
    { device = "/dev/disk/by-uuid/19C9-747A";
      fsType = "vfat";
    };

  swapDevices =
    [ { device = "/dev/disk/by-id/ata-Samsung_SSD_870_EVO_1TB_S75BNL0WA24883N-part2"; }
    ];

  boot.initrd.network = {
    enable = true;
    ssh = {
      enable = true;
      port = 2222;
      hostKeys = [ /home/rrix/arroyo-nix/files/last-bank-initrd-host-key ];
      authorizedKeys = [ "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCt7MT45sX7yML+aUqWUC2RZdxhVpoGz2XLEDes/h0HnvwkV8ZURSBAlkwSAH5Sd2c6nyego0GsvkOUppeqoKtacMz6JK5iut3hMWiR6NcSZfG7r8NR5/WrPpWwGtU7cRkkxVKM1PwtYk0crQTCVg5G9+9quKtGkEQ33ile5XSr2VVO44hWafZlSLPFPXTLvxgm7MN9E28k7hVeDBIYppM6VnWz5xsbhboKJMSHU8SFPQKw2GqaugDqokeS0SbyCj7poj1uyijQx3hw0RTpzy1XrmCFu4HmT7qgpESi+1aMObItezKyHy6zBh58DF3Hu/T3tqFglR6XbyfsR3IHyTVz rrix" ];
    };
    # postCommands = ''
    #   zpool import -a
    #   echo "zfs load-key -a; killall zfs" >> /root/.profile
    # '';
  };
  # greetz https://elis.nu/blog/2026/04/nixos-zfs-remote-unlock-over-ssh/
  boot.initrd.systemd.services.zfs-setup-root-profile = {
    description = "Prepare root .profile for ZFS unlocking via SSH";
    wantedBy = [ "initrd.target" ];
    before = [ "initrd-root-fs.target" ];
    unitConfig.DefaultDependencies = false;
    script = ''
      mkdir -p /var/empty
      echo "systemd-tty-ask-password-agent --watch" > /var/empty/.profile
    '';
    serviceConfig.Type = "oneshot";
  };

  networking.useDHCP = lib.mkDefault true;

  nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
  hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
}

Deploying the Edge Server

King Mountain

The Wobserver's Edge Server in seattle

King Mountain is The Wobserver's Edge Server, a small VM hosted by Wobscale Technologies in Seattle, WA so that my Wobserver doesn't need a public IP.

nix:tangle ~/nix/snippets/king-mountain.nix:noweb yes
nixosConfigurations.king-mountain = mkHost {
  name = "king-mountain";
  roleModules = [
    <<host-modules("edge")>>
  ];
};
nix:tangle ~/nix/hosts/king-mountain/default.nix:mkdirp yes
{ lib, config, modulesPath, ... }:

{
  imports = [
    "${toString modulesPath}/profiles/qemu-guest.nix"
  ];

  networking.hostName = "king-mountain";
  system.stateVersion = "24.11";

  sops.secrets.tailscale_king_mountain.owner = "root";

  services.tailscale.authKeyFile = config.sops.secrets.tailscale_king_mountain.path;

  networking.hostId = "66c334a2";          # required for zfs use
  boot.zfs.devNodes = "/dev/disk/by-uuid"; # (ref:devNodes)

  fileSystems."/" = {
    device = "/dev/disk/by-label/nixos";
    autoResize = true;
    fsType = "ext4";
  };

  boot.growPartition = true;
  boot.kernelParams = ["console=ttyS0"];
  boot.loader.grub.device = "/dev/sda";
  boot.loader.timeout = 3;

  boot.initrd.availableKernelModules = [ "ehci_pci" "ahci" "isci" "usbhid" "usb_storage" "sd_mod" ] ++ [
    "virtio_net"
    "virtio_pci"
    "virtio_mmio"
    "virtio_blk"
    "virtio_scsi"
    "9p"
    "9pnet_virtio"
  ];
  boot.initrd.kernelModules = [
    "virtio_balloon"
    "virtio_console"
    "virtio_rng"
    "virtio_gpu"
  ];
  boot.kernelModules = [ "kvm-intel" ];
  boot.extraModulePackages = [ ];

  networking.useDHCP = lib.mkDefault true;

  nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
  hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
}

Shared Generator

host-modules(role) queries the DB for ARROYO_NIXOS_MODULE entries filtered by role and returns ./modulePath lines.

lua#+name: host-modules:eval arroyo:results raw:var role="endpoint"
local modules = arroyo.nixos_role_modules(role)
local lines = {}
for _, m in ipairs(modules) do
  table.insert(lines, "./" .. m.module_path)
end
  return table.concat(lines, "\n    ")