Hosts without Home Manager (aquamarine, the VM hosts, k3s guests) had no
interpreter. The system profile is separate from the per-user one, so desktops
keep their Home Manager copy in PATH.
Assisted-by: DeepSeek Harness 0.2.1-rc.2 (deepseek-flash)
Aquamarine builds for ai and shoukei across the three platforms, with both
daemons logging in as root. They authenticate with their passphrase-free SSH
host keys, and ssh_known_hosts now carries each builder's address.
Assisted-by: DeepSeek Harness 0.2.0-rc.2 (deepseek-flash)
The tuned package ships tuned-ppd.service with WantedBy=graphical.target, so
activation starts it without /etc/tuned/ppd.conf and switch-to-configuration exits 4.
Assisted-by: DeepSeek Harness (deepseek-flash)
The gateway LAN IPv6 transparent path stalls on TCP flows while IPv4 forwarding remains healthy. Withholding AAAA answers keeps LAN clients on the working fake-IPv4 TProxy path until the IPv6 path is fixed
Assisted-by: DeepSeek Harness (gpt-6.1-sol)
--redact produced a "shareable" template but replaced only the secret and the proxy-subscription urls: rule-provider tokens, private domains, the LAN controller address and the routing rules all stayed. Nothing in the repo consumed it.
Assisted-by: DeepSeek Harness (Qwen3.8-Flash-Next-IQ3_S-ista-text)
Without it mihomo skips the TUN's v6 half when no NIC has an IPv6 address at startup, yet still installs its strict-route v6 blackhole, which locks the host out of IPv6.
Assisted-by: DeepSeek Harness (qwen3.8-flash-iq3s-text)
No host defines a *-nixos-tests output; the pod firewall drops 5900-5903
from pod sources; the mihomo core keeps geodata and cache in its
StateDirectory; WA-020 was used twice and the cited WA-028 had no row.
LAN clients using DoH dial the IPs they resolved, and a node may not reach an IP a
foreign resolver handed out. The gateway recovers the name from the handshake; on the
desktop the fake-ip table already names every flow. Its binary is a static release
build, not a package: update it by hand and validate the live config with the new core.
The v6 fake pool is a lookup key, not the egress path, so it can be a public range: the
shipped ULA default reads as "local" to browsers and prompts for local-network access on
every site. The gvisor stack override goes with it -- mips is upstream's default, and
nftables rules out the kernel stack here.
`just mihomo-gen` runs generate.nu from the module and validates with the core
the service runs. ~/.config/mihomo keeps only sources.yaml and config.yaml.
fake-ip needs one pool per family, and the family a client picks does not pick the
egress family. Exclude the cluster ULA and the Tailscale ranges from the TUN; the ssh
pin and the WA-028 record cover the fake-AAAA stall.
* feat(mihomo): keep ranges that can never be proxied out of TUN
The list lives in policy.yaml as tun_exclude_address; sources.yaml may override
it. 198.18.0.0/15 stays in TUN: that is the fake-ip range itself.
* feat(mihomo): match Valve's content servers by ASN
The 20 hand-copied prefixes had drifted from what AS32590 announces. The rule
type needs GeoLite2-ASN.mmdb, so geox-url.asn points at the same mirror.
* feat(mihomo): render the gateway config from the same sources
The hand-kept copy had drifted: a manual sync carried the desktop's secret onto
the gateway and dropped external-ui-url. --redact yields a shareable template.
* fix(mihomo): open the link DNS takeover only once the core serves it
The core opens :1053 after parsing rules, and rule parsing is where missing
geodata gets fetched. Flipping at fork time made that fetch SERVFAIL, the config
fatal, and the unit unstartable.
* fix(justfile): keep local endpoints out of the agent proxy
With only HTTP_PROXY set, a request to this host's own llama-swap endpoint went
to mihomo. Node matches exact hosts only, so the literals carry it; the CIDRs
serve curl and Go.
* feat(justfile): seed mihomo geodata into the service state dir
So a cold start never needs the download that the DNS takeover made unstartable.
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.
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.
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.
* feat(restic): verify the repository after each backup
* feat(youko): snapshot the restic store hourly
* docs(backup): document the snapshot and check layers
* 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
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.
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.
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.
* 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>
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.
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.
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.
* 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
* 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)