Skip to content

Per Machine Config

NullString1 edited this page May 29, 2026 · 3 revisions

Per-Machine Configuration

NullOS is designed to manage multiple machines with shared configurations while allowing easy per-machine customization via a simple pipeline.

Overview

NullOS supports multiple machines using:

  1. machines/{hostname}/default.nix: Per-machine variables and overrides.
  2. machines/{hostname}/secrets.yaml: Encrypted secrets via SOPS-nix.
  3. modules/system/hardware_{hostname}.nix: Hardware-specific configurations.
  4. machines/profiles/{profile}.nix: Shared feature flags for specific classes of machines (e.g. pc or server).

Current Machine Configurations

nslapt - Laptop Configuration

Profile: pc Hardware: Intel + NVIDIA (Prime) laptop.

  • Uses NVIDIA PRIME (dGPU offload)
  • Specialisation for power-efficient (disables NVIDIA for battery life)
  • Passwordless sudo, Restic backups

nspc - Desktop Configuration

Profile: pc Hardware: Full NVIDIA (open driver) desktop.

  • Full NVIDIA GPU active
  • Steam enabled
  • Configured as distributed build machine (speedFactor 2x) for other hosts.

nsminipc - Mini PC Configuration

Profile: server Hardware: Small form factor headless server.

  • Headless (desktopEnvironment = null)
  • Minimal services

Setting Up a New Machine

Step 1: Generate Hardware Configuration

Boot the new machine with the NixOS installer and run:

nixos-generate-config --show-hardware-config > /tmp/hardware_newmachine.nix

Copy /tmp/hardware_newmachine.nix to your NullOS repo as modules/system/hardware_newmachine.nix.

Step 2: Create the Machine Directory

Create a folder for the new machine:

mkdir machines/newmachine

Create machines/newmachine/default.nix:

{
  username = "yourusername";
  hostname = "newmachine";
  system = "x86_64-linux";
  
  # Select desktop environment: "hyprland", "kde", or null
  desktopEnvironment = "hyprland";
  
  # Override any base feature flags
  enableSteam = true;
  
  # Extra arbitrary NixOS config (if needed)
  boot.devSize = "8G";
}

Step 3: Set up Secrets (sops-nix)

Create the secrets file for the new machine:

# Assuming your SOPS key is set up
sops machines/newmachine/secrets.yaml

Add required secrets like githubToken or resticRepository. Also ensure you update .sops.yaml in the root of the project to allow the new machine if you use machine-specific keys, though currently NullOS uses a single user key.

Step 4: Add to Flake

Edit flake.nix and add the new configuration under nixosConfigurations:

nixosConfigurations = {
  # Existing machines...
  nslapt = mkSystem "nslapt" "pc";
  nspc = mkSystem "nspc" "pc";
  
  # Your new machine
  newmachine = mkSystem "newmachine" "pc"; # Or "server" for a server profile
};

Step 5: Build and Switch

sudo nixos-rebuild switch --flake .#newmachine

The 3-Stage Feature Toggle Pipeline

The core logic of NullOS per-machine configs lives in flake.nix lines 58-100.

  1. Base defaults are loaded from machines/profiles/base.nix.
  2. Profile overrides are applied from machines/profiles/<profile>.nix (e.g. enabling Steam/Lutris for PCs, but disabling them for servers).
  3. Machine overrides from machines/{hostname}/default.nix are applied last.

This resulting configuration object is named vars and is passed to all modules using specialArgs.


Machine-Specific NixOS Configurations

There's a neat quirk in NullOS: Any key inside machines/{hostname}/default.nix that is not one of the reserved variables (like username, enableSteam, etc.) is automatically bundled into extraNixosConfig.

This means you can place pure NixOS config directly inside your machine's default.nix without creating a whole new module. Example:

{
  hostname = "nsminipc";
  # ... other vars ...
  
  # This becomes part of the raw NixOS config:
  services.periodic-reboot = {
    enable = true;
    timerConfig.OnCalendar = "weekly";
  };
}

Using vars in Custom Modules

Inside modules/software/packages.nix or home/default.nix, use vars to conditionally enable configurations:

{ config, pkgs, vars, lib, ... }:

{
  config = lib.mkIf vars.enableSteam {
    programs.steam.enable = true;
  };
}

This prevents you from needing complex if vars.hostname == "nspc" then ... statements. Instead, rely on the feature flags!


Next Steps

Clone this wiki locally