Commit Graph
740 Commits
Author SHA1 Message Date
Ryan Yin c8bbeb708d refactor(overlays): get NUR packages from the nur-ryan4yin overlay
myNurPkgs evaluated a second nixpkgs just for four packages. Apply the
NUR repo's own overlay instead, so they come from the host's pkgs.

Darwin's pkgs now gets nixpkgsConfig too: it set nixpkgs.pkgs, which
ignores nixpkgs.config, so only myNurPkgs carried the npm mirror there.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 11:55:14 -06:00
Ryan Yin 70d8bd6791 refactor(shoukei): drop dead nettle and qemu-user static overlays
Both only touch pkgsStatic builds, which nothing on this host pulls in
since qemu-user binfmt was removed; the toplevel drvPath is unchanged.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 11:55:14 -06:00
Ryan Yin eaa53004e5 fix(aquamarine): install only clr's OpenCL ICD instead of the openvino-gpu wrapper
hardware.amdgpu.opencl.enable also adds clr, whose OpenCL 2.2 libOpenCL.so.1
lands in /run/opengl-driver/lib, first in OpenVINO's RUNPATH, and shadows the
ocl-icd loader the GPU plugin links. With clr.icd alone the plugin finds
ocl-icd, so the wrapper and WA-038 go.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 11:55:14 -06:00
Ryan Yin b063feca29 chore(youko): drop victoriametrics' leftover data-dir group
The data dir is the module's own DynamicUser StateDirectory (already
/var/lib/victoriametrics -> private/victoriametrics on youko), so the
victoriametrics-data group, its tmpfiles rule and SupplementaryGroups
did nothing. stateDir was set to its default.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 11:42:57 -06:00
Ryan Yin 64c465660c refactor(youko): create the /data-ro mountpoints in initrd tmpfiles
Root is tmpfs, so the backing dirs must exist before the /data bind
mounts. initrd tmpfiles rules on /sysroot do that before switch-root,
replacing the activation script.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 11:42:57 -06:00
Ryan Yin 6fa6e6626e refactor(youko): run homepage from the native NixOS module
services.homepage-dashboard runs the nixpkgs package with DynamicUser,
replacing the :latest container, its system user and the activation
script that rsynced the YAML into place. The YAML stays as is and is
linked into /etc/homepage-dashboard.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 11:42:57 -06:00
Ryan Yin c8d8b17a27 refactor(youko): link caddy's wallpapers with tmpfiles
A tmpfiles L+ symlink to the store path replaces the activation script
that rsynced it on every switch. Files that were removed upstream no
longer linger.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 11:42:57 -06:00
Ryan Yin 5c9bb6f95f chore(shoryu): drop the libvirt default-network oneshot
NixOS's libvirtd-config copies default.xml but never creates its
autostart link, and shoryu has no networks/autostart directory at all,
so virbr0 never starts and the oneshot had nothing to disable.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 11:42:57 -06:00
Ryan Yin f520c992d5 refactor(youko): order transmission-netns after the br0 device
Replace the 30 s `ip link show br0` poll with BindsTo/After on
sys-subsystem-net-devices-br0.device.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 11:42:57 -06:00
Ryan Yin 8d32297dcd refactor(ai): reset the Insta360 Link on resume via a usbcore quirk
USB_QUIRK_RESET_RESUME ("b") makes usbcore reset the camera instead of
resuming it, and uvcvideo implements reset_resume, so the resume hook
that ran usbreset after S3 is no longer needed.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 11:42:57 -06:00
Ryan Yin 8084f25e6f refactor(youko): disable HDD spindown from a udev rule
Apply hdparm -B 255 -S 0 whenever a disk appears, which also covers the
re-add after a bridge reset, instead of a boot oneshot plus an hourly
timer. Drop -J 0: hdparm has always aborted it without
--please-destroy-my-drive, and wdidle3 already reads disabled on both
disks (it is persistent firmware state).

