Day 12 — Flake host skeleton

Updated

July 30, 2026

Day 12 — Flake host skeleton

Stage II · ~4h
Goal: Manage the lab host with a flake (nixosConfigurations) from day one of ownership—nixos-rebuild switch --flake .#<host> is the source of truth.

Tip

Syllabus expert default: do not invest weeks in non-flake /etc/nixos only to rewrite. Migrate now while the config is small.

Why this day exists

A NixOS system without a flake pin drifts like a channel laptop. Flakes give you:

  • Locked nixpkgs (and later inputs)
  • Named hosts in one repo
  • A rebuild command you can document and automate

Theory 1 — nixosConfigurations output

outputs = { self, nixpkgs, ... }: {
  nixosConfigurations.lab = nixpkgs.lib.nixosSystem {
    system = "x86_64-linux";
    modules = [
      ./hosts/lab/configuration.nix
      ./hosts/lab/hardware-configuration.nix
    ];
  };
};
Piece Role
nixosSystem Module system entry for a host
system CPU-OS triple for packages
modules List of NixOS modules (files/functions)
attr name lab Host id in .#lab

Rebuild:

sudo nixos-rebuild switch --flake /path/to/repo#lab
# or from repo:
sudo nixos-rebuild switch --flake .#lab

Theory 2 — Where the flake lives

Location Pros Cons
/etc/nixos/flake.nix Simple path Mixed with generated hardware; git harder
/home/you/nixos-config git repo Proper history Need path on rebuild
Separate git + copy Flexible Sync discipline

Recommended for this volume: git repo in your home (or shared path), rebuild with explicit flake path. Optionally symlink strategy later.


Theory 3 — Module list composition

modules = [
  ./hardware-configuration.nix
  ./configuration.nix
  ./modules/ssh.nix      # later
];

Each module is typically:

{ config, lib, pkgs, ... }: {
  # options / config
}

Or a plain attrset in simple files. Day 18–19 deepen modules; today: imports work.


Theory 4 — Minimal flake host contents

flake.nix

{
  description = "lab flake host";

  inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-26.05";

  outputs = { self, nixpkgs }: {
    nixosConfigurations.lab = nixpkgs.lib.nixosSystem {
      system = "x86_64-linux"; # match your VM
      modules = [
        ./hosts/lab/configuration.nix
        ./hosts/lab/hardware-configuration.nix
      ];
    };
  };
}

hosts/lab/configuration.nix

{ config, lib, pkgs, ... }: {
  networking.hostName = "lab";

  nix.settings.experimental-features = [ "nix-command" "flakes" ];

  boot.loader.systemd-boot.enable = true;
  boot.loader.efi.canTouchEfiVariables = true;

  time.timeZone = "UTC";

  users.users.alice = {
    isNormalUser = true;
    extraGroups = [ "wheel" ];
  };

  environment.systemPackages = with pkgs; [ vim git ];

  services.openssh.enable = true;

  system.stateVersion = "26.05";
}

hardware-configuration.nix

Copy from the machine’s generated file—do not invent UUIDs.


Theory 5 — First rebuild flow

edit flake modules
    ↓
nixos-rebuild switch --flake .#lab
    ↓
eval modules → system derivation → realize → activate
    ↓
new system generation
Outcome Meaning
Success New generation is current
Eval error Fix Nix before build
Build error Package/build failure
Activation error System may be partially switched—read output carefully

Theory 6 — specialArgs / extraSpecialArgs (preview)

nixpkgs.lib.nixosSystem {
  specialArgs = { inherit inputs; };
  modules = [];
}

Used later to pass flake inputs into modules. Not required for the minimal host.


Theory 7 — Hostname vs flake attribute

Name Where
networking.hostName OS hostname
nixosConfigurations.lab Flake attribute

They may match but are not required to. Document both in README.


Worked examples bank

Example A — Build without switching (safe)

nixos-rebuild build --flake .#lab
# or
nix build .#nixosConfigurations.lab.config.system.build.toplevel

Example B — Switch

sudo nixos-rebuild switch --flake .#lab

Example C — Show config value

nix eval .#nixosConfigurations.lab.config.networking.hostName

Lab 1 — Repository layout on the lab host

mkdir -p ~/nixos-config/hosts/lab
cd ~/nixos-config
git init
sudo cp /etc/nixos/hardware-configuration.nix ~/nixos-config/hosts/lab/
sudo chown "$USER":"$USER" ~/nixos-config/hosts/lab/hardware-configuration.nix

Write flake.nix + hosts/lab/configuration.nix (adapt user, system, boot).

git add .
nix flake lock
git add flake.lock
git commit -m "day12: initial nixosConfigurations.lab"

Lab 2 — First flake rebuild

cd ~/nixos-config
sudo nixos-rebuild switch --flake .#lab

Verify:

nixos-version
hostname
nix eval .#nixosConfigurations.lab.config.networking.hostName

Lab 3 — Prove flake is authority

  1. Change a harmless package in environment.systemPackages (add htop).
  2. Rebuild switch.
  3. Confirm htop available.
  4. Commit.

Avoid editing /etc/nixos/configuration.nix as the long-term path—if installer files remain, leave a comment in README: flake repo is SoT.


Lab 4 — README for future you

README.md:

# nixos-config

## Rebuild
sudo nixos-rebuild switch --flake .#lab

## Host
- flake attr: lab
- hostname: lab
- nixpkgs: 26.05 (see flake.lock)

Lab 5 — Optional: match /etc/nixos to flake

Some prefer:

# conceptual — only if you understand implications
# keep hardware in repo; rebuild always with --flake

Do not create circular confusion. Simplest: always cd ~/nixos-config && sudo nixos-rebuild switch --flake .#lab.


Common gotchas

Symptom Theory
Absolute import paths broken Prefer relative module paths in repo
Wrong system Eval/build target mismatch
hardware config not updated after disk change Regenerate carefully
experimental-features missing Rebuild cannot use flakes cleanly
Dirty git / missing files Flake file inclusion
stateVersion folklore Set to install release; read release notes before changing

Checkpoint

  • nixosConfigurations.<host> exists
  • hardware-configuration.nix imported from flake repo
  • switch --flake .#host succeeded
  • Lock committed
  • README documents rebuild
  • Small declarative change proven

Commit

cd ~/nixos-config
git add .
git commit -m "day12: flake host skeleton rebuild switch"

Tomorrow

Day 13 — Rebuild modes & generations. switch / test / boot / build, generation listing, and a deliberate break → rollback.