Skip to content

Architecture

This repository manages two independent NixOS systems through separate flakes. Each system is self-contained with its own flake.nix, inputs, and module tree.

Systems

PropertyLaptop (laptop)Server (homelab)
CPUAMD Ryzen (Radeon iGPU)Intel
KernelCachyOS (Chaotic-Nyx)Vanilla Linux
BootLanzaboote (Secure Boot)systemd-boot
DiskLUKS + ext4LUKS + BTRFS + Impermanence
DesktopSway (Wayland)Headless
SecretsNoneagenix (11 encrypted secrets)
ContainersNone7 active (systemd-nspawn)
State Version24.1124.11

Design Principles

Independent Flakes

The laptop and server configurations are completely decoupled. Each has its own flake.nix with its own set of inputs. This means:

  • Updating the server does not affect the laptop, and vice versa.
  • Each system can pin different versions of nixpkgs or any other input.
  • No shared modules or abstractions that could introduce coupling.

Module Granularity

Every feature is isolated in its own file. The laptop has 22 modules; the server has 16 modules plus 9 container definitions. A module typically owns a single concern:

laptop/modules/
  boot.nix          # Lanzaboote + Secure Boot
  kernel.nix        # CachyOS kernel + sysctl
  network.nix       # iwd WiFi
  pipewire.nix      # Audio stack
  ...

This makes it trivial to enable, disable, or audit any feature by adding or removing a single import in flake.nix.

Parameterised Configuration

Both flakes pass common values through specialArgs:

nix
specialArgs = {
  inherit inputs;
  username = "nixos";
  hostname = "laptop";    # or "homelab"
  domain = "nemnix.site"; # server only
};

Modules receive these as function arguments, avoiding hardcoded values:

nix
{ username, hostname, ... }:
{
  networking.hostName = hostname;
  users.users.${username}.isNormalUser = true;
}

Pure Nix, No Channels

Both systems set nix.channel.enable = false and rely entirely on flake inputs. The nixPath is pinned to the flake's nixpkgs input to ensure nix-shell and legacy tooling still work:

nix
nix.nixPath = [ "nixpkgs=${inputs.nixpkgs}" ];

Data Flow

flake.nix
  ├── inputs (nixpkgs, disko, lanzaboote, chaotic, ...)
  └── nixosConfigurations.<hostname>
        ├── specialArgs (username, hostname, domain)
        └── modules/
              ├── hardware-configuration.nix   (generated, hardware-specific)
              ├── disko.nix                     (declarative disk layout)
              ├── boot.nix                      (bootloader config)
              ├── kernel.nix                    (kernel, sysctl)
              ├── network.nix                   (networking)
              └── ...                           (one file per concern)

Flake Inputs

Laptop

InputSourcePurpose
nixpkgsnixos-unstablePrimary package set
nixpkgs-stablenixos-25.11Stable packages (AppFlowy)
chaoticchaotic-cx/nyxCachyOS kernel, binary cache
diskonix-community/diskoDeclarative disk partitioning
lanzabootenix-community/lanzaboote v1.0.0Secure Boot
helixhelix-editor/helix masterEditor from git
neixHovirix/neixNix package search tool

Server

InputSourcePurpose
nixpkgsnixos-unstablePrimary package set
nixpkgs-stablenixos-25.05Stable packages
diskonix-community/diskoDeclarative disk partitioning
lanzabootenix-community/lanzaboote v0.4.2Imported but using systemd-boot
impermanencenix-community/impermanenceEphemeral root filesystem
agenixryantm/agenixSecrets management

Built with VitePress