Commit Graph
544 Commits
Author SHA1 Message Date
ryan4yin | 二花 9e2633f496 feat(gaming): generic umu game installer, skill, and desktop entries (#411) 2026-10-08 14:59:11 +08:00
ryan4yin | 二花 dc211bbca3 fix(mihomo): restore the Steam community and store PROXY rules (#412)
The comment trim dropped them. Without a domain rule above the Valve IP ranges,
steamcommunity.com and steampowered.com match those ranges and go DIRECT.
2026-10-08 09:50:41 +08:00
ryan4yin | 二花 ded8d91507 feat(mihomo): keep Steam downloads off the proxy so Steam keeps a CN CDN (#408)
Steam picks download caches from the IP it sees on the CM login. Pin the CM hosts
and content CDN DIRECT, keep the community and store proxied, and add Valve's
AS32590 ranges because Steam dials cached CM IPs without a lookup. Sources in
README.md.
2026-10-08 09:41:51 +08:00
ryan4yin | 二花 c89c5e9698 fix(mihomo): say what a dropped catch-all actually costs (#410) 2026-10-08 09:40:17 +08:00
ryan4yin | 二花 835b7f6df1 feat(shoukei): pin home Wi-Fi to a static IPv4 & adjust networking.nix (#407) 2026-10-07 21:27:34 +08:00
ryan4yin | 二花 8f065f24bc feat(nix): use Nix 2.35 via nixVersions.latest (#405)
Nix 2.35 brings lazy flake source copying, mimalloc (5-12% faster
evaluation), lower nix-daemon memory use, HTTP/3 support, and jittered
transfer retries with Retry-After.
2026-10-07 18:32:09 +08:00
Ryan Yin 13fe324507 refactor(nixpkgs): drop the repo-wide pkgs-x64 package set
Every remaining pkgs-x64 consumer runs only on x86_64-linux hosts, where the
native pkgs already carries the same allowUnfree config
(modules/nixos/base/nix.nix) and overlays (modules/base/overlays.nix), so
replace the references with pkgs and drop the extra nixpkgs instantiation
(which also removes an eval on aarch64-darwin).

media.nix keeps the native Zoom app on x86_64 hosts only, since zoom-us has
no aarch64 Linux build.
2026-10-07 15:56:58 +08:00
ryan4yin | 二花 f5a111c638 feat(backup): hourly read-only snapshots and per-backup integrity checks (#402)
* feat(restic): verify the repository after each backup

* feat(youko): snapshot the restic store hourly

* docs(backup): document the snapshot and check layers
2026-10-07 15:26:57 +08:00
ryan4yin | 二花 3acb5d4ee5 fix(nfs,libvirt): restrict the golden export and bind VNC to loopback (#400)
* fix(nfs): restrict the golden export to its real clients

* fix(libvirt): bind VNC consoles to loopback

* fix(firewall): drop VNC ports on every host

* docs(security): record the NFS and VNC boundaries
2026-10-07 15:10:52 +08:00
ryan4yin | 二花 95b849420e feat(gaming): declarative Proton and dGPU game rendering (#393) 2026-10-07 13:14:42 +08:00
ryan4yin | 二花 dc65254511 fix(ssh): make sandboxed ssh work on Linux (#390) 2026-10-06 15:20:53 +08:00
Ryan Yin 8e3f12aa19 feat(vinput): open the command palette with right Ctrl
Pin keyd's right-hand modifiers (rightcontrol/rightshift/rightmeta) to their own keycodes; keyd otherwise folds them into the left keys. Set Vinput's MenuKey to right Ctrl and clear CommandKeys, which would shadow it.
2026-10-05 22:41:48 +08:00
ryan4yin | 二花 50a4182898 feat(mihomo): show hostname in metacubexd page title (#383)
metacubexd hardcodes its tab title in the SPA, so dashboards on
different hosts are indistinguishable. Patch the static <title> and
re-apply the hostname from config.js, since Nuxt's useHead resets
document.title on every route change.
2026-10-05 10:05:12 +08:00
ryan4yin | 二花 b8348bf276 fix(mihomo): order the service after its config mount (#382)
The config deliberately stays out of the store, under the home directory, which is a persistent bind mount on tmpfs-root hosts. When the service and the mount are introduced in the same activation, mihomo can start before the mount is up and fail with "Failed to set up credentials: No such file or directory", making the switch report status 4. Add RequiresMountsFor so the mount is brought up and ordered before the service.
2026-10-05 01:08:08 +08:00
ryan4yin | 二花 8f0961d9c2 fix(desktop): tie ai's link DNS takeover to mihomo's lifecycle (#380)
* fix(desktop): tie ai's link DNS takeover to mihomo's lifecycle

sing-tun normally points systemd-resolved at the TUN DNS by running
resolvectl (dns/domain/default-route). Under nixpkgs' hardened
DynamicUser mihomo unit that hand-off fails silently: the unit's
RestrictAddressFamilies blocks resolvectl's D-Bus socket and resolve1
requires privileged authorization, so resolved keeps querying the
physical-link DNS, fake-ip is bypassed, and domain rules degrade to
MATCH.

Do the hand-off as '+' ExecStartPost/ExecStopPost hooks instead: '+'
commands run outside the sandbox (systemd.exec: address-family
restrictions do not apply to them) and ExecStopPost reverts even on
crashes, so a dead mihomo leaves DNS usable.

Signed-off-by: Ryan Yin <xiaoyin_c@qq.com>

* docs(mihomo): record sing-tun's resolvectl hand-off as the leak cause

Signed-off-by: Ryan Yin <xiaoyin_c@qq.com>

* refactor(desktop): keep mihomo only on ai and shoukei

ruby/kana never ran the core (service inactive live), and their
resolved + TUN combo would reintroduce the resolver leak once enabled.
Drop the enable and the explicit module import from computer-use; the
eval test now pins mihomo=false for both guests.

---------

Signed-off-by: Ryan Yin <xiaoyin_c@qq.com>
2026-10-05 00:07:32 +08:00
ryan4yin | 二花 bbfe1fa53b feat(desktop): replace Clash Verge with native mihomo on all NixOS hosts (#379) 2026-10-04 21:04:41 +08:00
ryan4yin | 二花 6259359945 security(monitoring): bind exporters to static LAN addresses (#373)
node_exporter listened on 0.0.0.0, so access control rested entirely on
the nftables allowlist. Bind node/smartctl exporters to the host static
LAN IPv4 (the same address VictoriaMetrics scrapes), keeping the socket
off tailscale/bridge interfaces even if the firewall regresses.

Hosts without a static LAN address (shoukei, akane) now run no exporters
at all instead of loopback-bound ones nobody scrapes; akane, a UTM VM,
previously ran a loopback smartctl exporter with no physical disks.

LAN-bound exporters also get the boot-race treatment from #372
(network-online ordering plus patient restart); loopback-bound hosts
must not pull in network-online because NM wait-online would stall
their offline boots.
2026-10-03 19:07:21 +08:00
ryan4yin | 二花 1b31730db4 fix(monitoring): order smartctl exporter after network-online.target (#372)
The exporter binds to the host LAN address, which systemd-networkd
assigns during boot. Without ordering, the service starts before the
address exists, `bind: cannot assign requested address` trips the
start limit, and the unit stays failed until restarted manually.

Order the unit after network-online.target, and since wait-online is
best-effort (120s timeout), also retry patiently so the unit self-heals
when the link comes up late.
2026-10-03 18:54:08 +08:00
ryan4yin | 二花 3a5b9ec4c6 docs: README audit fixes and de-duplication (#371) 2026-10-03 18:28:58 +08:00
ryan4yin | 二花 6a1b4c699a chore(docs): prune stale TODOs (#370) 2026-10-03 17:50:28 +08:00
ryan4yin | 二花 37d79fbb08 chore(hardening): consolidate system hardening and fix stale docs (#368) 2026-10-03 17:11:51 +08:00
ryan4yin | 二花 f03907c6a4 feat(security): add balanced kernel and exporter baseline (#365) 2026-10-03 16:33:50 +08:00
ryan4yin | 二花 d5fa86dbc7 fix(qemu-guest): let the NixOS test framework override serial-getty@ttyS0 (#362)
test-instrumentation.nix sets serial-getty@ttyS0.enable = false at normal priority to keep ttyS0 free for the test backdoor console, while qemu-guest.nix set it to true at normal priority. Two conflicting normal-priority definitions made `nix flake check` fail while evaluating packages.x86_64-linux.ruby-nixos-tests.

Use lib.mkDefault so the test framework wins in tests while ordinary QEMU guests still enable the serial getty.
2026-10-03 12:18:46 +08:00
ryan4yin | 二花 18925eac8b fix(colmena): expose colmenaHive for the nix-community evaluator (#361)
* fix(colmena): expose colmenaHive for the new evaluator

nixpkgs now ships the nix-community Colmena rewrite, whose default
evaluator reads an evaluated colmenaHive flake output instead of the raw
colmena hive. Without it every colmena apply recipe failed with
"does not provide attribute colmenaHive".

Add a colmena input pinned to the same v0.5.0 as nixpkgs and expose
colmenaHive = colmena.lib.makeHive <raw hive>, with the raw hive kept as
an internal binding rather than a flake output of its own.

* chore: clean up stale colmena and aquamarine references

- point the Colmena links at nix-community/colmena after the move
- rename the security-aquamarine-metrics test to youko-metrics (it
  already tested youko) and update the outputs README
- drop the commented aquamarine remote-builder example
2026-10-03 12:14:13 +08:00
ryan4yin | 二花 d056aece28 chore(workarounds): re-evaluate stale hardware/kernel fixes (#360)
* chore(workarounds): re-evaluate stale hardware/kernel fixes

Prune workarounds whose root cause is gone, fix one vendor typo, and
document the ones we keep:

- drop `transparent_hugepage=madvise` on shoryu/shushou/youko: it was tied to
  the old fixed 1G hugetlb pool, and the VMs now use ordinary memory
- shoryu: `hardware.cpu.intel.updateMicrocode` -> `amd` (it is an AMD APU)
- ai: drop `i915.enable_guc=3` (GuC/HuC submission is the default on modern
  i915/Xe)
- kernel-hardening: name the Dirty Frag CVEs (CVE-2026-43284 / CVE-2026-43500)
  and the re-evaluation condition
- document re-eval conditions for the Insta360 resume fix, the darwin
  auto-optimise-store workaround, and the youko USB-SATA bridge mitigations

* chore(workarounds): keep the Dirty Frag module blacklist as defence in depth

* chore(ai): correct the i915.enable_guc rationale (verified against the kernel)

* chore(darwin): drop the auto-optimise-store workaround (nix#7273 fixed)
2026-10-03 11:25:34 +08:00
ryan4yin | 二花 dc3ec8c159 feat(storage): relax ai NVMe workarounds and add drive SMART monitoring (#359)
* fix(ai): relax NVMe power-management workarounds and enable smartd

Logs show no NVMe errors, so allow APST again (capped at 100 ms), restore
the default io_timeout, and drop pcie_aspm=off. Add smartd for drive
health visibility.

* feat(storage): add drive/SSD SMART monitoring on physical hosts

node_exporter's nvme collector only exposes node_nvme_info and namespace
capacity, not SMART health, so SSD wear/lifespan and drive temperature were
not observable anywhere.

- enable services.prometheus.exporters.smartctl on physical hosts, gated on
  modules.hardwareTools (off on QEMU/MicroVM guests), bound to the host's LAN
  address on port 9633
- firewall: drop 9633 from anything but the monitoring host
- youko: scrape smartctl-<host> for the physical hosts
- alert rules (storage.yml): SMART health, NVMe wear, available spare, media
  errors, critical warning, and drive temperature (warn 70 / crit 80 C)
- Grafana dashboard "Drive SMART (smartctl)"
2026-10-03 11:13:46 +08:00
ryan4yin | 二花 51261645ca chore: small audit cleanups (#357)
Remove a dead .gitattributes rule, bump the mirror workflow's checkout,
document the daemon test settings, drop unused JACK, and align the
installer's disko version.
2026-10-03 10:32:08 +08:00
ryan4yin | 二花 885dabb49d refactor: scope host tools, locate and mDNS by purpose (#356) 2026-10-03 10:23:21 +08:00
ryan4yin | 二花 ce416240b2 fix: avoid mkForce for allowUnfree and boot timeout (#355)
Let hosts override these again and drop the forced priorities.
2026-10-03 10:14:50 +08:00
ryan4yin | 二花 2bacb5c138 refactor: drop redundant package declarations (#353)
Remove no-op overrides and packages already provided elsewhere in the
same profile.
2026-10-03 10:11:30 +08:00
ryan4yin | 二花 42641e2fdf feat!: replace zellij with tuios, default to ghostty + kitty (#349)
* feat!: replace zellij with tuios and switch to ghostty + kitty

Terminal environment overhaul:

- add the tuios flake input (upstream 0.8.5; nixpkgs has 0.8.1) and link
  the checked-in config out-of-store; auto-start tuios in nushell instead
  of zellij
- remove zellij entirely: both modules, config, README and nushell
  completions
- remove foot and alacritty, which lack the Kitty graphics protocol;
2026-10-03 02:34:31 +08:00
Ryan Yin d27818e948 docs: update stale workaround comments
- wechat.nix: repacking is needed because nixpkgs' wechat package does not expose its AppImage wrapper args for `.override`, not because wrapAppImage lacks overriding (it forwards args to buildFHSEnv).
- peripherals.nix: drop a link to an already-closed issue and fix a typo.
2026-10-03 00:14:00 +08:00
Ryan Yin facf33615e fix(nixos): install terminfo only for terminals in use
environment.enableAllTerminfo installs every terminal's terminfo, including rxvt-unicode, which no longer builds with GCC 16 (NixOS/nixpkgs#568896). Install just the terminals we use (alacritty, foot, ghostty, kitty) instead. This also makes the aarch64 jasper workaround unnecessary.
2026-10-03 00:14:00 +08:00
Ryan Yin 6a026ecf9f chore(desktop): make podman rootless-only
Disable the rootful system podman.socket on desktop hosts and drop the module's autoPrune, which prunes the rootful store and pulls in the rootful API service. Add a weekly per-user timer that prunes the rootless store instead.
2026-10-02 15:58:12 +08:00
ryan4yin | 二花 9c44117f75 refactor(editors): standardize on helix, keep neovim as backup (#345) 2026-10-02 13:33:17 +08:00
ryan4yin | 二花 68ea04f173 fix(docs): correct stale and mismatched documentation (#338) 2026-10-02 10:21:55 +08:00
ryan4yin | 二花 4909f6357b security: scope privileges and stop a world-readable secret copy (#335) 2026-10-01 21:18:34 +08:00
ryan4yin | 二花 d690f45183 feat: add CanoKey hardware security key support (#334) 2026-10-01 20:50:13 +08:00
Ryan Yin a6553b25a5 chore: drop archived terraformer and unused netbird 2026-10-01 20:10:07 +08:00
ryan4yin | 二花 ab2fd0fee9 feat: add plocate filesystem search and cap podman log size (#333) 2026-10-01 20:00:53 +08:00
ryan4yin | 二花 8f9fdda2bb refactor: trim unused virtualisation config and packages (#332) 2026-10-01 19:42:20 +08:00
ryan4yin | 二花 9ab5eca60c feat(monitoring): GPU-aware btop variants and GPU metrics (#330) 2026-09-30 00:16:50 +08:00
Ryan Yin 098ed110d7 chore(darwin): drop redundant broken-packages overlay
conda/mitmproxy/wireshark are already Linux-gated in the shared home modules, and verible is unreferenced, so replacing them with emptyDirectory is unnecessary.
2026-09-28 10:55:22 +08:00
ryan4yin | 二花 e5b95affa6 feat(nixos): default-deny host inbound, trust the LAN/tailnet (#325)
Hosts used to trust the router as the only boundary (servers ran with the
firewall off; service ports were opened globally), so any LAN device could
reach every host service. Move filtering to the hosts as defence in depth
behind the router, which keeps its firewall on and uses a port mapping for
the few ports we actually need.

- base: nftables backend; deny inbound by default; trust the home LAN by
  source and the tailnet by interface (restrict the tailnet with ACLs);
  suppress per-service `openFirewall` global ports; allow node_exporter only
  from the monitoring host. The local podman bridge, the tailnet and the pod
  CIDRs are accepted only after the node_exporter drop.
- servers: stop disabling the firewall; drop redundant global port opens
  (caddy 80/443, NFS 2049, Jellyfin, localsend/test ports); delete the
  redundant desktop firewall module; aarch64/riscv64 import the firewall
  explicitly (akane was missing it).
- k3s: Cilium pods (10.0.0.0/8, fd00::/8) may reach host services; drop the
  flannel-era cni0/flannel.1 trust.
- youko: postgres listens on localhost + the LAN with pg_hba limited to the
  LAN; the NFS export stays LAN-scoped; remove the unauthenticated v2ray
  proxy.
- tests: `security-firewall` asserts every host runs the shared firewall, has
  the LAN CIDR rule and no global ports.
2026-09-26 14:02:03 +08:00
ryan4yin | 二花 5ee8b728b5 fix(restic): use the correct systemd timer option names (#319)
timerConfig was set with lowercase onCalendar/randomizedDelaySec, which systemd treats as unknown directives. The generated timer had no schedule, so `systemctl list-timers` showed NEXT=- and no backup ever ran. Use the real keys OnCalendar/RandomizedDelaySec.
2026-09-25 20:39:59 +08:00
ryan4yin | 二花 97c2d1325d docs: refresh stale docs after the VM and backup refactors 2026-09-21 22:03:21 +08:00
Ryan Yin 00aab5f562 feat(computer-use): add a headless X11/i3 environment
Give the idols-ruby and idols-kana VMs a headless computer-use
environment: Xvfb plus i3, driven by cua-driver (and computer-use-linux
as a fallback). Includes the system module (AT-SPI, fonts, Mesa, Clash
Verge proxy, proxy-region timezone), the home i3 module (Xvfb/i3/x11vnc
services, browser flags), host wiring and an eval test.
2026-09-21 21:31:27 +08:00
ryan4yin | 二花 ef00eb31e0 docs: warn that user-readable decrypted secrets must not be read (#303)
Only three secrets are readable as the login user (nix-access-tokens,
ssh-key-romantic and the nushell one); everything else is root-only and
the filesystem already keeps agents out.
2026-09-21 21:18:06 +08:00
Ryan Yin 096607a5c5 feat(backup): notify on failure, and 404 unconfigured hostnames
A failed backup was silent. Post to alertmanager (which routes above-info
to telegram), and have caddy answer 404 instead of its empty 200 for
*.writefor.fun names that are not services.
2026-09-21 20:42:39 +08:00
Ryan Yin d322f4d2b6 docs: add BACKUP.md, and stagger the restic schedule per host
The design (layers, password groups, retention, restore steps) was only in
code comments. Also make the timer configurable: a whole hour of random
delay defeated any staggering, and the desktop's push, youko's own run and
btrbk all otherwise contend for the same disks.
2026-09-21 20:38:08 +08:00