docs: move prose documentation into docs/ so the docs site publishes it
CI / flake (push) Skipped
CI / flake (pull_request) Successful in 4m21s
CI / flake (push) Skipped
CI / flake (pull_request) Successful in 4m21s
The docs-site build syncs this repo's README.md and docs/ into the site tree; nothing else is copied. All prose apart from the README therefore lived outside the sync and never appeared on https://docs.lyrapup.pet/nixfiles/, and the one page that did publish carried 18 link targets that resolved to nothing. Moves: home/README.md -> docs/shell.md home/KEYBINDINGS.md -> docs/keybindings.md hosts/<Name>/README.md -> docs/hosts/<name>.md docs/.pages and docs/hosts/.pages give the awesome-pages plugin an explicit order; new pages are picked up by the trailing '...' without an edit. Links are rewritten so a single URL is correct in both Gitea and the published site: absolute Gitea source URLs for .nix files and directories, relative links between pages under docs/, and absolute docs.lyrapup.pet URLs from the root README, which the build republishes at a different depth from the rest of the tree. In-code comments that pointed at a moved README are updated to the new path. The README gains a Documentation section covering the sync contract and the linking rules, and CLAUDE.md carries the short version so future edits do not reintroduce unsynced pages or dead links. Verified by reproducing the docs-site assembly locally against its pinned toolchain (mkdocs 1.6.1, mkdocs-material 9.7.7, awesome-pages 2.10.1): pages render at the URLs used above and in the declared order.
This commit is contained in:
@@ -0,0 +1 @@
|
||||
title: Hosts
|
||||
@@ -0,0 +1,51 @@
|
||||
# macOS (nix-darwin) — `lyrathorpe-mac`
|
||||
|
||||
Flake host: `lyrathorpe-mac` (`aarch64-darwin`). Apple Silicon Mac managed by
|
||||
**nix-darwin** from this same flake. Built via `mkDarwinHost` (single-user —
|
||||
macOS owns the account; identity still comes from the registry). Files:
|
||||
`configuration.nix`.
|
||||
|
||||
## What this host is
|
||||
|
||||
A macOS workstation. The interactive user environment (shell, git, editor,
|
||||
Claude) is the **shared `../../home` bundle** — the same modules the Linux hosts
|
||||
use — so the terminal experience matches. The Linux-only `desktop.nix`/`sway.nix`
|
||||
are intentionally left out. This host config covers the macOS-specific layer:
|
||||
system packages, Homebrew, and macOS UI defaults.
|
||||
|
||||
## Package sourcing
|
||||
|
||||
- **nixpkgs** (`environment.systemPackages`) for CLI tooling and libraries.
|
||||
- **Homebrew**, owned declaratively by `nix-homebrew` (Rosetta enabled for
|
||||
x86_64 formulae). The `brews`/`casks` lists are **authoritative**:
|
||||
`onActivation.cleanup = "zap"` uninstalls anything not declared. GUI apps are
|
||||
casks (nixpkgs darwin GUI support is unreliable); a few version-pinned
|
||||
toolchains and the PWA host stay on brew for continuity.
|
||||
- **Mac App Store** apps are **not** declarative: nix-darwin 26.05 runs
|
||||
activation as root, and `mas` cannot reach the App Store session from root.
|
||||
Install them by hand with `mas install <id>` from a GUI Terminal (the `mas`
|
||||
CLI is in `environment.systemPackages`).
|
||||
|
||||
## macOS integration
|
||||
|
||||
- `security.pam.services.sudo_local` — **Touch ID for sudo** (and
|
||||
`darwin-rebuild`'s sudo prompt), kept in `sudo_local` so it survives OS
|
||||
updates. `reattach` pulls in `pam_reattach` so Touch ID works inside tmux
|
||||
(which the terminals auto-start).
|
||||
- `system.defaults` — declarative dock / finder / global / trackpad preferences,
|
||||
applied on activation and reversible. This is the main reason to run nix-darwin
|
||||
beyond package management.
|
||||
- The JetBrainsMono Nerd Font is installed to `/Library/Fonts`; set it in
|
||||
iTerm2 (Settings → Profiles → Text → Font) so the tmux statusline glyphs
|
||||
render.
|
||||
|
||||
## stateVersion
|
||||
|
||||
`system.stateVersion = 5` (the nix-darwin state version, an integer — not a
|
||||
NixOS release string). Read `darwin-rebuild changelog` before changing it.
|
||||
|
||||
## Apply
|
||||
|
||||
```sh
|
||||
darwin-rebuild switch --flake .#lyrathorpe-mac
|
||||
```
|
||||
@@ -0,0 +1,87 @@
|
||||
# Work WSL box — `emmathorpe-edaas`
|
||||
|
||||
Flake host: `emmathorpe-edaas` (`x86_64-linux`). NixOS running under
|
||||
**NixOS-WSL** on the corporate Windows machine. Headless: no Sway desktop
|
||||
(`features.swayDesktop.enable = false`), plain WSL shell login. Files:
|
||||
`configuration.nix`.
|
||||
|
||||
## What this host is
|
||||
|
||||
The day-to-day work environment. It layers the corporate Kubernetes / Helm /
|
||||
Terraform / cloud toolchain and a couple of work-only editor language servers on
|
||||
top of the shared home profile. The system config here is thin — it is mostly
|
||||
WSL plumbing; the user-facing tooling lives in
|
||||
[`../../users/emmathorpe/work.nix`](https://code.emmathe.dev/lyrathorpe/nixfiles/src/branch/main/users/emmathorpe/work.nix).
|
||||
|
||||
## WSL specifics
|
||||
|
||||
- `wsl.enable`, default user `emmathorpe`, Windows PATH interop and start-menu
|
||||
launchers on. `/etc/hosts` generation is off (`generateHosts = false`).
|
||||
- **Docker Desktop integration**, not the native daemon as the primary path:
|
||||
`wsl.extraBin` shims the coreutils/`groupadd`/`usermod` binaries Docker
|
||||
Desktop's `wsl-distro-proxy` expects, and `docker-desktop-proxy.script` is
|
||||
patched to the real proxy path. The native `virtualisation.docker` is also
|
||||
enabled (with `enableOnBoot` + `autoPrune`).
|
||||
- `programs.ssh.systemd-ssh-proxy.enable = false` — the NixOS-WSL store is a
|
||||
read-only VHD owned by `nobody`, and OpenSSH rejects the generated
|
||||
`ssh-proxy` Include as "Bad owner or permissions", which would break ssh/git
|
||||
for every command. The vsock proxy it provides is unused under WSL.
|
||||
- `networking.hostName = "emmathorpe-edaas"` matches the flake attribute so
|
||||
`nh os switch` resolves without `-H`.
|
||||
|
||||
## Renovate review timer
|
||||
|
||||
The host-table entry sets `users.emmathorpe.linger = true` so the user's
|
||||
`systemd --user` instance stays alive without an open login session. That keeps
|
||||
the daily headless **Renovate PR review** timer firing — defined in
|
||||
[`../../users/emmathorpe/renovate-review.nix`](https://code.emmathe.dev/lyrathorpe/nixfiles/src/branch/main/users/emmathorpe/renovate-review.nix)
|
||||
(imported only from `work.nix`, so it exists on this machine alone). See that
|
||||
file's header for the auth (Vertex AI ADC), triage policy, and caveats.
|
||||
|
||||
## Secret Service (keychain)
|
||||
|
||||
`work.nix` sets `services.headlessSecretService.enable = true`, which runs
|
||||
`gnome-keyring` as a `systemd --user` service owning `org.freedesktop.secrets`
|
||||
on the session bus, with the login keyring unlocked at start.
|
||||
|
||||
This exists for **gcx**, the Grafana Cloud CLI. gcx stores its OAuth access and
|
||||
refresh tokens in the keychain unconditionally (its config keeps only opaque
|
||||
`keychain:gcx:v2:...` handles) and has no plaintext fallback, so without a
|
||||
Secret Service `gcx login` authenticates and then fails to persist with "The
|
||||
name is not activatable".
|
||||
|
||||
Home-manager's own `services.gnome-keyring` does not work here: it is
|
||||
`WantedBy=graphical-session-pre.target`, which never activates on this headless
|
||||
box, and it cannot unlock the keyring. See
|
||||
[`../../home/secret-service.nix`](https://code.emmathe.dev/lyrathorpe/nixfiles/src/branch/main/home/secret-service.nix) for the full
|
||||
rationale and the security trade-off of an auto-unlocked keyring.
|
||||
|
||||
Only the `secrets` component is started. The `ssh` component is deliberately off
|
||||
— it would claim `SSH_AUTH_SOCK` and displace `services.ssh-agent`, breaking SSH
|
||||
auth and signed commits.
|
||||
|
||||
Checking it:
|
||||
|
||||
```sh
|
||||
systemctl --user status headless-secret-service
|
||||
busctl --user list | grep secrets # expect org.freedesktop.secrets
|
||||
secret-tool search --all service gcx # inspect what gcx stored
|
||||
gcx config check # end-to-end
|
||||
```
|
||||
|
||||
If the keyring password is ever lost or changed, the login keyring cannot be
|
||||
unlocked: delete `~/.local/share/keyrings` and re-run `gcx login`.
|
||||
|
||||
## stateVersion
|
||||
|
||||
`system.stateVersion = "24.11"` — the release this box was first installed on.
|
||||
Leave it; it freezes stateful defaults and is not meant to track the current
|
||||
nixpkgs.
|
||||
|
||||
## Apply
|
||||
|
||||
```sh
|
||||
sudo nixos-rebuild switch --flake .#emmathorpe-edaas
|
||||
# or, since the hostname matches the attribute:
|
||||
nh os switch
|
||||
```
|
||||
@@ -0,0 +1,138 @@
|
||||
# Mac Pro 3,1 (Early 2008) — install notes
|
||||
|
||||
Flake host: `lyrathorpe-macpro31`. Desktop (`portable = false`, imports
|
||||
`../../modules/desktop.nix`). Files: `configuration.nix`, `nvidia.nix`,
|
||||
`hardware-configuration.nix`.
|
||||
|
||||
## Hardware configuration
|
||||
|
||||
`hardware-configuration.nix` here is the real config generated by
|
||||
`nixos-generate-config` on the machine. Root is an **LVM** logical volume
|
||||
(`/dev/mapper/MacPro-Root`, ext4); the ESP (vfat) and swap are referenced by
|
||||
UUID. The initrd carries `dm-snapshot` for the LVM root. Regenerate and commit
|
||||
if the disk layout changes.
|
||||
|
||||
## Bootloader
|
||||
|
||||
The Mac Pro 3,1 has **64-bit EFI**, so it uses **systemd-boot** (no GRUB/CSM
|
||||
shim). `canTouchEfiVariables = false` because Apple's firmware does not reliably
|
||||
accept `efibootmgr` NVRAM writes.
|
||||
|
||||
Apple-EFI quirk: if the firmware boot picker does not show NixOS after install,
|
||||
either
|
||||
|
||||
- uncomment `boot.loader.efi.efiInstallAsRemovable = true;` in
|
||||
`configuration.nix` (installs the fallback `\EFI\BOOT\BOOTX64.EFI`), and/or
|
||||
- "bless" the ESP from macOS.
|
||||
|
||||
Partition the disk GPT with an ESP (vfat).
|
||||
|
||||
## Graphics — NVIDIA Quadro P400
|
||||
|
||||
The stock card (**ATI Radeon HD 2600 XT** or **NVIDIA GeForce 8800 GT**,
|
||||
depending on the unit) has been replaced with an **NVIDIA Quadro P400** (Pascal,
|
||||
GP108). Everything driver-related lives in [`nvidia.nix`](https://code.emmathe.dev/lyrathorpe/nixfiles/src/branch/main/hosts/MacPro31/nvidia.nix):
|
||||
|
||||
- **Driver branch 580** (`nvidiaPackages.legacy_580`), _not_ the nixpkgs default
|
||||
(`production`, currently 595.x). 580 is the last branch that supports
|
||||
Maxwell/Pascal/Volta and is maintained as an LTS branch until Aug 2028; a
|
||||
newer branch does not drive this card at all.
|
||||
- `modesetting.enable = true` — mandatory for Wayland (sets
|
||||
`nvidia-drm.modeset=1`); without it wlroots gets no GBM device and both Sway
|
||||
and the greeter fail to start.
|
||||
- `open = false` — the open kernel modules require Turing or later.
|
||||
- Sway runs with `--unsupported-gpu` (`programs.sway.extraOptions`); wlroots
|
||||
refuses the proprietary driver otherwise. `cage`/ReGreet needs no such flag.
|
||||
- nouveau and `nvidiafb` are blacklisted automatically by the NVIDIA module.
|
||||
|
||||
The driver is unfree, so it is **not in the binary cache**: the kernel module is
|
||||
compiled on the machine, which on these 2008 Xeons is slow — budget for a long
|
||||
first rebuild and again after every kernel bump. The package names are
|
||||
allowlisted in `unfreePackages` in [`flake.nix`](https://code.emmathe.dev/lyrathorpe/nixfiles/src/branch/main/flake.nix).
|
||||
|
||||
Note the Mac Pro shows no EFI boot screen with a stock PC card (no Apple EFI
|
||||
ROM): the machine boots blind until KMS brings the display up. That is expected,
|
||||
not a fault.
|
||||
|
||||
Verify after a rebuild:
|
||||
|
||||
```sh
|
||||
nvidia-smi
|
||||
```
|
||||
|
||||
## Docker with CUDA
|
||||
|
||||
`nvidia.nix` also enables Docker and gives containers GPU access via **CDI**
|
||||
(`hardware.nvidia-container-toolkit.enable`), which generates device specs from
|
||||
the host driver at boot (regenerated by a udev rule when the `nvidia` device
|
||||
appears) and turns on the daemon's CDI feature:
|
||||
|
||||
```sh
|
||||
docker run --rm --device=nvidia.com/gpu=all nvidia/cuda:12.9.1-base-ubuntu24.04 nvidia-smi
|
||||
```
|
||||
|
||||
- Use the `--device=nvidia.com/gpu=all` form. `--gpus all` is the legacy
|
||||
runtime-wrapper path (`virtualisation.docker.enableNvidia`), which is
|
||||
deprecated upstream and deliberately not enabled here.
|
||||
- **CUDA version matters.** The P400 is compute capability 6.1 (`sm_61`); CUDA
|
||||
13 dropped Maxwell/Pascal/Volta, so container images must ship a **CUDA 12.x
|
||||
or older** runtime. The 580 driver itself is happy with either.
|
||||
- 2 GB of VRAM, 256 CUDA cores — fine for encode/decode and small models, not
|
||||
for training anything serious.
|
||||
- Docker socket is local-only (no TCP listener, unlike the Pi). Users need the
|
||||
`docker` group; the registry already grants it.
|
||||
|
||||
### "Driver Not Loaded" from the CDI generator
|
||||
|
||||
`nvidia-container-toolkit-cdi-generator.service` fails with
|
||||
`failed to initialize NVML: Driver Not Loaded` whenever the `nvidia` kernel
|
||||
module is not loaded in the **running** kernel. After a kernel bump that is
|
||||
unavoidable — the rebuilt module cannot load until reboot — so the unit is
|
||||
guarded with `ConditionPathExists=/proc/driver/nvidia/version` and skips
|
||||
instead of failing. Without that guard it also takes `docker.service`
|
||||
(`requiredBy`) with it and makes `nixos-rebuild switch` exit non-zero.
|
||||
|
||||
**Reboot after a rebuild that touches the driver or the kernel.** The toolkit's
|
||||
udev rule restarts the generator when the GPU device appears, so the CDI specs
|
||||
are written on the next boot. To check the state:
|
||||
|
||||
```sh
|
||||
lsmod | grep nvidia # nvidia, nvidia_modeset, nvidia_drm, nvidia_uvm
|
||||
cat /proc/driver/nvidia/version
|
||||
nvidia-smi
|
||||
systemctl status nvidia-container-toolkit-cdi-generator.service
|
||||
ls /var/run/cdi # the generated spec
|
||||
```
|
||||
|
||||
If the module is genuinely absent after a reboot, check `dmesg | grep -i
|
||||
nvidia` (build/version mismatch, or nouveau still bound — the module blacklists
|
||||
it, so that should not happen).
|
||||
|
||||
## Claude Code — not installed here
|
||||
|
||||
The dual Harpertown Xeons are **x86-64-v1** (SSE4.1, but no SSE4.2/POPCNT) and
|
||||
the Node runtime Claude Code ships on requires x86-64-v2. `configuration.nix`
|
||||
declares `features.cpu.microarchLevel = 1`, which switches the tool off through
|
||||
the fleet-wide gate in [`../../modules/features.nix`](https://code.emmathe.dev/lyrathorpe/nixfiles/src/branch/main/modules/features.nix)
|
||||
— see the root README. Forcing `features.claudeCode.enable` on here is an
|
||||
evaluation error, not a broken install.
|
||||
|
||||
## Networking
|
||||
|
||||
Wired Ethernet via NetworkManager (from `desktop.nix`) — the Mac Pro has two
|
||||
gigabit ports.
|
||||
|
||||
## Login
|
||||
|
||||
Graphical login via a Wayland greeter — `greetd` running ReGreet inside the
|
||||
`cage` kiosk compositor — configured centrally in `../../modules/sway.nix` for
|
||||
every Sway host (gated on `features.swayDesktop.enable`). The greeter is forced
|
||||
to the Dvorak layout to match the console and Sway session. Set the user
|
||||
password (`passwd lyrathorpe`) after install, or the greeter cannot
|
||||
authenticate. Requires working KMS (NVIDIA modesetting — see Graphics).
|
||||
|
||||
## Apply
|
||||
|
||||
```sh
|
||||
sudo nixos-rebuild switch --flake .#lyrathorpe-macpro31
|
||||
```
|
||||
@@ -0,0 +1,69 @@
|
||||
# Raspberry Pi 5 (`lyrathorpe-rpi5`)
|
||||
|
||||
Headless `aarch64-linux` server with two roles:
|
||||
|
||||
- **Docker host** — daemon exposed over the network (`docker.nix`).
|
||||
- **nginx reverse proxy** — declarative `virtualHosts` (`reverse-proxy.nix`).
|
||||
|
||||
## Install
|
||||
|
||||
1. Flash a NixOS `aarch64` SD image (or USB) and boot the Pi. The
|
||||
`raspberry-pi-5` profile from `nixos-hardware` (wired in the flake host table)
|
||||
supplies the kernel, firmware and device tree; boot is U-Boot + extlinux.
|
||||
2. Partition/mount the target, then **regenerate the hardware config on the
|
||||
device** and replace the committed placeholder:
|
||||
```sh
|
||||
nixos-generate-config --root /mnt
|
||||
# copy /mnt/etc/nixos/hardware-configuration.nix over
|
||||
# hosts/RPi5/hardware-configuration.nix in this repo, then commit
|
||||
```
|
||||
`hardware-configuration.nix` in this directory is a **placeholder** committed
|
||||
only so the host evaluates in CI. The machine will not boot correctly until it
|
||||
is replaced with the generated one.
|
||||
3. Set the host name to match the flake attribute (already done in
|
||||
`configuration.nix`: `lyrathorpe-rpi5`) and build:
|
||||
```sh
|
||||
sudo nixos-rebuild switch --flake .#lyrathorpe-rpi5
|
||||
# or, once the hostname is live:
|
||||
nh os switch
|
||||
```
|
||||
4. Give the login user a password (`passwd lyrathorpe`) and confirm the key in
|
||||
the user registry (`../../users/registry.nix`, applied by
|
||||
`../../modules/ssh.nix`) is the one you will connect with.
|
||||
|
||||
## Docker socket (security)
|
||||
|
||||
The daemon listens on **plain TCP `2375`, no TLS, no auth**. Access is
|
||||
root-equivalent on this host. The only protection is the nftables rule in
|
||||
`docker.nix`, which accepts `2375` **only** from the trusted LAN subnet
|
||||
(`10.187.1.0/24` by default — change it to match your network). Do not widen
|
||||
that subnet to anything untrusted.
|
||||
|
||||
From a LAN client:
|
||||
|
||||
```sh
|
||||
export DOCKER_HOST=tcp://lyrathorpe-rpi5:2375
|
||||
docker info
|
||||
```
|
||||
|
||||
The secure upgrade path is mutual TLS on `2376` (`--tlsverify` with a CA and
|
||||
client certs); it needs out-of-band cert provisioning and is intentionally not
|
||||
wired here.
|
||||
|
||||
## Adding a reverse-proxy site
|
||||
|
||||
Each proxied service is a Nix entry in `reverse-proxy.nix`:
|
||||
|
||||
```nix
|
||||
services.nginx.virtualHosts."app.example.lan" = {
|
||||
# enableACME = true; forceSSL = true; # once a DNS name + cert exist
|
||||
locations."/" = {
|
||||
proxyPass = "http://127.0.0.1:8080"; # e.g. a local container
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
The example vhost is HTTP-only by design. Turn on `enableACME`/`forceSSL`
|
||||
per-vhost once the host has a real DNS name and the ACME challenge can be met;
|
||||
`443` is already open in the firewall.
|
||||
@@ -0,0 +1,48 @@
|
||||
# ThinkPad T400 — install notes
|
||||
|
||||
Flake host: `lyrathorpe-t400`. Files: `configuration.nix`, the `boot-*.nix`
|
||||
variants, and `hardware-configuration.nix`.
|
||||
|
||||
## Hardware configuration
|
||||
|
||||
`hardware-configuration.nix` here is a hand-written **placeholder**. On the real
|
||||
machine, run `nixos-generate-config`, replace the file, and commit it. It assumes
|
||||
by-label partitions — root `nixos` (ext4) and `swap` — so either label them at
|
||||
install time or swap in the generated UUIDs.
|
||||
|
||||
## Bootloader — import the module matching the flashed firmware
|
||||
|
||||
`configuration.nix` imports exactly one boot module. Default is `boot-bios.nix`;
|
||||
switch by commenting it out and uncommenting the relevant alternative.
|
||||
|
||||
| Firmware | Module | Notes |
|
||||
| ---------------------------------------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Stock Lenovo BIOS, or coreboot + **SeaBIOS** payload | `boot-bios.nix` | GRUB on the MBR. Set `device` to the real install disk (`/dev/sda` by default). MBR/legacy layout. |
|
||||
| coreboot + **GRUB** payload | `boot-coreboot-grub.nix` | GRUB is config-only (`device = "nodev"`); NixOS does **not** write to a disk. Your coreboot `grub.cfg` (in the flash chip) must `search` for and `configfile` the on-disk `/boot/grub/grub.cfg`, or chainload the disk's GRUB. |
|
||||
| coreboot + **Tianocore/edk2 (UEFI)** payload | `boot-coreboot-uefi.nix` | systemd-boot. `canTouchEfiVariables = true` (coreboot honours NVRAM writes). The module **declares its own ESP** (`/boot` vfat, label `ESP`) — when you regenerate `hardware-configuration.nix`, do **not** let it also define `/boot`. Create + label an `ESP` vfat partition (GPT). |
|
||||
|
||||
## Graphics
|
||||
|
||||
This unit has the optional **discrete ATI Mobility Radeon HD 3470 (RV620)**. The
|
||||
open `radeon` KMS driver is loaded in the initrd for early modesetting; firmware
|
||||
comes from `enableRedistributableFirmware`.
|
||||
|
||||
The T400 has switchable graphics (discrete ATI + Intel GMA 4500MHD). Select
|
||||
**Discrete** in the firmware's graphics setting so only the ATI is live. If you
|
||||
run **Integrated** instead, the Intel `i915` driver takes over with no config
|
||||
change and `radeon` stays idle.
|
||||
|
||||
## Login
|
||||
|
||||
Graphical login via a Wayland greeter — `greetd` running ReGreet inside the
|
||||
`cage` kiosk compositor — configured centrally in `../../modules/sway.nix` for
|
||||
every Sway host (gated on `features.swayDesktop.enable`). The greeter is forced
|
||||
to the Dvorak layout to match the console and Sway session. Set the user
|
||||
password (`passwd lyrathorpe`) after install, or the greeter cannot
|
||||
authenticate. Requires working radeon/i915 KMS (see Graphics).
|
||||
|
||||
## Apply
|
||||
|
||||
```sh
|
||||
sudo nixos-rebuild switch --flake .#lyrathorpe-t400
|
||||
```
|
||||
Reference in New Issue
Block a user