Lab 0B — NixOS development machine
Lab 0B — NixOS development machine
Goal: Configure a comfortable, stable environment for writing flakes, reviewing nixpkgs, running builds, and pushing configs to lab VMs—without turning your editor session into the system under test.
On a single Elitebook, Lab 0B usually lives on the host (same metal as Lab 0A). The split is role, not necessarily second hardware.
Text-first infrastructure (flakes, modules, virsh/incus CLI) is also what makes human + AI co-maintenance safe: agents can read and propose diffs against git. GUI-only state and untracked shell fixes cannot. Keep Lab 0B disciplined: if it matters, it is in the repo.
Dev machine vs journey guest
| Dev (this lab) | Journey guest (nixlab) |
|
|---|---|---|
| Purpose | Author configs, run nix tools |
Be the OS you break |
| Rebuild frequency | Low | High |
| Secrets | Your age keys, git ssh | Lab secrets only |
| Editor | Yes | Optional |
| “Does this need to be pretty?” | Yes (you live here) | No |
Part 1 — Install Nix (if host is not NixOS)
Multi-user install; enable flakes:
# ~/.config/nix/nix.conf
experimental-features = nix-command flakesOn NixOS host, put the same under nix.settings.experimental-features.
Part 2 — Essential packages
NixOS host module sketch
{ pkgs, ... }: {
environment.systemPackages = with pkgs; [
git
git-lfs
vim
neovim
ripgrep
fd
jq
tree
htop
tmux
direnv
nix-direnv
nixfmt-rfc-style # or nixfmt — pick one and stick to it
nil # LSP for Nix
# optional:
# vscode / emacs — your preference
];
programs.direnv.enable = true;
programs.direnv.nix-direnv.enable = true;
# nice for rebuilds against VMs
environment.systemPackages = with pkgs; [
# already have git etc.
];
}Non-NixOS host
nix profile install nixpkgs#git nixpkgs#neovim nixpkgs#direnv nixpkgs#nix-direnv nixpkgs#nilPart 3 — Editor + LSP
| Editor | Nix LSP |
|---|---|
| Neovim/VS Code | nil or nixd |
| Emacs | same + envrc |
Minimal checks:
nil --help # or nixd
rg "mkOption" ~/src/nix-config -n | headPart 4 — Git layout for the whole journey
~/src/nix-config/ # or ~/lab/90daysofx/nixos-config
flake.nix
flake.lock
hosts/
nixlab/
deploy-a/
modules/
homes/ # from Stage III
secrets/ # encrypted only (Stage IV)
.envrc # use flake
README.md
cd ~/src/nix-config
git init
echo ".direnv" >> .gitignore
echo "result" >> .gitignore
echo "result-*" >> .gitignore.envrc:
use flakedirenv allowPart 5 — Build ergonomics
Keep host builds from melting a 2012 laptop
nix.settings = {
max-jobs = 2; # Elitebook: start low
cores = 2;
# auto-optimise-store = true; # optional
};Substituters
Default cache.nixos.org is fine. Later stages may add Cachix/Attic—document tokens only in sops, never in world-readable nix.
Remote / guest as builder (optional, Stage V+)
When nixlab is stronger or you want isolation:
# conceptual — configure nix.buildMachines later in curriculumEarly on: build on host, deploy to guest is simplest.
Part 6 — Access to journey VMs
# ssh config ~/.ssh/config
Host nixlab
HostName 192.168.122.10
User YOU
IdentityFile ~/.ssh/id_ed25519_lab
Host deploy-a
HostName 192.168.122.11
User YOU
IdentityFile ~/.ssh/id_ed25519_labGenerate a lab-only key:
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_lab -C "lab-elitebook"Do not reuse your primary GitHub key as the only lab key if you prefer blast-radius control.
Part 7 — Workflow commands you will live with
# evaluate / build a guest config from the flake (host)
nix build .#nixosConfigurations.nixlab.config.system.build.toplevel
# apply (from host, once SSH works)
nixos-rebuild switch --flake .#nixlab --target-host YOU@nixlab --use-remote-sudo
# or: ssh and rebuild inside guest
ssh nixlab 'sudo nixos-rebuild switch --flake /path/to/config#nixlab'
# format
nix fmt # if configuredPart 8 — Home Manager on the dev role
Optional but nice on the host:
- Shell (fish/zsh), git, ssh config
- Keep HM on host separate from guest HM experiments
When Stage III teaches HM, practice on nixlab first if you want isolation; port habits back to host later.
Part 9 — Binary cache & secrets (preview only)
| Later stage | Dev machine prep |
|---|---|
| sops-nix | Install sops, age; create age key backup offline |
| CI | GitHub/GitLab SSH deploy key for the flake repo |
| Cachix | Account ready; don’t put signing key in git |
Create age key early if you want:
mkdir -p ~/.config/sops/age
age-keygen -o ~/.config/sops/age/keys.txt
# back up keys.txt to password manager / encrypted USBPart 10 — Quality of life on old hardware
| Tip | Why |
|---|---|
| External monitor + keyboard | 2570p is a server that happens to fold |
tmux/zellij |
Long builds survive SSH drops |
| Disable heavy desktop effects on host | Free RAM for VMs |
nix-store --optimise occasionally |
Disk |
| Don’t run browser + 2 VMs + big compile | Sequentialize |
Dev machine checklist
nix flake metadataworks in~/src/nix-config(even empty flake)
- direnv loads a simple
devShell
- Editor can jump/lint Nix files
- SSH to
nixlab(or console) documented
- Lab SSH key created; age key backup plan written
max-jobs/coresset conservatively
.gitignoreincludesresultand.direnv
Anti-patterns
| Anti-pattern | Prefer |
|---|---|
| Editing production-like host to “try modules” | Try on nixlab (or host-sim VM) |
One 2k-line configuration.nix on host |
Layout from Stage III early for guests |
| Storing secrets in world-readable nix | sops/agenix later |
Building with max-jobs = auto until OOM |
Cap jobs on Elitebook |
| “YOLO” imperative fix left uncommitted | Encode fix in flake; commit with why |
| Relying on virt-manager clicks you cannot replay | Keep a virt-install / incus snippet in README |
Next
→ Lab 0C — HP Elitebook 2570p profile
→ Then Why Nix exists (first topic chapter)