Archived
Both existed only so the installer could boot as an LXC container and nixos-install some other host from within it, but lxc-* targets are already excluded from the install menu (nixos-install can't touch its own running root filesystem), and now have their own direct tarball path anyway. That left the installer's own LXC form with no real use case, and packages.all with only two members worth bundling. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01La55Nsss8jZ7ZuzUV9mfot
175 lines
9.1 KiB
Markdown
175 lines
9.1 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
## Repo purpose
|
|
|
|
Flake-based NixOS configuration for Wayne's LAN servers and workstation. There is
|
|
no application code here — changes are Nix module edits that affect real
|
|
machines when deployed.
|
|
|
|
## Safety rules (read before touching anything)
|
|
|
|
- **Never** run `nixos-rebuild switch|boot|test`, `nixos-install`, `parted`,
|
|
`mkfs`, `mkswap`, `swapon`, `mount`, or any other destructive disk/deploy
|
|
command from an agent session, even if asked indirectly. Deployment is done
|
|
manually by the operator on the target host.
|
|
- Validation is limited to evaluation, linting, formatting checks, and
|
|
`nix build --dry-run --no-link`.
|
|
- Do not add secrets, tokens, private keys, or new password hashes to the repo.
|
|
- This repo currently contains **committed password hashes** in
|
|
`modules/installer/common.nix` (the auto-installer's own root/nixos login —
|
|
a deliberate, documented choice, see `docs/auto-installer.md`, not
|
|
accidental tech debt) and **SSH public keys** in `variables.nix`
|
|
(`vars.adminSshKey`, `vars.remoteBuilderAuthorizedKeys`) plus a couple of
|
|
per-host `KEY` values for beszel-agent auth (`hosts/server/host.nix`,
|
|
`hosts/nix-cache/host.nix`). Don't use the installer's hardcoded hash as a
|
|
template for a *real* host — every other host uses sops-nix
|
|
(`hashedPasswordFile`, see "Security Notes" in `README.md`). Flag any *new*
|
|
secret-like string you encounter instead of committing it.
|
|
- `host-keys/` is gitignored — locally-generated *private* SSH host keys for
|
|
the auto-installer (see `docs/auto-installer.md`). Never commit its
|
|
contents; if `git status` ever shows it as trackable, something is wrong.
|
|
|
|
## Commands
|
|
|
|
```bash
|
|
# One-time environment bootstrap (installs Nix if missing, prints hosts)
|
|
bash scripts/codex-setup.sh
|
|
|
|
# Full validation: secret grep, nixpkgs-fmt --check, statix lint, eval all hosts
|
|
bash scripts/codex-maintenance.sh
|
|
|
|
# Same, plus a dry-run build (no result symlink) of every host's toplevel
|
|
bash scripts/codex-maintenance.sh dry-run
|
|
|
|
# List the hosts the flake currently exposes
|
|
nix eval --json .#nixosConfigurations --apply builtins.attrNames | jq -r '.[]'
|
|
|
|
# Evaluate a single host without building (fast sanity check)
|
|
nix eval .#nixosConfigurations.<host>.config.system.build.toplevel.drvPath --raw
|
|
|
|
# Dry-run build a single host
|
|
nix build --dry-run --no-link .#nixosConfigurations.<host>.config.system.build.toplevel
|
|
```
|
|
|
|
Formatting/lint tools (`nixpkgs-fmt`, `statix`) are not installed locally; the
|
|
maintenance script pulls them via `nix run github:NixOS/nixpkgs/nixos-25.11#<tool>`.
|
|
There is no test suite — "correctness" here means the flake evaluates and
|
|
`nixpkgs-fmt`/`statix` are clean.
|
|
|
|
**In an interactive agent session**, prefer targeted checks over full-repo
|
|
sweeps: after editing one or two hosts/modules, evaluate just the
|
|
`nixosConfigurations.<host>` you touched (plus any `config.system.build.tarball`
|
|
/`diskoImagesScript`/package output affected) rather than looping over every
|
|
host — `codex-maintenance.sh` evaluates 19 hosts plus every package/tarball/
|
|
image variant now and is slow to run after each small change. Reserve a full
|
|
`codex-maintenance.sh` run for changes that plausibly affect every host
|
|
(`modules/common/*`, `flake.nix`, `variables.nix`) or as a final check before
|
|
committing. This is a session-workflow preference only — it does not apply to
|
|
CI, which should keep running the full script on every push/PR regardless of
|
|
diff size; that's the point of it.
|
|
|
|
## Architecture
|
|
|
|
`flake.nix` is the single entry point. It generates one
|
|
`nixosConfigurations.<platform>-<buildtype>` attribute per target via the
|
|
`mkTarget` function, composed from:
|
|
|
|
```
|
|
nixosSystem {
|
|
modules = [
|
|
disko.nixosModules.disko
|
|
sops-nix.nixosModules.sops
|
|
./modules/common/configuration.nix
|
|
./modules/platforms/${platform}.nix # what it runs on
|
|
./modules/build-types/${buildType}.nix # what it's for
|
|
hostPath # hosts/<name>/host.nix — per-machine identity
|
|
home-manager.nixosModules.home-manager { ... }
|
|
] ++ (client-only modules, for every buildType except "nix-cache" itself)
|
|
}
|
|
```
|
|
|
|
Platforms: `linode`, `proxmox`, `lxc`. Build types: `minimal`, `nix-cache`,
|
|
`server`, `docker`, `gui`, `pxe-boot`. Not every combination is built — e.g.
|
|
`pxe-boot` has no `linode` variant (PXE/DHCP/TFTP need LAN L2 adjacency a
|
|
Linode VPS doesn't have). Treat `flake.nix`'s `generatedTargets` as the source
|
|
of truth for which hosts exist — `README.md`, `AGENTS.md`,
|
|
`docs/flake-lock-automation.md`, and the CI eval workflows
|
|
(`.github/workflows/check-nixos.yml`, `.gitea/workflows/check-nixos.yml`) list
|
|
hosts by hand (or, for the CI workflows, evaluate the flake dynamically) and
|
|
can drift from it, so re-check them against `flake.nix` when adding or
|
|
removing a host.
|
|
|
|
### Composition pattern
|
|
|
|
- `hosts/<name>/host.nix` — per-machine identity **only**: hostname, hostId,
|
|
per-machine secrets, `system.stateVersion`. These files carry no `imports`
|
|
of their own beyond narrow parameterized helpers (see
|
|
`modules/beszel/host-token.nix` below) — all shared behavior comes from the
|
|
platform/build-type modules composed in `flake.nix`, not from the host file.
|
|
- `modules/platforms/{linode,proxmox,lxc}.nix` — platform-specific config:
|
|
boot method, guest tooling, and (for linode/proxmox) the hypervisor-specific
|
|
hardware config, imported directly by the platform module itself
|
|
(`../hardware-configuration/vm/{proxmox,linode}.nix`) — **not** wired in
|
|
from `flake.nix`. `lxc.nix` has no hardware-configuration counterpart since
|
|
containers share the host kernel; instead it imports nixpkgs' own
|
|
`virtualisation/proxmox-lxc.nix`, which gives every `lxc-*` host a
|
|
`config.system.build.tarball` output (`pct restore`-ready, no install step
|
|
— see `docs/auto-installer.md`).
|
|
- `modules/build-types/*.nix` — what a system is for:
|
|
minimal/server/docker/gui/pxe-boot/nix-cache.
|
|
- `modules/common/configuration.nix` — base NixOS config imported by every
|
|
host: locale, users, nix settings, git.
|
|
- `modules/common/home.nix` / `hosts/nixos/home.nix` — Home Manager config for
|
|
the `nixos` user; the `nixos` workstation (`gui` build type) has its own,
|
|
other hosts share `modules/common/home.nix`.
|
|
- `modules/disko/proxmox.nix` — declarative disk layout (GPT: ESP + swap +
|
|
ext4 root) via disko, used by all Proxmox-VM hosts (`proxmox-*`, not
|
|
`lxc-*`). Also carries `imageSize`/`imageName`, letting every `proxmox-*`
|
|
host be built as a standalone, `qm importdisk`-ready `.raw` image with no
|
|
install step — see `docs/proxmox-images.md`.
|
|
- `modules/boot/efi.nix` — systemd-boot + EFI vars, paired with the disko module.
|
|
- `modules/installer/` — the auto-installer environment (ISO, also served as
|
|
PXE netboot): `common.nix` (shared config + the generated
|
|
`auto-install.sh`), `iso.nix`, `host-keys.nix` (optionally bakes
|
|
`host-keys/` into the image under `--impure`). See
|
|
`docs/auto-installer.md`.
|
|
- `modules/pxe-boot/stage-installer-artifacts.nix` — builds the installer's
|
|
netboot image and stages it on the `pxe-boot` host so its iPXE menu can
|
|
chain straight to it. See `docs/pxe-boot.md`.
|
|
- `modules/nix-cache/{client,server,remote-builder-client}.nix` — binary cache
|
|
substituter + SSH remote-builder wiring; see `docs/nix-cache.md` for the
|
|
full design (per-host local stores, no shared `/nix/store`, and how the
|
|
`nixremote` signing/SSH keys fit together).
|
|
- `modules/beszel/host-token.nix` — parameterized helper module
|
|
(`{ name, sopsFile }`) that wires a host's beszel-agent sops secret/template
|
|
and `environmentFile`; used by `hosts/server/host.nix` and
|
|
`hosts/nix-cache/host.nix` to avoid duplicating that boilerplate.
|
|
- `modules/tailscale/`, `modules/docker/`, `modules/networking/`,
|
|
`modules/traefik/`, `modules/services/*` — single-purpose, single-host
|
|
feature modules (e.g. `docker/enable-service.nix`,
|
|
`services/zfs/enable-service.nix`). Grep `modules/build-types/*.nix` for
|
|
each build type's `imports` list to see which modules apply where.
|
|
|
|
New host = new `hosts/<name>/host.nix` + a matching
|
|
`mkTarget { platform; buildType; hostPath; }` entry added to `flake.nix`'s
|
|
`generatedTargets`, composed from existing `modules/*` pieces rather than
|
|
duplicating config.
|
|
|
|
### Other docs worth reading before touching these areas
|
|
|
|
- `docs/nix-cache.md` — nix-cache binary cache/remote-builder design and key
|
|
handling.
|
|
- `docs/pxe-boot.md` — the `pxe-boot` host's iPXE/TFTP/HTTP boot chain and
|
|
directory layout under `/srv/pxe`.
|
|
- `docs/auto-installer.md` — the installer environment (ISO/netboot/Proxmox
|
|
LXC), `host-keys/` and the sops-nix pre-seeding problem it solves, and why
|
|
`lxc-*` hosts are deliberately excluded from its menu.
|
|
- `docs/proxmox-images.md` — building `proxmox-*` hosts as standalone `.raw`
|
|
disk images (disko's image builder) instead of installing, and deploying
|
|
the result to Proxmox.
|
|
- `docs/flake-lock-automation.md` — how `flake.lock` updates flow through CI
|
|
(scheduled `nix flake update` PR + host-eval-on-PR workflow) and why hosts
|
|
should track the committed lock file rather than `nixos-rebuild --upgrade-all`.
|