This was the last user of mylib.systemdHardening.privilegedOneshot, so
remove the preset and its test group.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 11:42:57 -06:00
Ryan Yin 42341491f3 refactor(shoukei): cap battery charging from a udev rule
macsmc-battery's "add" uevent fires before the supply accepts writes
(power_supply_register bumps use_cnt after device_add); its deferred
register work then emits "change". Match both instead of polling for 30 s
from a oneshot.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 11:42:57 -06:00
Ryan Yin ecf242d6ab refactor(aquamarine): cap the R9700 power limit from a udev rule
amdgpu registers power1_cap with its hwmon device, so a rule on each
card's hwmon add event replaces the oneshot that polled /sys/class/hwmon
for 60 s waiting for both cards to probe.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 11:42:57 -06:00
Ryan Yin 201070155a fix(homepage): drop the weather providers block that never worked
A 2024 formatter pass turned `{{…}}` into a YAML flow map, the variable
was never passed to the container, and no widget uses it.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 10:51:51 -06:00
Ryan Yin 32620ed9db chore(aquamarine): drop pcie_aspm=off
It was a precaution for the R9700 links, never an observed problem, and
on BIOS 1013 the FADT already disables ASPM ("ACPI FADT declares the
system doesn't support PCIe ASPM"), so the parameter did nothing.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 10:51:51 -06:00
Ryan Yin dd2bd44bc2 fix(youko): apply /data tmpfiles in a pass of their own
89d7a9bd made systemd-tmpfiles-setup RequiresMountsFor the five nofail
USB-disk mounts. One failed mount then skipped every tmpfiles rule on the
host, and sysinit.target waited for the disks and the LUKS unlock even on
success.

Leave the boot-wide pass as upstream ships it and add data-tmpfiles:
`systemd-tmpfiles --prefix=/data` with WantsMountsFor on the /data mounts,
ordered before the services that use them.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 10:51:51 -06:00
Ryan Yin e4c2548a93 refactor: replace redundant mkForce with plain values and mkDefault
Each of these overrode a value nothing else set at a higher priority:

- qemu-guest: btrbk, hardwareTools and cloud-init have no competing
  definition on the guests.
- mdns: nixpkgs' sunshine module sets avahi.publish.* with mkDefault.
- computer-use: i18n now sets the time zone with mkDefault.
- darwin terminal: the shared ghostty/kitty font sizes are now mkDefault.
- shoukei: sunshine is mkDefault false in remote-desktop.nix, zram's
  memoryPercent is mkDefault 50; supportedFilesystems now merges instead
  of discarding the fsType entries other modules add.
- youko: nothing enables docker.
- nixpak: pasta.enable and sockets.pipewire are mkDefault in the shared
  modules, sockets.pulse already was.

Every NixOS host's toplevel drvPath is unchanged; on fern and frieren the
terminal font sizes and time zone evaluate to the same values.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 10:14:27 -06:00
Ryan Yin a5fac14ab3 docs(workarounds): drop WA-034, removed with the gateway's fake-IP IPv6
bb899876 moved the proxy gateway to fake-IP for IPv6 and removed
aquamarine's getaddrinfo precedence table, so the row's removal condition
has been met since 2026-10-14; only the row and a comment pointer lingered.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 10:14:27 -06:00
Ryan Yin f7a92ac704 chore(nvme): drop default_ps_max_latency_us=100000, the kernel default
drivers/nvme/host/core.c defaults default_ps_max_latency_us to 100000, so
the "relaxed" APST cap on ai and its copy on aquamarine set the value the
kernel already uses. Keep ai's history and rollback recipe as a comment,
and stop the aquamarine pcie_aspm=off comment from citing WA-008, which
never covered it. Removes WA-008.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 10:14:27 -06:00
Ryan Yin b5c573592b chore(ai): drop the nvidia-drm.fbdev kernel param the module already sets
hardware.nvidia.modesetting.enable makes nixpkgs' nvidia module add
nvidia-drm.modeset=1 and, for drivers >= 545, nvidia-drm.fbdev=1 to
moduleParams, which reach modprobe via extraModprobeConfig (evaluated:
"options nvidia-drm fbdev=1 modeset=1" on ai with 595.x).

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 10:14:27 -06:00
ryan4yin | 二花 5c4318b2c9 feat(aquamarine): suspend after idle & wake-on-lan (#503) 2026-11-01 23:28:47 +08:00
ryan4yin | 二花 0888f87075 feat(power): monitor homelab power and reduce aquamarine idle draw (#501)
Assisted-by: DeepSeek Harness (deepseek-flash)
2026-11-01 20:53:41 +08:00
Ryan Yin a97400df69 fix(systemd): sandbox privileged hardware oneshots
Assisted-by: DeepSeek Harness (deepseek-flash)
2026-11-01 20:49:51 +08:00
Ryan Yin e0cb3eab75 fix(grafana): restore datasources and GPU power metric
Assisted-by: DeepSeek Harness (deepseek-flash)
2026-11-01 20:49:05 +08:00
ryan4yin | 二花 bc0df6a800 fix(openrgb): apply declarative off profile at boot (#502)
Assisted-by: DeepSeek Harness (deepseek-flash)
2026-11-01 20:31:02 +08:00
ryan4yin | 二花 f3b741f5a0 feat(builders): enable aquamarine on remaining physical hosts (#500)
Enable the existing remote-builder module on shoryu, shushou and
youko, and authorize their SSH host keys on aquamarine.

Kana and Ruby are VM guests with no need to build; leave their local
store and build behavior unchanged.

Assisted-by: DeepSeek Harness (deepseek-flash)
2026-11-01 04:44:43 -06:00
ryan4yin | 二花 58d1af8f9d feat(youko): add pull-through cache for two Nix upstreams (#499)
Run nginx on youko as a loopback pull-through HTTP cache for
cache.nixos.org and cache.numtide.com, exposed by Caddy at
https://nix-cache.writefor.fun.

Assisted-by: DeepSeek Harness (deepseek-flash)
2026-11-01 18:27:43 +08:00
ryan4yin | 二花 89d7a9bd82 fix(youko): wait for data mounts before tmpfiles setup (#498)
systemd-tmpfiles-setup only orders itself after local-fs.target, but the nofail /data submounts can complete later. It then sees /data as the read-only fallback tmpfs and fails to create the Transmission, Immich, RustFS and restic directories at boot.

Add RequiresMountsFor for the data mounts and cover the generated unit dependency with an eval test.
2026-11-01 16:36:00 +08:00
Ryan Yin 56edac8252 fix(transmission): grant the AppArmor lock permission
nixpkgs' transmission 4.1.4 profile grants rw on the daemon's config directory
but not k, while 4.1.4 takes a fcntl lock on
~/.config/transmission-daemon/lock, so the daemon exited at startup with
"Another process is already using". Include rwk for that one file only.

WA-044, drop once the nixpkgs profile carries the permission.

Assisted-by: Claude Code (claude-opus-5-5)
2026-10-31 01:09:16 +08:00
Ryan Yin 560a6cc2d8 fix(preservation): mount /etc/ssh in initrd so key changes apply on boot
NixOS copies mode-carrying /etc entries such as authorized_keys.d during
stage-2 activation, which runs before systemd starts. preservation mounted the
persisted /etc/ssh from preservation.target afterwards and hid that copy, so a
key change only took effect on `switch`: revoking a key and rebooting silently
restored the old one.

Prepare the mount in initrd, before activation runs, and cover it with a VM
test that seeds a stale authorized_keys file, reboots, and asserts the declared
key replaced it. The same test fails on that assertion with inInitrd disabled.

Verified on all four hosts: /persistent/etc/ssh/authorized_keys.d/root is now
rewritten at boot instead of keeping the timestamp of the last switch.

Assisted-by: Claude Code (claude-opus-5-5)
2026-10-31 01:09:16 +08:00
Ryan Yin 7dc4e7a39f feat(security): harden homelab SSH, services and audit trail
The homelab hosts accept root SSH with long-lived file keys, run several
exposed services with almost no systemd sandboxing, and keep no audit trail of
privileged actions. Close those three gaps, weighing each measure against its
cost instead of adopting a policy wholesale.

SSH
- Turn off KbdInteractiveAuthentication: nixpkgs defaults it to true and PAM
  then still accepts the Unix password despite PasswordAuthentication = false.
- authorizedKeysInHomedir = false: only keys declared in Nix take effect;
  youko keeps Gitea's forced-command file through `Match User gitea`.
- Pin aquamarine's passphrase-free remote-builder keys to
  `restrict,command="nix-daemon --stdio --store daemon"`, so builds run in the
  system daemon instead of an audited root login session.

systemd sandboxing
- Add the mylib.systemdHardening preset and apply it to the exposed, weakly
  sandboxed services: caddy 7.8 -> 1.5, vmalert 8.2 -> 1.4, rustfs 6.6 -> 1.4,
  whisper-asr 7.7 -> 1.6. An eval test pins the key restrictions.
- Rejected: a global all-keys policy (<=0.2 score gains on services nixpkgs
  already sandboxes) and per-service confinement (bind paths to maintain).

auditd on all four hosts, reusing nixpkgs' loader and unit
- Audit login sessions only: a first `-a never,task -F auid=unset` rule keeps
  services out of the per-syscall audit path. A compromised service is
  therefore unrecorded until it opens a session.
- Record root commands, credential and host-key access, writes to SSH, account,
  PAM, Nix-trust and audit configuration, module loads and session denials.
- Rejected: global denial logging, service-UID watches and
  --loginuid-immutable (the kernel already records loginuid changes).

Verified on all four hosts after deployment: zero failed units, k3s 6/6 Ready,
and the exposed services healthy.

Assisted-by: Claude Code (claude-opus-5-5)
2026-10-31 01:09:15 +08:00
Ryan Yin def7d8f754 feat(niri): enable on-demand VRR for games
Turn on adaptive sync at the output only when a game window opts in, keeping desktop compositing fixed-rate to avoid idle/low-load VRR flicker. The Steam/Proton game rule enables VRR alongside the fullscreen rule.

Assisted-by: DeepSeek Harness (deepseek-flash)
2026-10-30 00:47:51 +08:00
ryan4yin | 二花 e8e9691f2d chore(nix): update nixpkgs to e62746b and refresh flake inputs (#488)
* chore(nix): update nixpkgs to e62746b and fix 26.11 breakage

Bump nixpkgs to e62746b and preservation to 00be7f7, then adapt to the removals and renamed options in the new revision: drop the removed boot.initrd.systemd.enable settings, trim the stale emSign CA blacklist on Linux while keeping it for the older Darwin input, and migrate Avahi publishing to settings.publish. Work around sunshine still setting the legacy Avahi options and keep dsh-nu on its tested Nushell 0.115.1. Patch NUR dsh's pnpm call to pass nodejs = null, and update pyclipsync for the stdenv.hostPlatform.system rename.

* chore(nix): refresh flake inputs for 26.11

- update nixpkgs-darwin to the same e62746b revision as nixpkgs
- make dsh-nu follow main nixpkgs and patch its testedWith manifest for the resolved Nushell
- refresh floating inputs; update lanzaboote, tuios, and ponytail
- drop the nixpkgs-2505 and rust-overlay workarounds
- keep pyclipsync on main and simplify the cross-platform CA blacklist
- adopt home-manager's Nushell loadSessionVariables default

* fix(gitea): use ROOT_URL for nixpkgs 26.11

nixpkgs removed the legacy settings.server.DOMAIN option; the existing ROOT_URL already carries the public URL.

* chore(nix): update dsh-nu to 0.7.0

Assisted-by: DeepSeek Harness (deepseek-flash)
2026-10-30 00:39:01 +08:00
Ryan Yin 01d2e76410 chore(secrets): refresh mysecrets and follow agenix-rules rename
Update the mysecrets lock to 7f93490, which renames secrets.nix to agenix-rules.nix, drops the deprecated ./ key prefixes for agenix 0.18, and re-encrypts the access-token secret. Update the docs and agenix skill to the new filename and path convention.
2026-10-29 21:28:08 +08:00
Ryan Yin add8ad9796 chore(home): remove VS Code 2026-10-28 13:51:16 +08:00
Ryan Yin bd41cca5c6 fix(grafana): correct alertmanager dashboard description typo 2026-10-28 13:51:16 +08:00
Ryan Yin b334336cd9 feat: idols-ai - persistent ~/models 2026-10-24 17:16:20 +08:00
Ryan Yin 5088535ac3 fix(ai): bind the nvidia GPU exporter to the static LAN IPv4
The 2026-10-22 audit found the live socket on *:9835: #373 bound
node/smartctl in monitoring.nix, but the nvidia exporter enabled in
hardware-nvidia.nix kept the nixpkgs default, so the socket-level
defence-in-depth layer never existed for 9835.

Extend the security-exporters eval check to every enabled exporter's
listenAddress so a future exporter without a bind fails the test.

Assisted-by: DeepSeek Harness (gpt-6-astra)
2026-10-24 14:16:14 +08:00
Ryan Yin f564807ac5 fix(preservation): persist OpenRGB settings and profiles
Assisted-by: DeepSeek Harness (gpt-6-astra)
2026-10-23 11:29:45 +08:00
Ryan Yin d421a89bd9 fix(tailscale): drop a duplicate CLI install and a stale comment
Assisted-by: DeepSeek Harness 0.2.1-rc.2 (deepseek-flash)
2026-10-22 00:54:27 +08:00
Ryan Yin 9b68cfdb8a feat(backup): alert when the last successful backup goes stale
The backup unit publishes `restic_backup_last_success_timestamp_seconds` for the node_exporter textfile collector, and a rejected alert now fails the notify unit instead of exiting 0.

Assisted-by: DeepSeek Harness 0.2.1-rc.2 (deepseek-flash)
2026-10-22 00:54:27 +08:00
ryan4yin | 二花 de6a66ccd4 fix(microvm): run k3s guests from their nixosConfigurations entry (#483)
Assisted-by: DeepSeek Harness 0.2.1-rc.2 (claude-opus-5-5)
2026-10-21 21:32:56 +08:00
Ryan Yin 1324131c6d docs: correct statements that no longer match the configuration
Assisted-by: DeepSeek Harness 0.2.1-rc.2 (claude-opus-5-5)
2026-10-21 20:59:07 +08:00
Ryan Yin 92f59df25a fix(youko): date restic store snapshots by name, not mtime
On its next run the unit deletes every snapshot whose name stamp is older than 14 days, whatever
its mtime.

Assisted-by: DeepSeek Harness 0.2.1-rc.2 (claude-opus-5-5)
2026-10-21 20:59:07 +08:00
Ryan Yin a8d47e30cf fix(ai): pin the 4K monitor at 144 Hz and record the OSD wake workaround
The DPMS wake failure is the monitor no-signal auto power-off (HPD cycling during idle), not the refresh rate: the 120 Hz pin did not fix it. Disabled in the OSD and recorded as WA-041; pin 144.000 explicitly so niri stops silently falling back.

Assisted-by: DeepSeek Harness (deepseek-flash)
2026-10-21 13:56:01 +08:00
Ryan Yin 169a87f3b9 fix(ai): pin the 4K monitor to its real 120 Hz mode
The 4090 reports the panel 120 Hz mode as 119.880, not 120, so niri fell back to 144 Hz; that DSC link stays dark after a DPMS wake.

Assisted-by: DeepSeek Harness (deepseek-flash)
2026-10-21 12:03:40 +08:00
ryan4yin | 二花 274590df63 feat(aquamarine): track linuxPackages_latest (#478)
Assisted-by: DeepSeek Harness (deepseek-flash)
2026-10-20 23:12:37 +08:00
Ryan Yin 58334d86b3 fix(microvm): pass myNurPkgs into the k3s guests
The guest configurations import modules/base/overlays.nix, whose overlays
require myNurPkgs, so every VM host failed to evaluate its microVM definitions.

Assisted-by: DeepSeek Harness 0.2.1-rc.2 (deepseek-flash)
2026-10-20 00:24:08 +08:00
ryan4yin | 二花 d5fac4bcce fix(ai): bound niri's NVIDIA free-buffer pool (#477)
* fix(ai): bound niri's NVIDIA free-buffer pool

Assisted-by: DeepSeek Harness 0.2.1-rc.2 (deepseek-flash)

* docs(ai): trim the niri VRAM workaround comment

Assisted-by: DeepSeek Harness 0.2.1-rc.2 (deepseek-flash)
2026-10-19 01:15:54 +08:00
Ryan Yin 2a792a643f fix(ai): reclaim page cache before the desktop's anon pages
Assisted-by: DeepSeek Harness 0.2.1-rc.2 (deepseek-flash)
2026-10-18 22:05:03 +08:00