From 9c3881951735a48002dd45e11f8bd890630a8c4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?ryan4yin=20=7C=20=E4=BA=8C=E8=8A=B1?= Date: Mon, 12 Oct 2026 10:02:38 +0800 Subject: [PATCH] docs: review and correct comments and documentation (#436) --- AGENTS.md | 2 +- Justfile | 2 +- README.md | 2 +- SECURITY.md | 40 +++++++++---------- WORKAROUNDS.md | 11 ++--- agents/README.md | 10 ++--- docs/nixos-modernization-options.md | 28 ++++++++----- hardening/README.md | 4 +- hardening/apparmor/default.nix | 2 +- hardening/bwraps/wechat.nix | 3 +- hardening/nixpaks/firefox.nix | 2 +- home/README.md | 2 +- home/base/core/editors/helix/README.md | 2 +- home/base/core/npm.nix | 2 +- home/base/tui/tuios/default.nix | 1 - home/linux/gui/base/README.md | 3 +- home/linux/gui/base/misc.nix | 4 +- home/linux/gui/base/xdg/default.nix | 2 +- hosts/12kingdoms-shoryu/preservation.nix | 8 ++-- .../hardware-configuration.nix | 3 +- .../homelab-services/disko-fs.nix | 6 +-- .../homelab-services/immich/README.md | 2 + .../homelab-services/jellyfin.nix | 8 ++-- .../homelab-services/monitoring/alert.nix | 2 +- hosts/README.md | 13 +++--- hosts/darwin-frieren/default.nix | 2 +- hosts/idols-ai/VR.md | 8 ++-- hosts/idols-ai/default.nix | 10 +++-- hosts/idols-ai/preservation.nix | 8 ++-- hosts/idols-ai/restic.nix | 3 -- hosts/idols-akane/virtfs.nix | 4 +- hosts/idols-kana/default.nix | 4 +- hosts/idols-ruby/default.nix | 4 +- hosts/idols-ruby/oci-containers/default.nix | 17 -------- hosts/k8s/k3s-test-1-master-1/default.nix | 4 +- lib/genMicrovmGuestModule.nix | 2 +- lib/genVmHostModule.nix | 10 +++-- modules/README.md | 9 +++-- modules/darwin/users.nix | 3 +- modules/nixos/base/monitoring.nix | 2 +- modules/nixos/base/ssh.nix | 2 +- modules/nixos/base/user-group.nix | 2 +- modules/nixos/base/zram.nix | 5 +-- modules/nixos/desktop.nix | 2 +- modules/nixos/desktop/security.nix | 3 +- modules/nixos/server/qemu-guest.nix | 2 - nixos-installer/README.shoukei.md | 10 +++-- outputs/README.md | 10 +++-- outputs/default.nix | 3 +- secrets/README.md | 3 +- 50 files changed, 148 insertions(+), 148 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index a1c9328b..43faa9c0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -35,7 +35,7 @@ projects live in [agents/](./agents/README.md). ## Validation - For Nix changes, run `just fmt` and inspect the diff: it formats all Nix files. Nix style is - `nixfmt` with width 100. + `nixfmt`, whose default width is 100. - For supported non-Nix files, use `prettier --write ` and `prettier --check `; configuration lives in `.prettierrc.yaml`. Spelling checks use `typos` and `.typos.toml`. - Run `just test` for configuration changes; it evaluates `.#evalTests` across Linux and Darwin and diff --git a/Justfile b/Justfile index 1f7e76c6..026e6303 100644 --- a/Justfile +++ b/Justfile @@ -125,7 +125,7 @@ verify-store: repair-store *paths: nix store repair {{paths}} -# Update all Nixpkgs inputs +# Update the secondary nixpkgs inputs (the primary `nixpkgs` needs `just up`) [group('nix')] up-nix: nix flake update --commit-lock-file nixpkgs-stable nixpkgs-master nixpkgs-darwin nixpkgs-patched diff --git a/README.md b/README.md index 89cbde66..dff50a90 100644 --- a/README.md +++ b/README.md @@ -140,7 +140,7 @@ For macOS (nix-darwin): # If you are deploying for the first time, # 1. install nix & homebrew manually. # 2. prepare the deployment environment with essential packages available -nix-shell -p just nushell +nix shell nixpkgs#just nixpkgs#nushell # 3. comment home-manager's code in lib/macosSystem.nix to speed up the first deployment. # Deploy the darwinConfiguration by hostname match (fern, frieren) diff --git a/SECURITY.md b/SECURITY.md index f3c10fa3..dff818dd 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -33,18 +33,18 @@ small, reversible controls and narrow exceptions; benchmark before adopting expe ## Architecture and trust boundaries -| Boundary | Current design | Limitation | -| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Administration | Key-based SSH; root key login retained for Colmena/MicroVM deployment | Deployment credentials are root-equivalent; password login being disabled does not restrict stolen keys | -| Host network | Shared nftables firewall trusts the home LAN, tailnet interface and local Podman bridge; IPv6 link-local is accepted | These are broad trust zones, not service-level least privilege; router exposure and tailnet ACLs require separate verification | -| Monitoring | node/smartctl exporters bind the host LAN IPv4 (9100/9633); firewall rules restrict exporter ports 9100, 9835 and 9633 to the monitoring host over IPv4 | nvidia_gpu_exporter (9835) still binds wildcard; IPv6 denial is planned in the baseline implementation; current running hosts require separate verification | -| VM hosts | shoryu, shushou and youko run guests behind `br0`; ruby/kana are libvirt guests | A bridge is not network isolation; host compromise affects its guests | -| k3s | Three control-plane and three worker MicroVMs; Cilium, API VIP and NFS CSI | Cluster-admin, privileged/host-mounted pods and writable NFS data are powerful trust boundaries | -| MicroVM storage | Host store shared read-only through virtiofs; guest `/etc`, `/var` and `/home` persisted in separate images | Read-only store does not isolate the host-side virtiofs implementation or protect writable guest state | -| Desktop apps | Selected apps use nixpak/bubblewrap; Podman is rootless | Rules and shared directories vary per app; user namespaces are needed for these sandboxes | -| Secrets | agenix declarations here, encrypted data in the private nix-secrets repository | Recipients and plaintext file permissions must be reviewed; root on a recipient can read its decrypted secrets | -| Supply chain | Locked flake inputs; explicit binary-cache trust keys; normal user is not a Nix trusted-user | A trusted cache or imported Nix module can supply code executed as root; a lock file is not a security audit | -| Recovery | NixOS generations, btrbk/restic, hourly read-only snapshots of the REST store, and documented backup procedures | A rollback does not undo compromised data or secrets; backup configuration alone does not prove restore works; the offsite immutable copy is still planned | +| Boundary | Current design | Limitation | +| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Administration | Key-based SSH; root key login retained for Colmena/MicroVM deployment | Deployment credentials are root-equivalent; password login being disabled does not restrict stolen keys | +| Host network | Shared nftables firewall trusts the home LAN, tailnet interface and local Podman bridge; IPv6 link-local is accepted | These are broad trust zones, not service-level least privilege; router exposure and tailnet ACLs require separate verification | +| Monitoring | node/smartctl exporters bind the host LAN IPv4 (9100/9633); firewall rules restrict exporter ports 9100, 9835 and 9633 to the monitoring host over IPv4 | nvidia_gpu_exporter (9835) still binds wildcard; the IPv6 denial for those three ports is in the shared firewall; current running hosts require separate verification | +| VM hosts | shoryu, shushou and youko run guests behind `br0`; ruby/kana are libvirt guests | A bridge is not network isolation; host compromise affects its guests | +| k3s | Three control-plane and three worker MicroVMs; Cilium, API VIP and NFS CSI | Cluster-admin, privileged/host-mounted pods and writable NFS data are powerful trust boundaries | +| MicroVM storage | Host store shared read-only through virtiofs; guest `/etc`, `/var` and `/home` persisted in separate images | Read-only store does not isolate the host-side virtiofs implementation or protect writable guest state | +| Desktop apps | Selected apps use nixpak/bubblewrap; Podman is rootless | Rules and shared directories vary per app; user namespaces are needed for these sandboxes | +| Secrets | agenix declarations here, encrypted data in the private nix-secrets repository | Recipients and plaintext file permissions must be reviewed; root on a recipient can read its decrypted secrets | +| Supply chain | Locked flake inputs; explicit binary-cache trust keys; normal user is not a Nix trusted-user | A trusted cache or imported Nix module can supply code executed as root; a lock file is not a security audit | +| Recovery | NixOS generations, btrbk/restic, hourly read-only snapshots of the REST store, and documented backup procedures | A rollback does not undo compromised data or secrets; backup configuration alone does not prove restore works; the offsite immutable copy is still planned | Sources: [host layout](hosts/README.md), [k3s deployment](hosts/k8s/README.md), [firewall](modules/nixos/base/networking/firewall.nix), [SSH](modules/nixos/base/ssh.nix), @@ -153,14 +153,14 @@ configuration and certificate lifecycle procedures. Never bypass TLS verificatio hostname mismatch. Eval tests protect the domain join endpoint and server SAN declarations; live TLS checks remain necessary after deployment. -## Implementation plan and completed audit findings +## Implementation status and completed audit findings ### Implementation status -| Component | Status | Runtime verification | -| ---------------------------------------------------------------- | ------------------------------------- | --------------------------------------------------- | -| Architecture, agent-first policy, audits and canonical API tests | Included in this documentation change | Only the dated observations below were checked live | -| Explicit sysctl baseline and IPv6 exporter defence | Implemented in this baseline change | Not deployed or verified on running hosts | +| Component | Status | Runtime verification | +| ---------------------------------------------------------------- | --------------------------------------- | --------------------------------------------------- | +| Architecture, agent-first policy, audits and canonical API tests | In this repository | Only the dated observations below were checked live | +| Explicit sysctl baseline and IPv6 exporter defence | In `hardening/` and the shared firewall | Not deployed or verified on running hosts | ### Baseline implementation checks @@ -168,11 +168,11 @@ checks remain necessary after deployment. - IPv6 exporter denial precedes broad LAN/tailnet/container rules. The monitoring configuration uses IPv4 targets for these ports, so no scrape endpoint migration is needed. - x86_64/aarch64 eval checks cover baseline values, normal host overrides and generated exporter - rules. Canonical API endpoint checks for all six cluster nodes already accompany this document. + rules. Canonical API endpoint checks cover all six cluster nodes. - A reusable isolated VM check exercises allowed monitoring IPv4 access, denied other IPv4/IPv6 access to all three exporter ports, retained IPv6 loopback and a reachable ordinary IPv4/IPv6 - service. Run `nix build .#checks.x86_64-linux.security-exporters`, importing only the shared - firewall, not real-host secrets or workloads, and does not replace deployment-time checks. + service. Run it with `nix build .#checks.x86_64-linux.security-exporters`. It imports only the + shared firewall, not real-host secrets or workloads, and does not replace deployment-time checks. ### Read-only audit snapshot — 2026-10-03 diff --git a/WORKAROUNDS.md b/WORKAROUNDS.md index ef7e4cd7..b4ea908e 100644 --- a/WORKAROUNDS.md +++ b/WORKAROUNDS.md @@ -48,7 +48,8 @@ A setting that works around a bug or a hardware quirk. | WA-029 | mihomo `fake-ip-range6` is `2001:2::/64`, not the shipped ULA default — `modules/nixos/desktop/networking/mihomo/generate.nu` | the default `fdfe:dcba:9876::/64` sits in `fc00::/7`, which Local Network Access calls local, so a public page loaded over the v4 fake pool and pulling a dual-stack subresource prompts for local-network access (Chrome 154, Firefox). The same range also stalled ssh: a session to a fake AAAA authenticated and then never closed, on both `gvisor` and `mips`. `2001:2::/48` is RFC 5180 benchmarking -- the v6 twin of the `198.18.0.0/15` v4 default, absent from that table -- and both symptoms went with the move | Go back to the upstream default once mihomo ships a pool outside the LNA non-public table; the ULA default brings the ssh stall back | 2026-10-09 | on a browser or mihomo bump -- that table already grew to cover `2001:db8::/32` and `198.18.0.0/15` | active | | WA-030 | mihomo unit sets `SKIP_SYSTEM_IPV6_CHECK=1` — `modules/nixos/desktop/networking/mihomo/default.nix` | mihomo checks at startup whether another NIC already holds an IPv6 address and, finding none, skips the TUN's v6 half -- but `strict-route` still installs its v6 blackhole (`ip -6 rule add priority 9000 unreachable`). On a cold boot that rule lands before networkd's Router Solicitation is answered, so the host can never send RS/NS, never gets a GUA, and mihomo never re-checks: self-locking until the core restarts. The env var forces the TUN v6 address up, which installs mihomo's normal v6 rules whose `lookup main suppress_prefixlength 0` keeps on-link neighbor discovery and the RA default route off the TUN | Drop once mihomo either re-runs the IPv6 check or skips the v6 strict-route blackhole when the v6 TUN is disabled | 2026-10-10 | on a mihomo bump | active | -If WA-008 freezes recur, the fallback is to restore +If WA-008 freezes recur, the fallback is to restore the parameters commented out in +`hosts/idols-ai/hardware-configuration.nix` — `nvme_core.default_ps_max_latency_us=0 nvme_core.io_timeout=4294967295 pcie_aspm=off`; this is a recovery procedure, not its removal condition. @@ -71,10 +72,10 @@ A known limitation with no fix yet. An unfinished feature or gap. -| ID | What & where | Why | Removal condition | Added | Revisit | Status | -| ------ | --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | ---------- | ----------------------- | ------ | -| WA-013 | NixOS tests — `outputs/README.md` | full-host tests still rebuild custom packages (no private cache) and need the host ssh key to decrypt agenix; the shared-firewall security-exporters VM test now runs in CI (KVM) | Resolve when a private cache exists and tests can run per-service | 2024-03-13 | quarterly | active | -| WA-027 | NFS golden store `no_root_squash` — `hosts/12kingdoms-youko/nfs-golden.nix` | the existing PVC subdirectories are root-owned, so enabling `root_squash` would break running workloads until they are migrated; the CSI node plugin is hostNetwork and sources from the allowlisted node IPs | Drop when the PVC subdirectories are migrated and `root_squash` is enabled | 2026-10-07 | next maintenance window | active | +| ID | What & where | Why | Removal condition | Added | Revisit | Status | +| ------ | --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------- | ---------- | ----------------------- | ------ | +| WA-013 | NixOS tests — `outputs/README.md` | full-host tests still rebuild custom packages (no private cache) and need the host ssh key to decrypt agenix; the shared-firewall security-exporters VM test now runs in CI (KVM); `outputs/x86_64-linux/nixos-tests/idols-ruby.nix` is exposed as `packages.x86_64-linux.ruby-nixos-tests` but is not in `checks` or CI | Resolve when a private cache exists and tests can run per-service | 2024-03-13 | quarterly | active | +| WA-027 | NFS golden store `no_root_squash` — `hosts/12kingdoms-youko/nfs-golden.nix` | the existing PVC subdirectories are root-owned, so enabling `root_squash` would break running workloads until they are migrated; the CSI node plugin is hostNetwork and sources from the allowlisted node IPs | Drop when the PVC subdirectories are migrated and `root_squash` is enabled | 2026-10-07 | next maintenance window | active | ## Related diff --git a/agents/README.md b/agents/README.md index fb79e976..899f43df 100644 --- a/agents/README.md +++ b/agents/README.md @@ -102,11 +102,11 @@ recorded in [#428](https://github.com/ryan4yin/nix-config/pull/428). door, and blast radius for PR bodies. - **Write a `testing-strategy` skill**: E2E of real workflows first, unit tests for logic and edge cases E2E cannot reach. -- **Merge `ponytail-review` with a comment and doc pruning pass** (reference: - `MidAutumnMoon/TaysiTsuki` `home/agents/skills/prune-comments-and-docs`). Worth borrowing from - `garrytan/gstack` `review/checklist.md`: a critical pass before an informational one, reading - consumers outside the diff for a new enum value or loosened validator, a do-not-flag list, and - "zero findings is valid". Keep review report-only. +- **Merge `ponytail-review` into the shipped `review-comments-and-docs` skill** (its doc-pruning + half came from `MidAutumnMoon/TaysiTsuki` `home/agents/skills/prune-comments-and-docs`). Worth + borrowing from `garrytan/gstack` `review/checklist.md`: a critical pass before an informational + one, reading consumers outside the diff for a new enum value or loosened validator, a do-not-flag + list, and "zero findings is valid". Keep review report-only. - **Adapt `wayfinder` in the fork** so its map and tickets default to local Markdown and research stays local, instead of GitHub issues and pushed `research/` branches. - **Adapt `domain-modeling` in the fork** to record decisions in the repository's existing documents diff --git a/docs/nixos-modernization-options.md b/docs/nixos-modernization-options.md index 85a99eb5..e7b0f320 100644 --- a/docs/nixos-modernization-options.md +++ b/docs/nixos-modernization-options.md @@ -25,7 +25,7 @@ repository already runs** or **unlocks a concrete need**. "It exists and is newe ## A1. Tailscale Serve instead of caddy vhosts -**Current:** one caddy instance on `youko` fronts 12 vhosts on `*.writefor.fun` by Host/SNI, with +**Current:** one caddy instance on `youko` fronts 17 vhosts on `*.writefor.fun` by Host/SNI, with two TLS chains — a private `ecc-ca` (only repo machines trust it) and a lego/Cloudflare DNS-01 wildcard for phone/TV clients — plus `file_server`, `header_up Host` (SigV4), a wildcard 404 fallback, and a root-readable Cloudflare token in agenix. @@ -56,8 +56,9 @@ LAN-only client can run Tailscale. ## A2. systemd-resolved -**Current:** `services.resolved.enable` is set **nowhere**; hosts use dhcpcd or static config and -the default `/etc/resolv.conf`. Note `modules/nixos/base/networking/mdns.nix` already sets +**Current:** `services.resolved.enable` is set **nowhere**; hosts get DNS from systemd-networkd or +NetworkManager (or static config) and use the default `/etc/resolv.conf`. Note +`modules/nixos/base/networking/mdns.nix` already sets `services.resolved.settings.Resolve.MulticastDNS = false` — currently inert, and it will activate the moment resolved is enabled. mDNS itself is provided by avahi. @@ -83,14 +84,16 @@ changes. ## A3. systemd-networkd instead of dhcpcd -**Current:** physical hosts use `networking.useDHCP` (dhcpcd script); VM hosts and MicroVM guests -use static config with `useDHCP = false`; the `br0` bridge on VM hosts is declared through +**Current:** dhcpcd is not used anywhere in this repo. `ai`, `kana` and `ruby` already set +`networking.useNetworkd = true`; `shoukei` and `akane` run NetworkManager; VM hosts and MicroVM +guests use static config with `useDHCP = false`. The `br0` bridge on VM hosts is declared through `systemd.network.netdevs/networks` already. **Proposed:** `networking.networkd.enable = true` with `networking.networks`/`networkdOptions`. **Pros:** declarative per-interface config, one implementation for stage 1 and stage 2, no dhcpcd -shell script in the path, and VM hosts already speak `systemd.network` for the bridge. +anywhere in the path (nothing in this repo uses it), and VM hosts already speak `systemd.network` +for the bridge. **Cons:** bigger blast radius than any other item — a mistake on a `br0` VM host cuts the guests and possibly remote reachability; migration touches every DHCP host; behaviour differences around @@ -152,8 +155,10 @@ the gain over a working `zramSwap` is mostly cosmetic. ## A6. nixos-facter instead of hand-written hardware-configuration.nix -**Current:** 8 hosts carry hand-written `hardware-configuration.nix` (plus deliberate per-host -quirks such as the NVMe APST workaround WA-008 and USB-SATA mitigations WA-009). +**Current:** 3 hosts carry hand-written `hardware-configuration.nix` (`shoryu`, `shoukei`, `ai`; +`shushou` and `youko` import `shoryu`'s, and the qemu guests use the shared +`modules/nixos/server/qemu-guest-hardware-configuration.nix`), plus deliberate per-host quirks such +as the NVMe APST workaround WA-008 and USB-SATA mitigations WA-009. **Proposed:** `hardware.facter` from nixpkgs (nixos-facter-modules upstreamed), report generated on the machine. @@ -294,8 +299,9 @@ validates); no benefit for hosts without Secure Boot. ## B3. Declarative images with systemd-repart -**Current:** guest images come from the existing pipeline (nixos-generators / disko-based); k8s -guests are MicroVMs booting declared state images. +**Current:** libvirt guest images are one-time reflink copies of the VMs' former KubeVirt disks +(`hosts/12kingdoms-shoryu/libvirtd.nix`); k8s guests are MicroVMs booting declared state images +against a read-only host store, with no OS image built at all. **Proposed:** `image.repart.enable` + `system.build.images.{qemu,raw-efi,raw,sd-card}`. @@ -479,7 +485,7 @@ only. | B5 | sysupdate | | | | | B6 | measured boot / FIDO2 | | | | | B7 | systemd-vmspawn | | | | -| C1–C4 | tooling + cleanups | | | | +| C1–C5 | tooling + cleanups | | | | | D1–D7 | lab-only group | | | | | E | rejected set | | | | diff --git a/hardening/README.md b/hardening/README.md index 6a161f8d..cedff97f 100644 --- a/hardening/README.md +++ b/hardening/README.md @@ -72,8 +72,8 @@ hardening/ - https://gitlab.com/apparmor/apparmor/-/wikis/Documentation - AppArmor.d is a set of over 1500 AppArmor profiles whose aim is to confine most Linux based applications and processes. - - But all the profiles of AppArmor assume a FHS filesystem, which caused all apparmor policies - takes no effect on NixOS. + - But its profiles assume an FHS filesystem, so most of them never match the Nix store paths a + NixOS system actually executes. - Apparmor on NixOS Roadmap: - https://discourse.nixos.org/t/apparmor-on-nixos-roadmap/57217 - https://github.com/LordGrimmauld/aa-alias-manager diff --git a/hardening/apparmor/default.nix b/hardening/apparmor/default.nix index f75b6ce3..0e0aa503 100644 --- a/hardening/apparmor/default.nix +++ b/hardening/apparmor/default.nix @@ -3,7 +3,7 @@ ... }: { - # AppArmor in complain mode: log violations instead of blocking. + # AppArmor policy for D-Bus. services.dbus.apparmor = "enabled"; security.apparmor = { diff --git a/hardening/bwraps/wechat.nix b/hardening/bwraps/wechat.nix index ca6bab09..7b0105a4 100644 --- a/hardening/bwraps/wechat.nix +++ b/hardening/bwraps/wechat.nix @@ -36,7 +36,8 @@ appimageTools.wrapAppImage { substituteInPlace $out/share/applications/wechat.desktop --replace-fail AppRun wechat ''; - # Add these root paths to FHS sandbox to prevent WeChat from accessing them by default + # Prepare the WeChat data dirs before the sandbox starts. The isolation itself + # is the `--tmpfs /home` / `--tmpfs /root` in `extraBwrapArgs` below. # Adapted from https://aur.archlinux.org/cgit/aur.git/tree/wechat-universal.sh?h=wechat-universal-bwrap extraPreBwrapCmds = '' XDG_DOCUMENTS_DIR="''${XDG_DOCUMENTS_DIR:-$(xdg-user-dir DOCUMENTS)}" diff --git a/hardening/nixpaks/firefox.nix b/hardening/nixpaks/firefox.nix index f84e4a03..266e4d90 100644 --- a/hardening/nixpaks/firefox.nix +++ b/hardening/nixpaks/firefox.nix @@ -78,7 +78,7 @@ let # Shared NSS client-certificate store (imported outside Firefox). (sloth.concat' sloth.homeDir "/.pki/nssdb") - # Unsure + # dconf settings. Not verified as needed; candidate for removal. (sloth.concat' sloth.xdgConfigHome "/dconf") ]; }; diff --git a/home/README.md b/home/README.md index 607aab6b..77a2392d 100644 --- a/home/README.md +++ b/home/README.md @@ -15,7 +15,7 @@ home/ │ │ └── ... │ └── ... ├── hosts/ # Host-specific home manager entry modules -│ ├── linux/ # Linux host home modules (idols-ai, 12kingdoms-shoukei, idols-kana, idols-ruby, k3s-test-1-worker-*, etc.) +│ ├── linux/ # Linux host home modules (idols-ai, 12kingdoms-shoukei, idols-kana, idols-ruby) │ └── darwin/ # macOS host home modules (fern, frieren) └── darwin/ # macOS-specific home manager configurations ├── proxy/ # Proxy configurations diff --git a/home/base/core/editors/helix/README.md b/home/base/core/editors/helix/README.md index b6907b81..3a5d4c96 100644 --- a/home/base/core/editors/helix/README.md +++ b/home/base/core/editors/helix/README.md @@ -38,7 +38,7 @@ Run `:tutor` inside Helix, or `hx --tutor` from the shell ### Terminal related -tuios shortcuts used often (leader is `Ctrl + B`; same idea as in the Neovim notes): +tuios shortcuts used often (leader is `Ctrl + B`): | Action | tuios shortcut | | ----------------- | -------------------------- | diff --git a/home/base/core/npm.nix b/home/base/core/npm.nix index 8d3c8f04..7c3806eb 100644 --- a/home/base/core/npm.nix +++ b/home/base/core/npm.nix @@ -7,7 +7,7 @@ min-release-age=2 ''; - # npm - set min release age (in minutes) for supply-chain security + # pnpm - same supply-chain policy as the npm setting above; its value is in minutes, not days xdg.configFile."pnpm/config.yaml".text = '' minimumReleaseAge: 2880 ''; diff --git a/home/base/tui/tuios/default.nix b/home/base/tui/tuios/default.nix index 2f874b8d..b7035e6d 100644 --- a/home/base/tui/tuios/default.nix +++ b/home/base/tui/tuios/default.nix @@ -22,7 +22,6 @@ in # `work` for the ~/work tree, `personal` for everything else (a host with no # ~/work gets `personal` everywhere). programs.nushell.extraConfig = '' - # auto start tuios if $nu.is-interactive and (not ("TUIOS_SESSION" in $env)) { # Exit 3 means the daemon is stopped; stdout still lists saved sessions. let listing = (^tuios ls --json | complete) diff --git a/home/linux/gui/base/README.md b/home/linux/gui/base/README.md index 66755ef0..c689e1a1 100644 --- a/home/linux/gui/base/README.md +++ b/home/linux/gui/base/README.md @@ -83,8 +83,7 @@ Noctalia consolidates functionality that previously required multiple tools: - **[`desktop-tools.nix`](./desktop-tools.nix)**: Wayland session tools (clipboard, brightness, screen recording, auto-mount, virt-manager/virt-viewer, `wlogout` emergency fallback) - **[`browsers.nix`](./browsers.nix)**: Web browsers -- **[`vscode.nix`](./vscode.nix)**: VS Code (GUI editor; the primary Zed config is shared from - [`home/base/gui/zed-editor.nix`](../../../base/gui/zed-editor.nix)) +- **[`vscode.nix`](./vscode.nix)**: VS Code - **[`media.nix`](./media.nix)**: Media players - **[`gaming.nix`](./gaming.nix)**: Gaming applications - **[`creative.nix`](./creative.nix)**: Creative software diff --git a/home/linux/gui/base/misc.nix b/home/linux/gui/base/misc.nix index c8c3d312..0d31bf5e 100644 --- a/home/linux/gui/base/misc.nix +++ b/home/linux/gui/base/misc.nix @@ -20,8 +20,8 @@ # discord # update too frequently, use the web version instead ]; - # allow fontconfig to discover fonts and configurations installed through home.packages - # Install fonts at system-level, not user-level + # Fonts install at system level, not user level, so fontconfig does not + # scan home.packages for them. fonts.fontconfig.enable = false; } diff --git a/home/linux/gui/base/xdg/default.nix b/home/linux/gui/base/xdg/default.nix index 935371b7..3d00be70 100644 --- a/home/linux/gui/base/xdg/default.nix +++ b/home/linux/gui/base/xdg/default.nix @@ -1,4 +1,4 @@ -# XDG stands for "Cross-Desktop Group", with X used to mean "cross". +# XDG stands for "X Desktop Group", the former name of freedesktop.org. # It's a bunch of specifications from freedesktop.org intended to standardize desktops and # other GUI applications on various systems (primarily Unix-like) to be interoperable: # https://www.freedesktop.org/wiki/Specifications/ diff --git a/hosts/12kingdoms-shoryu/preservation.nix b/hosts/12kingdoms-shoryu/preservation.nix index 11daf975..c94fce40 100644 --- a/hosts/12kingdoms-shoryu/preservation.nix +++ b/hosts/12kingdoms-shoryu/preservation.nix @@ -88,13 +88,11 @@ in "/home/${username}/.terraform.d".d = permission; }; - # systemd-machine-id-commit.service would fail but it is not relevant - # in this specific setup for a persistent machine-id so we disable it - # - # see the firstboot example below for an alternative approach + # Mask the commit service: /etc/machine-id is persisted by preservation + # (see the `files` entry above), so there is no transient ID to commit. systemd.suppressedSystemUnits = [ "systemd-machine-id-commit.service" ]; - # let the service commit the transient ID to the persistent volume + # Inert while the unit is masked above; kept as the alternative approach. systemd.services.systemd-machine-id-commit = { unitConfig.ConditionPathIsMountPoint = [ "" diff --git a/hosts/12kingdoms-shoukei/hardware-configuration.nix b/hosts/12kingdoms-shoukei/hardware-configuration.nix index 699d56dc..dbb1de44 100644 --- a/hosts/12kingdoms-shoukei/hardware-configuration.nix +++ b/hosts/12kingdoms-shoukei/hardware-configuration.nix @@ -47,7 +47,8 @@ in }) ]; - # supported file systems, so we can mount any removable disks with these filesystems + # supported file systems, so we can mount any removable disks with these filesystems. + # mkForce replaces the whole list, so entries added by any other module are lost here. boot.supportedFilesystems = lib.mkForce [ "ext4" "btrfs" diff --git a/hosts/12kingdoms-youko/homelab-services/disko-fs.nix b/hosts/12kingdoms-youko/homelab-services/disko-fs.nix index bf58417e..488d989f 100644 --- a/hosts/12kingdoms-youko/homelab-services/disko-fs.nix +++ b/hosts/12kingdoms-youko/homelab-services/disko-fs.nix @@ -57,10 +57,10 @@ in keyFile = cryptKeyFile; # The maximum size of the keyfile is 8192 KiB # type `cryptsetup --help` to see the compiled-in key and passphrase maximum sizes - # to generate a key file: + # The key file must be at least keyFileOffset + keyFileSize bytes. # dd bs=512 count=1024 iflag=fullblock if=/dev/random of=./hdd-luks-crypt-key - keyFileSize = 512 * 64; # match the `bs * count` of the `dd` command - keyFileOffset = 512 * 128; # match the `bs * skip` of the `dd` command + keyFileSize = 512 * 64; + keyFileOffset = 512 * 128; fallbackToPassword = true; allowDiscards = true; }; diff --git a/hosts/12kingdoms-youko/homelab-services/immich/README.md b/hosts/12kingdoms-youko/homelab-services/immich/README.md index f4fdfe66..7b4893f0 100644 --- a/hosts/12kingdoms-youko/homelab-services/immich/README.md +++ b/hosts/12kingdoms-youko/homelab-services/immich/README.md @@ -95,6 +95,8 @@ document is the agreed design and the rationale. ## Rollout +Applied — immich runs on youko. The steps below are the procedure as deployed: + 1. `../valkey.nix`: the shared Valkey instance. 2. `./default.nix`: the `services.immich` configuration (server, database, machine-learning, tmpfiles). diff --git a/hosts/12kingdoms-youko/homelab-services/jellyfin.nix b/hosts/12kingdoms-youko/homelab-services/jellyfin.nix index ad621c3c..ce486f81 100644 --- a/hosts/12kingdoms-youko/homelab-services/jellyfin.nix +++ b/hosts/12kingdoms-youko/homelab-services/jellyfin.nix @@ -30,15 +30,15 @@ in # HDR/DoVi transcoding needs OpenCL for `tonemap_opencl`. With only Mesa # installed, ffmpeg cannot create an OpenCL device (`Failed to get number of # OpenCL platforms: -1001`) and the transcode aborts with exit code 237, so - # HDR titles fail to play. ROCm's clr provides the ICD for the Barceló iGPU - # (reported as `gfx90c`); `ocl-icd` finds it under + # HDR titles fail to play. ROCm's clr provides the ICD for the AMD Radeon iGPU + # (Vega, `gfx90c`); `ocl-icd` finds it under # /run/opengl-driver/etc/OpenCL/vendors. hardware.graphics.extraPackages = [ pkgs.rocmPackages.clr.icd ]; services.jellyfin = { enable = true; - # AMD Barceló iGPU: VA-API hardware transcoding. renderD128 is world + # AMD Radeon iGPU (Vega, `gfx90c`): VA-API hardware transcoding. renderD128 is world # readable/writable, and the user is in `render`/`video` as well. hardwareAcceleration = { enable = true; @@ -55,7 +55,7 @@ in # for decode/scale and falls back to the CPU `libx264`, which pins # several cores per stream. enableHardwareEncoding = true; - # Vega (Barceló) decodes these. + # Vega decodes these. hardwareDecodingCodecs = { h264 = true; hevc = true; diff --git a/hosts/12kingdoms-youko/homelab-services/monitoring/alert.nix b/hosts/12kingdoms-youko/homelab-services/monitoring/alert.nix index f39bbf49..fa2c49c4 100644 --- a/hosts/12kingdoms-youko/homelab-services/monitoring/alert.nix +++ b/hosts/12kingdoms-youko/homelab-services/monitoring/alert.nix @@ -119,7 +119,7 @@ chat_id = 586169186; # My Telegram ID # Whether to notify about resolved alerts. send_resolved = true; - # Disable notifications for resolved alerts + # Not disabled: resolved alerts are still notified (see send_resolved). disable_notifications = false; # Telegram's MarkdownV2 & Markdown are all very painful, we use html instead. # https://core.telegram.org/bots/api#formatting-options diff --git a/hosts/README.md b/hosts/README.md index ad7d89e6..2bdfea89 100644 --- a/hosts/README.md +++ b/hosts/README.md @@ -20,9 +20,9 @@ Named after characters from "Oshi no Ko": On 2026-04-27 `ai` was rebuilt on a new platform. The MSI board and i5-13600KF it was added with in 2023-05 (the host was originally named `msi-rtx4090`) gave way to the Colorful CVN Z890 ARK FROZEN + Intel Core Ultra 7 270K Plus. The traces in the history are PR #257 (the NIC moved from `enp5s0` to -`enp130s0`) and PR #258 (Niri output names renamed, `hardware-intel.nix` added with the Arrow Lake -NPU, kernel moved to `linuxPackages_latest`). The 2×48G DDR5 kit was already in place at that point; -the repo has no record of when it went in. +`enp130s0`) and PR #258 (Niri output names renamed, `hardware-intel.nix` added). The kernel moved to +`linuxPackages_latest` in `77ca37ea`, the same day but outside #258. The 2×48G DDR5 kit was already +in place at that point; the repo has no record of when it went in. On 2026-10-06 `ai` grew from 2×48G (96G) to 2×48G + 2×16G (128G) across all four DIMM slots, at DDR5-4800 with XMP off — the only stable setting with four DIMMs on this board. The 16G pair must be @@ -71,7 +71,8 @@ disks. #### `k8s` - Kubernetes Infrastructure -- **VM Cluster**: 3 physical mini PCs (shoryu, shushou, youko) running all VMs +- **VM Cluster**: 3 physical mini PCs (shoryu, shushou, youko) run the k3s VMs; `akane` is a NixOS + VM under UTM on macOS - **K3s Testing**: `k3s-test-1` control plane and workers, running as microVMs; placement and rollout are documented in [`k8s/README.md`](./k8s/README.md) @@ -122,8 +123,8 @@ just build-host ``` `eval-host` only evaluates the configuration. `build-host` builds the system closure without -activating it. Host activation remains an explicit Colmena operation such as `just shoryu`, -`just shushou`, or `just youko`. +activating it. Host activation is always explicit: Colmena (`just shoryu`, `just shushou`, +`just youko`) from another machine, or `just local` on the machine itself. ## Distributed Building diff --git a/hosts/darwin-frieren/default.nix b/hosts/darwin-frieren/default.nix index 07790a55..45304c70 100644 --- a/hosts/darwin-frieren/default.nix +++ b/hosts/darwin-frieren/default.nix @@ -1,7 +1,7 @@ { pkgs, ... }: ############################################################# # -# Fern - MacBook Pro 2024 14-inch M4 Pro 48G, mainly for business. +# Frieren - MacBook Pro 2024 14-inch M4 Pro 48G, mainly for business. # ############################################################# let diff --git a/hosts/idols-ai/VR.md b/hosts/idols-ai/VR.md index c6ec6235..7c330ff7 100644 --- a/hosts/idols-ai/VR.md +++ b/hosts/idols-ai/VR.md @@ -6,10 +6,10 @@ to run, but compatibility still depends on the game and translation layer. ## First activation and persistence -Run `just niri` on idols-ai from this branch's worktree, or after merging it. Log out and back in so -Steam sees `PRESSURE_VESSEL_IMPORT_OPENXR_1_RUNTIMES=1`. That variable is what makes pressure-vessel -mount WiVRn's `$XDG_RUNTIME_DIR/wivrn/comp_ipc` socket into a game's container; without it the -game's OpenXR client fails with `ERROR_RUNTIME_UNAVAILABLE` and the headset stays black. +Run `just niri` on idols-ai. Log out and back in so Steam sees +`PRESSURE_VESSEL_IMPORT_OPENXR_1_RUNTIMES=1`. That variable is what makes pressure-vessel mount +WiVRn's `$XDG_RUNTIME_DIR/wivrn/comp_ipc` socket into a game's container; without it the game's +OpenXR client fails with `ERROR_RUNTIME_UNAVAILABLE` and the headset stays black. The root filesystem is a 4 GiB tmpfs. These directories are preserved with mode 0700: diff --git a/hosts/idols-ai/default.nix b/hosts/idols-ai/default.nix index d712300b..7f498dad 100644 --- a/hosts/idols-ai/default.nix +++ b/hosts/idols-ai/default.nix @@ -41,7 +41,8 @@ in ]; # Zram consumes physical memory for compression, which can cause a deadlock and system hang if the model size approaches the physical memory limit. - # Disable the whole module (zram device + its swappiness=180 sysctl tunings); this host uses a disk swapfile instead. + # Disable the whole module (zram device + its swappiness=180 sysctl tunings); this host uses a + # disk swapfile instead, created by disko at /swap (see ./disko-fs.nix). The two must move together. modules.zram.enable = false; # zswap: compressed writeback cache in front of the disk swapfile. @@ -93,8 +94,9 @@ in networking = { inherit hostName; - # we use networkd instead - networkmanager.enable = false; # provides nmcli/nmtui for wifi adjustment + # off: this host uses networkd (below). NetworkManager would otherwise + # provide nmcli/nmtui for wifi adjustment. + networkmanager.enable = false; useDHCP = false; }; @@ -117,7 +119,7 @@ in ]; DNS = nameservers; DHCP = "ipv6"; # enable DHCPv6 only, so we can get a GUA. - IPv6AcceptRA = true; # for Stateless IPv6 Autoconfiguraton (SLAAC) + IPv6AcceptRA = true; # for Stateless IPv6 Autoconfiguration (SLAAC) LinkLocalAddressing = "ipv6"; # r8169 drops carrier on S3 resume; without this, networkd tears down the # static address/route and mihomo's TUN auto-detect briefly loses its diff --git a/hosts/idols-ai/preservation.nix b/hosts/idols-ai/preservation.nix index ff511043..7ef5b566 100644 --- a/hosts/idols-ai/preservation.nix +++ b/hosts/idols-ai/preservation.nix @@ -469,13 +469,11 @@ in "D! /var/lib/systemd/coredump 0755 root root" ]; - # systemd-machine-id-commit.service would fail but it is not relevant - # in this specific setup for a persistent machine-id so we disable it - # - # see the firstboot example below for an alternative approach + # Mask the commit service: /etc/machine-id is persisted by preservation + # (see the `files` entry above), so there is no transient ID to commit. systemd.suppressedSystemUnits = [ "systemd-machine-id-commit.service" ]; - # let the service commit the transient ID to the persistent volume + # Inert while the unit is masked above; kept as the alternative approach. systemd.services.systemd-machine-id-commit = { unitConfig.ConditionPathIsMountPoint = [ "" diff --git a/hosts/idols-ai/restic.nix b/hosts/idols-ai/restic.nix index 47cc6dcd..840cca30 100644 --- a/hosts/idols-ai/restic.nix +++ b/hosts/idols-ai/restic.nix @@ -3,9 +3,6 @@ ... }: { - # Part 1 of the backup plan: a local restic repository on this machine. - # The off-machine target (youko, or a cloud) is a later step. - # # Be specific here and keep `exclude` minimal: an allowlist of the # irreplaceable directories beats backing up a broad tree and excluding half # of it. Large files anywhere are skipped by size (excludeLargerThan), which diff --git a/hosts/idols-akane/virtfs.nix b/hosts/idols-akane/virtfs.nix index 6da0d91f..7ea7c43c 100644 --- a/hosts/idols-akane/virtfs.nix +++ b/hosts/idols-akane/virtfs.nix @@ -11,8 +11,8 @@ "auto" # Mount automatically with -a # Ownership mapping - all files appear as specified user/group - "uid=1000" # Map to user ID 1000 - "gid=1000" # Map to group ID 100 + "uid=1000" + "gid=1000" ]; }; } diff --git a/hosts/idols-kana/default.nix b/hosts/idols-kana/default.nix index 593de470..f4bd793e 100644 --- a/hosts/idols-kana/default.nix +++ b/hosts/idols-kana/default.nix @@ -52,10 +52,12 @@ in matchConfig.Name = [ iface ]; networkConfig = { Address = [ ipv4WithMask ]; + # DNS goes to the proxy gateway, which resolves through the proxy; + # `nameservers` is the plain upstream-DNS alternative. # DNS = nameservers; DNS = [ proxyGateway ]; DHCP = "ipv6"; # enable DHCPv6 only, so we can get a GUA. - IPv6AcceptRA = true; # for Stateless IPv6 Autoconfiguraton (SLAAC) + IPv6AcceptRA = true; # for Stateless IPv6 Autoconfiguration (SLAAC) LinkLocalAddressing = "ipv6"; }; routes = [ diff --git a/hosts/idols-ruby/default.nix b/hosts/idols-ruby/default.nix index cded3243..cd150a3a 100644 --- a/hosts/idols-ruby/default.nix +++ b/hosts/idols-ruby/default.nix @@ -61,10 +61,12 @@ in matchConfig.Name = [ iface ]; networkConfig = { Address = [ ipv4WithMask ]; + # DNS goes to the proxy gateway, which resolves through the proxy; + # `nameservers` is the plain upstream-DNS alternative. # DNS = nameservers; DNS = [ proxyGateway ]; DHCP = "ipv6"; # enable DHCPv6 only, so we can get a GUA. - IPv6AcceptRA = true; # for Stateless IPv6 Autoconfiguraton (SLAAC) + IPv6AcceptRA = true; # for Stateless IPv6 Autoconfiguration (SLAAC) LinkLocalAddressing = "ipv6"; }; routes = [ diff --git a/hosts/idols-ruby/oci-containers/default.nix b/hosts/idols-ruby/oci-containers/default.nix index 14e90caa..3ecb1f0e 100644 --- a/hosts/idols-ruby/oci-containers/default.nix +++ b/hosts/idols-ruby/oci-containers/default.nix @@ -7,25 +7,8 @@ { imports = mylib.scanPaths ./.; - # environment.systemPackages = with pkgs; [ - # podman-compose - # ]; - virtualisation = { docker.enable = true; - # podman = { - # enable = true; - # # Create a `docker` alias for podman, to use it as a drop-in replacement - # dockerCompat = true; - # # Required for containers under podman-compose to be able to talk to each other. - # defaultNetwork.settings.dns_enabled = true; - # # Periodically prune Podman resources - # autoPrune = { - # enable = true; - # dates = "weekly"; - # flags = [ "--all" ]; - # }; - # }; oci-containers = { backend = "docker"; diff --git a/hosts/k8s/k3s-test-1-master-1/default.nix b/hosts/k8s/k3s-test-1-master-1/default.nix index 38c31f94..dc47ace7 100644 --- a/hosts/k8s/k3s-test-1-master-1/default.nix +++ b/hosts/k8s/k3s-test-1-master-1/default.nix @@ -31,8 +31,8 @@ let # k3sExtraArgs = [ # # IPv4 Private CIDR(full) - 172.16.0.0/12 - # # IPv4 Pod CIDR(full) - fdfd:cafe:00:0000::/64 ~ fdfd:cafe:00:7fff::/64 - # # IPv4 Service CIDR(full) - fdfd:cafe:00:8000::/64 ~ fdfd:cafe:00:ffff::/64 + # # IPv6 Pod CIDR(full) - fdfd:cafe:00:0000::/64 ~ fdfd:cafe:00:7fff::/64 + # # IPv6 Service CIDR(full) - fdfd:cafe:00:8000::/64 ~ fdfd:cafe:00:ffff::/64 # "--cluster-cidr=172.18.0.0/16,fdfd:cafe:00:0002::/64" # "--service-cidr=172.19.0.0/16,fdfd:cafe:00:8002::/112" # ]; diff --git a/lib/genMicrovmGuestModule.nix b/lib/genMicrovmGuestModule.nix index 878e990d..6ef903e5 100644 --- a/lib/genMicrovmGuestModule.nix +++ b/lib/genMicrovmGuestModule.nix @@ -9,7 +9,7 @@ etcSize ? 64, varSize ? 4096, homeSize ? 4096, - # extra stateful mounts (e.g. aquamarine's /data on the passed-through HDDs) + # extra stateful mounts, e.g. a guest's /data on passed-through HDDs extraVolumes ? [ ], ... }: diff --git a/lib/genVmHostModule.nix b/lib/genVmHostModule.nix index a1d62d0a..66973dc0 100644 --- a/lib/genVmHostModule.nix +++ b/lib/genVmHostModule.nix @@ -23,9 +23,10 @@ in "nfs" ]; - # KVM for the microVMs and the libvirt domains. + # KVM for the microVMs and the libvirt domains. AMD-specific: an Intel VM host + # would need kvm-intel instead (see hosts/idols-ai/hardware-intel.nix). boot.kernelModules = [ "kvm-amd" ]; - boot.extraModprobeConfig = "options kvm_amd nested=1"; # for amd cpu + boot.extraModprobeConfig = "options kvm_amd nested=1"; boot.kernel.sysctl = { # --- filesystem --- # @@ -92,10 +93,11 @@ in matchConfig.Name = [ "br0" ]; networkConfig = { Address = [ ipv4WithMask ]; - # DNS = nameservers; + # DNS goes to the proxy gateway, which resolves through the proxy; plain + # upstream DNS would be myvars.networking.nameservers. DNS = [ proxyGateway ]; DHCP = "ipv6"; # enable DHCPv6 only, so we can get a GUA. - IPv6AcceptRA = true; # for Stateless IPv6 Autoconfiguraton (SLAAC) + IPv6AcceptRA = true; # for Stateless IPv6 Autoconfiguration (SLAAC) LinkLocalAddressing = "ipv6"; }; routes = [ diff --git a/modules/README.md b/modules/README.md index ea008e9e..0895930d 100644 --- a/modules/README.md +++ b/modules/README.md @@ -102,8 +102,9 @@ Platform-specific NixOS configuration: ## Usage -Modules are imported based on platform detection: +There is no automatic platform detection. Each host's entry under `outputs//src/` lists its +imports explicitly: -- **NixOS Systems**: Import `nixos/` modules -- **macOS Systems**: Import `darwin/` modules -- **All Systems**: Import `base/` modules for shared configuration +- **NixOS Systems**: import `nixos/` modules +- **macOS Systems**: import `darwin/` modules +- **Both**: import `base/` modules for shared configuration diff --git a/modules/darwin/users.nix b/modules/darwin/users.nix index b41fe706..8c4daf5f 100644 --- a/modules/darwin/users.nix +++ b/modules/darwin/users.nix @@ -4,8 +4,7 @@ users.users."${myvars.username}" = { home = "/Users/${myvars.username}"; - # set user's default shell back to zsh - # `chsh -s /bin/zsh` + # The login shell is set imperatively (`chsh -s /bin/zsh`), not declaratively here. # DO NOT change the system's default shell to nushell! it will break some apps! # It's better to change only kitty/wezterm & other terminal emulator's shell to nushell! }; diff --git a/modules/nixos/base/monitoring.nix b/modules/nixos/base/monitoring.nix index e058c00b..e8a89d02 100644 --- a/modules/nixos/base/monitoring.nix +++ b/modules/nixos/base/monitoring.nix @@ -14,7 +14,7 @@ let lanAddr = if hostAddr.homeOnly or false then null else hostAddr.ipv4 or null; in { - # enable the node exporter on all nixos hosts + # node_exporter on every host that has a static LAN IPv4 (see `lanAddr` above) # https://github.com/NixOS/nixpkgs/blob/nixos-26.05/nixos/modules/services/monitoring/prometheus/exporters/node.nix services.prometheus.exporters.node = lib.mkIf (lanAddr != null) { enable = true; diff --git a/modules/nixos/base/ssh.nix b/modules/nixos/base/ssh.nix index 2775bc2b..28d77a6a 100644 --- a/modules/nixos/base/ssh.nix +++ b/modules/nixos/base/ssh.nix @@ -11,7 +11,7 @@ # Secure by default: X11 forwarding off everywhere; desktops re-enable it # in modules/nixos/desktop/ssh.nix (needed for GUI forwarding). X11Forwarding = lib.mkDefault false; - # root user is used for remote deployment, so we need to allow it + # root login stays available for Colmena/MicroVM deployment, keys only PermitRootLogin = lib.mkDefault "prohibit-password"; PasswordAuthentication = false; # disable password login }; diff --git a/modules/nixos/base/user-group.nix b/modules/nixos/base/user-group.nix index 7e6642e7..02360106 100644 --- a/modules/nixos/base/user-group.nix +++ b/modules/nixos/base/user-group.nix @@ -29,7 +29,7 @@ # misc uinput = { }; # shared group for services that read/write the same data directory - # (e.g. sftpgo + transmission on aquamarine) + # (e.g. sftpgo + transmission on youko) fileshare = { }; }; diff --git a/modules/nixos/base/zram.nix b/modules/nixos/base/zram.nix index 1ee4b6e9..78950e5d 100644 --- a/modules/nixos/base/zram.nix +++ b/modules/nixos/base/zram.nix @@ -54,9 +54,8 @@ in "vm.watermark_boost_factor" = lib.mkDefault 0; # vm.watermark_scale_factor - Controls kswapd wakeup frequency (range: 1-1000, default: 10) - # A higher value triggers background memory reclamation earlier (at 12.5% memory pressure). - # Value 125 means kswapd becomes active when free memory drops below 1/125 of total memory, - # balancing memory more proactively to prevent sudden swap storms at high swappiness values. + # Units are 1/10000 of total memory: the value below widens the low-to-min watermark gap and + # makes kswapd reclaim earlier, which avoids swap storms at the high swappiness above. "vm.watermark_scale_factor" = lib.mkDefault 125; # vm.page-cluster - Controls swap readahead (range: 0-6, default: 3) diff --git a/modules/nixos/desktop.nix b/modules/nixos/desktop.nix index f98c6444..74f1e572 100644 --- a/modules/nixos/desktop.nix +++ b/modules/nixos/desktop.nix @@ -46,7 +46,7 @@ in enable = true; settings = { default_session = { - # Wayland Desktop Manager is installed only for user ryan via home-manager! + # The Wayland session is installed for this user only, via home-manager. user = myvars.username; # .wayland-session is a script generated by home-manager, which links to the current wayland compositor(sway/hyprland or others). # with such a vendor-no-locking script, we can switch to another wayland compositor without modifying greetd's config here. diff --git a/modules/nixos/desktop/security.nix b/modules/nixos/desktop/security.nix index 8458e520..1d5248c4 100644 --- a/modules/nixos/desktop/security.nix +++ b/modules/nixos/desktop/security.nix @@ -9,7 +9,8 @@ # security with gnome-kering services.gnome = { gnome-keyring.enable = true; - # Use gnome keyring's SSH Agent + # Not gcr's SSH agent: OpenSSH's own agent runs instead + # (programs.ssh.startAgent below). # https://wiki.gnome.org/Projects/GnomeKeyring/Ssh gcr-ssh-agent.enable = false; }; diff --git a/modules/nixos/server/qemu-guest.nix b/modules/nixos/server/qemu-guest.nix index ac5aed2c..79ce6e61 100644 --- a/modules/nixos/server/qemu-guest.nix +++ b/modules/nixos/server/qemu-guest.nix @@ -10,8 +10,6 @@ # # We write our hardware-configuration.nix, so that we can do some customization more easily. # -# the url above is used by `nixos-generator` to generate the guest's qcow2 image file. -# ############################################################################## { imports = [ diff --git a/nixos-installer/README.shoukei.md b/nixos-installer/README.shoukei.md index 7cfa3d55..3d8766de 100755 --- a/nixos-installer/README.shoukei.md +++ b/nixos-installer/README.shoukei.md @@ -249,8 +249,8 @@ cd ~/nix-config/nixos-installer/ rm -rf /mnt/etc # install nixos -# NOTE: --no-root-password leaves root locked; log in as ryan with the password from -# vars/default.nix +# NOTE: --no-root-password leaves root locked; log in as ryan with the password whose hash is +# `initialHashedPassword` in vars/default.nix nixos-install --root /mnt --flake .#shoukei --no-root-password --show-trace --verbose # install-1 # if you want to use a cache mirror, run this command instead @@ -259,7 +259,8 @@ nixos-install --root /mnt --flake .#shoukei --no-root-password --show-trace --ve # enter into the installed system, check password & users # `su ryan` => `sudo -i` => enter ryan's password => successfully login -# if login failed, check ryan's initial password in vars/default.nix, and try again +# if login failed, check that the password you typed is the one hashed by +# `initialHashedPassword` in vars/default.nix, and try again nixos-enter @@ -327,7 +328,8 @@ cd ~/nix-config just niri ``` -Finally, to enable secure boot, follow the instructions in +Secure Boot is not configured for `shoukei` (Apple Silicon, Asahi firmware). The links below are the +setup for `ai`, kept here as a reference: [lanzaboote - Quick Start](https://github.com/nix-community/lanzaboote/blob/master/docs/QUICK_START.md) and [hosts/idols-ai/secureboot.nix](https://github.com/ryan4yin/nix-config/blob/main/hosts/idols-ai/secureboot.nix) diff --git a/outputs/README.md b/outputs/README.md index daa4882e..e9e6cb01 100644 --- a/outputs/README.md +++ b/outputs/README.md @@ -44,7 +44,8 @@ suite passes when every `expr` equals its `expected`. #### Which tests cover a new host Some tests iterate over every configuration, so a new host is covered automatically and must satisfy -them. Others name specific hosts and only cover a new host if you add it. +them. Others name specific hosts — or a name prefix, like `k3s-api-endpoint`, which covers every +`k3s-test-1-*` configuration — and only cover a new host if you add it. | Kind | Tests | | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | @@ -71,8 +72,11 @@ Problems: agenix secrets. - [ ] Maybe it's better to test every service separately, not the whole host? -No host defines a NixOS integration test yet: full-host tests are tracked as WA-013 in -[WORKAROUNDS.md](../WORKAROUNDS.md). What runs today is the eval set above, with `just test`. +Full-host tests are tracked as WA-013 in [WORKAROUNDS.md](../WORKAROUNDS.md). +`outputs/x86_64-linux/nixos-tests/idols-ruby.nix` is exported as +`packages.x86_64-linux.ruby-nixos-tests`, but it is not a `checks` entry, so CI never builds it and +nothing else runs it. What runs today is the eval set above with `just test`, plus one NixOS-driver +check of the shared firewall — `checks.x86_64-linux.security-exporters`, built in CI. ## Overview diff --git a/outputs/default.nix b/outputs/default.nix index e450c3c6..1c902eb0 100644 --- a/outputs/default.nix +++ b/outputs/default.nix @@ -142,7 +142,8 @@ in # Packages packages = forAllSystems (system: allSystems.${system}.packages or { }); - # Eval Tests for all NixOS & darwin systems. + # Eval Tests for all NixOS & darwin systems. Each system's `evalTests` lists its + # failures, so an empty attrset means that system passed. evalTests = lib.lists.all (it: it.evalTests == { }) allSystemValues; checks = forAllSystems ( diff --git a/secrets/README.md b/secrets/README.md index b48980f7..176ef185 100644 --- a/secrets/README.md +++ b/secrets/README.md @@ -65,7 +65,8 @@ Placing a secret under `/etc/agenix/` with `environment.etc` has one trap: setti `environment.etc` **copy** the file instead of symlinking it, and the copy is owned by root unless `user` is set too. Widening the mode so the user can read a root-owned copy makes it readable by every local account. Always set `user` together with `mode`. nix-darwin ignores both on -`environment.etc`, so `secrets/darwin.nix` chowns `/etc/agenix/*` after activation instead. +`environment.etc`, so `secrets/darwin.nix` re-applies each secret's owner and mode after activation; +a blanket chown over `/etc/agenix/*` would make the root-only secrets readable by the login user. ## Adding or Updating Secrets