The NixOS fleet
Twelve computers, one description.
- 12 machines
- 54 shared modules
- 1 command to deploy
The problem
Our household runs on a dozen computers: my work laptop, the family's laptops, a recording PC, two little Raspberry Pis and a server in a data centre. Set up by hand, each one slowly drifts away from the others. A fix made on one never reaches the rest, and after a year nobody remembers how any of them was built.
What it does now
- Every machine is built from one written description, so any of them can be rebuilt from scratch and come back the same.
- One command updates a single machine or all of them, and each one reports back in my chat app when it's done.
- Every machine backs up every night, and a second copy goes offsite.
- A private network joins them wherever they are, without opening them to the internet.
- A dashboard on my phone shows the whole system at a glance.
Where AI came in
Most of the description is written by Claude Code, an AI assistant that works in my terminal. I decide what each machine should do, review every change, and check it on the real hardware. The project keeps its own handbook, and the AI has to update it with every change, so each session starts from what's written down instead of from guesswork.
How it's built
Shape
- One Nix flake describes all twelve machines. Each host has a module list in
flake.nix. The 54 shared modules are switched on per host through alocal.*option namespace, and home-manager carries each person's desktop. - Secrets are encrypted in the repo with sops-nix, per host, so the repo can be cloned anywhere without exposing them.
The network: Nebula, not Tailscale
li4, a small Linode VM, is the lighthouse and relay. Every other machine finds the rest through it and then talks to them directly.
The fleet started on Tailscale. I built a self-hosted headscale server to drop the vendor account, and abandoned it the next day (2026-09-11): an Android client shipped a protocol version no headscale release understood, and there was nothing installable that would fix it. Nebula has no control plane to fall out of step with. A machine either holds a valid certificate and can reach a lighthouse, or it doesn't, and both halves can be checked locally.
Hosts carry groups in their certificates. tinyclaw, the AI assistant, is in group agent,
and li4's firewall lets that group reach one port and nothing else. sparelt isn't on the
overlay yet, and woab01 stays off it entirely, by design.
Services that should never be public (the password vault, the dashboards) answer only on the overlay. Their TLS comes from a private certificate authority, name-constrained to the overlay's own domain, so there's no public DNS record and no ACME account.
Deploys
./rebuild <host>, ./rebuild fleet or ./rebuild hypr runs from my laptop. It builds on
tinydaw, the recording desktop, and switches each machine over ssh. A laptop that
is asleep gets its system built and held, then shipped on the next run. Every run posts a
record to the dashboard's deploy log, and when Claude runs it, the /rebuild skill pings
me on Matrix as each host finishes.
tinydaw also runs a binary cache (harmonia). The other machines pull from it before
cache.nixos.org, so a package is built or downloaded once per fleet, not once per laptop.
Backups
Every machine sends a nightly restic backup to tinydaw over the overlay. Each night tinydaw mirrors that store offsite, and the snapshots on the far end are what protects against tinydaw itself failing. A failed job emails me.
Keeping the AI honest
Every .nix file opens with a header that says what it is for and why, including what was
tried and reverted. That's often the most useful comment in the file. A docs/ wiki covers
what no single file can say, and its tables (the host-to-module matrix, the option list)
are generated from the tree by a script with a --check mode. The repo's CLAUDE.md tells
the AI that a change isn't finished until the header, the generated tables and a freshness
stamp are updated, and that a commit doesn't authorise a deploy.
670 commits since 2026-04-22. The repository is private, so there are no links to it here.