systemd-resolved only uses LLMNR for single-label hostnames, never DNS —
same issue mount-data.nix already documented and fixed for NFS by switching
to server.sweet.home. Change the substituter URL, SSH knownHosts, and
remote-builder hostName from bare "nix-cache" to "nix-cache.sweet.home",
and update nginx's virtualHost to match.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
variables.nix's nixCacheHostKey no longer matched nix-cache's actual SSH
host key (confirmed via ssh-keyscan against the live container), so every
declaratively-configured client's programs.ssh.knownHosts trusted the
wrong key -- distributed builds would fail host-key verification. Also,
modules/nix-cache/remote-builder-client.nix hardcoded sshKey to
/root/.ssh/nixremote, but the `server` host only has its own default
/root/.ssh/id_ed25519 installed (confirmed live via qm guest-agent) --
that file was never even present, so the build machine config pointed at
nothing. Standardize on each client's own default identity, matching the
per-host-key pattern vars.remoteBuilderAuthorizedKeys already uses instead
of a shared/differently-named keypair, and add
scripts/secrets/sync-nix-cache-host-key.sh (wired into
codex-maintenance.sh's --check) so the host-key drift doesn't silently
recur next time nix-cache is rebuilt or recreated.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V7yVH71vGrDVzovh9UaMu8
Distributed builds failed with "Host key verification failed" on any
client that had never manually SSH'd to nix-cache before, since
nothing populated root's known_hosts for it. Wire nix-cache's host
public key into programs.ssh.knownHosts via a new vars.nixCacheHostKey
so every client picks it up automatically on rebuild.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
nix-serve's secretKeyFile was a manual, undocumented-outside-a-comment
`nix-store --generate-binary-cache-key` step per host -- easy to miss on
a fresh nix-cache instance (as lxc-nix-cache testing just found: systemd
fails the unit with EXIT_CREDENTIALS when LoadCredential can't find the
source file, which nginx then reports as a 502 from clients). It also
can't be regenerated per-host safely: modules/nix-cache/client.nix
hardcodes every client's trust in one specific public key, so every
nix-cache instance has to share the exact same keypair.
Sourced from secrets/nix-cache.yaml's new cache-priv-key entry instead,
via the same sops-nix pattern every other secret in this repo already
uses. Verified the added value derives to the exact public key
modules/nix-cache/client.nix already trusts before committing.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01La55Nsss8jZ7ZuzUV9mfot
Adds nested vars.nfsShares (subpath + mountpoint per dataset, previously
duplicated independently across server.nix's NFS exports, mount-data.nix's
client mounts, docker.nix's tmpfiles rules, traefik's log rotation path,
and hosts/server/host.nix's beszel config), vars.ports (every literal port
in modules/ and hosts/, kept as separate entries per service even where
numbers coincide so changing one can't silently change another), plus
vars.proxmoxImageSize, vars.nixCacheGcMaxAge, vars.traefikLogRotate, and
raspberryPiHost/raspiNfsPath/raspiMountpoint for the Pi's own NFS export.
Also fixes docker.nix/minimal.nix/gui.nix hardcoding the literal "nixos"
username instead of the existing vars.primaryUser, found during the sweep.
system.stateVersion is deliberately left untouched everywhere -- per
NixOS's own docs that value must stay fixed from first install, not
follow any shared variable.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01La55Nsss8jZ7ZuzUV9mfot
Zero W20 (repeated attribute keys), W10 (empty { ... }: variadic
pattern, use _: instead), and W04 (a = x.a instead of inherit)
warnings remain anywhere in the tree, and nixpkgs-fmt --check is
clean on all 46 .nix files.
Repeated-key merges go as deep as statix actually flags per file
(e.g. boot.loader.* nested under boot.loader = { ... } once the
outer boot.* merge exposed it as its own repeat) — every merge is a
pure attribute-path restructuring with no value changes, verified by
comparing config.system.build.toplevel.drvPath before/after for a
representative host per changed module plus a full 19-host + 4-package
eval sweep.
One indentation slip caught and fixed during this pass: nesting
modules/installer/common.nix's environment.etc."auto-install.sh".text
under an environment = { ... } block initially normalized the
script's shebang/set line indentation, which actually changes the
rendered file (Nix's '' string dedent treats it as real content, not
cosmetic whitespace) — reproduced the original's exact indentation
and reverified the rendered script is byte-identical to before.
modules/services/zfs/auto-mount-volumes.nix picked up formatting too;
worth noting it isn't imported by anything in this flake at all.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01La55Nsss8jZ7ZuzUV9mfot
Several single-purpose modules sat at modules/ root or in the
services/ catch-all despite the repo's established pattern of one
directory per concern (tailscale/, beszel/, docker/, nix-cache/):
- remote-builder-client.nix -> nix-cache/ (always co-included with
nix-cache/client.nix in flake.nix's mkTarget, same buildType guard)
- set-locale.nix -> common/ (unconditionally imported by
common/configuration.nix already)
- enable-ip-forwarding.nix -> networking/
- rotate-traefik-logs.nix -> traefik/rotate-logs.nix
- services/docker-health-to-gotify.nix and services/nextcloud-cron-job.nix
-> docker/ (both only ever imported by the docker build type, same
as the rest of modules/docker/*)
Pure path moves plus import-path updates in flake.nix,
common/configuration.nix, and build-types/docker.nix — verified
eval-equivalent (drvPath-identical) across representative hosts.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01La55Nsss8jZ7ZuzUV9mfot
Pulls the beszel hub / PVE / PBS ports, the docker-compose host's LAN
name, and the remote-builder client SSH keys out of scattered inline
literals across modules/hosts and into variables.nix as the single
source of truth, matching the existing pattern for other cross-host
references (nixCacheHost, nfsServerHost).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01La55Nsss8jZ7ZuzUV9mfot
One file (variables.nix) holding every value that was previously
hardcoded and repeated across modules: LAN domain/CIDR, home/tailnet
domains, cross-host references (nix-cache substituter hostname, NFS
server hostname, remote-builder user), PXE/PBS IPs, timezone, and the
primary username.
Wired in via flake.nix's specialArgs (and home-manager's
extraSpecialArgs for the two home.nix files), so any module picks it
up by just adding `vars` to its function arguments — no explicit
import needed. Two hosts (nix-cache, server) now derive their own
networking.hostName from the same variable other hosts use to reach
them, so there's exactly one place to change either identifier.
Purely mechanical: every substituted value matches what was already
there, confirmed by identical toplevel .drv paths for all 17 targets
before and after.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>