From be592ae75cff8c1bd1ef8b49cbf20b0fa091768b Mon Sep 17 00:00:00 2001 From: Ryan Yin Date: Mon, 2 Nov 2026 01:12:41 +0800 Subject: [PATCH] refactor(mihomo): link geodata from nixpkgs instead of seeding it by hand `just mihomo-geo` copied geodata into the state dir so a cold start never fetched it. tmpfiles now links v2ray-rules-dat and the DB-IP lite mmdbs there, so geo-auto-update moves to the gateway config only. Assisted-by: Claude Code (claude-opus-5-5) --- AGENTS.md | 11 ++++---- Justfile | 27 ------------------- .../nixos/desktop/networking/mihomo/README.md | 9 ++++--- .../desktop/networking/mihomo/default.nix | 8 ++++++ .../networking/mihomo/gateway-config.nu | 3 +++ .../desktop/networking/mihomo/generate.nu | 2 -- .../desktop/networking/mihomo/policy.yaml | 6 ++--- 7 files changed, 24 insertions(+), 42 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index d05931c3..d0e71ce6 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -100,9 +100,8 @@ introduces one, and re-evaluate entries when their `Revisit` trigger comes up. - `just niri` and `just local` activate the machine you are on through `sudo` and block on a password prompt; `just darwin-rollback` switches the macOS generation on the machine you are on, and a bare `sudo systemctl restart ` activates a running service the same way. - `just mihomo-geo` (mihomo's state directory) and `just shoukei-home-wifi` (a persistent - NetworkManager profile) change the local machine through `sudo` too. The user runs these, not an - agent. + `just shoukei-home-wifi` (a persistent NetworkManager profile) changes the local machine through + `sudo` too. The user runs these, not an agent. - `just shoryu`, `just shushou`, `just youko`, `just aquamarine`, `just ruby`, `just kana`, `just lab`, `just k3s-test`, and `just col ` activate systems through Colmena. Use the narrower recipe that matches the intended host scope. @@ -140,9 +139,9 @@ repository, and cross-link them — no need to be told. change. - `~/codes/nix-secrets` — the private agenix store behind `secrets/` and the `mysecrets` input: ciphertext and recipient rules for the secrets declared here. -- `wallpapers`, `nur-ryan4yin`, `nu_scripts`, `mattpocock-skills`, `i-have-adhd` — - flake inputs from the user's own repositories; bump with `just upp ` after their source - changes, do not edit them from here. +- `wallpapers`, `nur-ryan4yin`, `nu_scripts`, `mattpocock-skills`, `i-have-adhd` — flake inputs from + the user's own repositories; bump with `just upp ` after their source changes, do not edit + them from here. ## Further Context diff --git a/Justfile b/Justfile index 970eb6e2..b3f5f370 100644 --- a/Justfile +++ b/Justfile @@ -322,33 +322,6 @@ mihomo-gen: } print "validated -- restart: sudo systemctl restart mihomo.service" -# Seed mihomo's geodata into the service's state dir, so a cold start needs no DNS. -[linux] -[group('services')] -mihomo-geo: - #!/usr/bin/env nu - # Copy geodata in by hand, so a cold start never has to fetch it. The core - # fetches it while parsing rules, before its own DNS is up and while the link - # DNS points at it -- that fetch can only fail. - let src = ($env.HOME | path join .config mihomo) - let dst = "/var/lib/private/mihomo" - sudo mkdir -p $dst - mut seeded = [] - for f in [GeoSite.dat geoip.metadb ASN.mmdb] { - let p = ($src | path join $f) - if ($p | path exists) { - sudo cp $p $dst - $seeded = ($seeded | append ($dst | path join $f)) - } else { - print $"(!) ($f) is not in ($src) -- fetch it first: mihomo -t -d ($src) -f ($src)/config.yaml" - } - } - if ($seeded | is-not-empty) { - sudo chmod 644 ...$seeded - let names = ($seeded | path basename | str join ', ') - print $"seeded ($names) -- restart mihomo to pick them up" - } - # Render the mihomo config into a Clash Verge Rev local profile on macOS. # sources.yaml comes from the encrypted dotfiles sync (nix-secrets `just restore`). [macos] diff --git a/modules/nixos/desktop/networking/mihomo/README.md b/modules/nixos/desktop/networking/mihomo/README.md index d3038188..9eba20be 100644 --- a/modules/nixos/desktop/networking/mihomo/README.md +++ b/modules/nixos/desktop/networking/mihomo/README.md @@ -13,10 +13,11 @@ sudo systemctl restart mihomo.service # dashboard: http://127.0.0.1:90 ``` `~/.config/mihomo` holds `sources.yaml` and the generated `config.yaml`, which the service loads -through systemd `LoadCredential`; the core's own state — geodata and cache — is in -`/var/lib/private/mihomo` (`StateDirectory`, `DynamicUser`). The generator, `policy.yaml` and -`gateway-config.nu` are run from here and never copied over. `just mihomo-gen` renders the config -and validates it with the core the service runs. +through systemd `LoadCredential`; the core's own state is in `/var/lib/private/mihomo` +(`StateDirectory`, `DynamicUser`), where the module links geodata from nixpkgs (`v2ray-rules-dat`, +`dbip-country-lite`, `dbip-asn-lite`), so it updates with nixpkgs, not at runtime. The generator, +`policy.yaml` and `gateway-config.nu` are run from here and never copied over. `just mihomo-gen` +renders the config and validates it with the core the service runs. `sources.yaml` holds everything private (subscription URLs, secret, private domains) and stays out of the repo and the Nix store; the module loads `config.yaml` via `LoadCredential`. Generate the diff --git a/modules/nixos/desktop/networking/mihomo/default.nix b/modules/nixos/desktop/networking/mihomo/default.nix index 3a9e6087..b338efaf 100644 --- a/modules/nixos/desktop/networking/mihomo/default.nix +++ b/modules/nixos/desktop/networking/mihomo/default.nix @@ -69,6 +69,14 @@ in # and fail with "Failed to set up credentials: No such file or directory". systemd.services.mihomo.unitConfig.RequiresMountsFor = builtins.dirOf configFile; + # Geodata from nixpkgs: a cold start must not fetch it (its DNS is not up yet). + systemd.tmpfiles.settings.mihomo-geodata = { + "/var/lib/private/mihomo/GeoSite.dat"."L+".argument = + "${pkgs.v2ray-rules-dat}/share/v2ray/geosite.dat"; + "/var/lib/private/mihomo/geoip.metadb"."L+".argument = pkgs.dbip-country-lite.mmdb; + "/var/lib/private/mihomo/ASN.mmdb"."L+".argument = pkgs.dbip-asn-lite.mmdb; + }; + services.resolved.enable = lib.mkIf cfg.resolvedIntegration true; networking.networkmanager = lib.mkIf (cfg.resolvedIntegration && config.networking.networkmanager.enable) diff --git a/modules/nixos/desktop/networking/mihomo/gateway-config.nu b/modules/nixos/desktop/networking/mihomo/gateway-config.nu index 897694eb..e5f24db7 100644 --- a/modules/nixos/desktop/networking/mihomo/gateway-config.nu +++ b/modules/nixos/desktop/networking/mihomo/gateway-config.nu @@ -36,6 +36,9 @@ def main [ | insert external-ui "ui" | insert external-ui-url $UI_URL | update secret "GATEWAY-SECRET-PLACEHOLDER" + # desktops take geodata from nixpkgs; the gateway updates its own + | insert geo-auto-update true + | insert geo-update-interval 24 # The gateway uses nftables TProxy for LAN traffic; its desktop-style TUN # auto-route would capture the gateway's own DIRECT IPv6 dials again. | upsert tun.enable false diff --git a/modules/nixos/desktop/networking/mihomo/generate.nu b/modules/nixos/desktop/networking/mihomo/generate.nu index ec81a9c3..5788f7d9 100644 --- a/modules/nixos/desktop/networking/mihomo/generate.nu +++ b/modules/nixos/desktop/networking/mihomo/generate.nu @@ -549,8 +549,6 @@ def main [ "fake-ip-filter": (($priv_filters | append $policy_filters) | uniq) } "geodata-mode": false - "geo-auto-update": true - "geo-update-interval": 24 "geox-url": { geoip: "https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geoip.dat" geosite: "https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geosite.dat" diff --git a/modules/nixos/desktop/networking/mihomo/policy.yaml b/modules/nixos/desktop/networking/mihomo/policy.yaml index 14143c6a..457a26a7 100644 --- a/modules/nixos/desktop/networking/mihomo/policy.yaml +++ b/modules/nixos/desktop/networking/mihomo/policy.yaml @@ -4,9 +4,9 @@ # rules, the rules from `sources.yaml` and the rules imported from your # subscriptions, so this file is the tail that closes every config. # -# GEOSITE categories come from meta-rules-dat, which the module keeps current -# (`geo-auto-update`). `mihomo -t` validates the names: `taobao`, `alipay` and -# `wechat` do not exist in it, hence the hand-written domains below. +# GEOSITE categories come from meta-rules-dat on the gateway and nixpkgs' +# v2ray-rules-dat on the desktops. `mihomo -t` validates the names: `taobao`, +# `alipay` and `wechat` do not exist in it, hence the hand-written domains below. # Region node groups. Each entry becomes two groups offered inside PROXY: # " 自动" (url-test, lazy: only health-checked once selected) and