Shared Clash/Mihomo Operations

zjlab-ubuntu and 72602-minipc both use nelvko/clash-for-linux-install from /home/aaron/clashctl. This page is the shared host-level proxy runbook; cluster-specific bridges and application proxy variables remain documented on their respective cluster pages.

Command Loading

clashctl is a Bash function loaded by /home/aaron/.bashrc, not an executable installed in PATH. Non-interactive SSH and agent shells do not automatically load it, so command -v clashctl or a direct clashctl status can incorrectly report that the command is missing.

Prefer explicit loading in automation:

CLASH_HOME=/home/aaron/clashctl
. "$CLASH_HOME/scripts/cmd/clashctl.sh"
clashctl --help
"$CLASH_HOME/bin/mihomo" -v
clashctl status

bash -ic 'clashctl status' is acceptable for a quick remote check, but it can emit harmless job-control warnings when SSH has no TTY. Explicit sourcing gives cleaner, more predictable automation output.

Read-Only Preflight

Run this once on the target host before trying alternate ports, editing proxy variables, or restarting anything:

CLASH_HOME=/home/aaron/clashctl
. "$CLASH_HOME/scripts/cmd/clashctl.sh"

hostname
"$CLASH_HOME/bin/mihomo" -v
clashctl status

proxy_port="$("$CLASH_HOME/bin/yq" \
  '."mixed-port" // .port // 7890' \
  "$CLASH_HOME/resources/runtime.yaml")"
printf 'proxy_port=%s\n' "$proxy_port"

curl --proxy "http://127.0.0.1:${proxy_port}" \
  --connect-timeout 5 --max-time 12 \
  --silent --show-error --output /dev/null \
  --write-out 'proxy_http_code=%{http_code}\n' \
  https://www.gstatic.com/generate_204

The expected result is one active mihomo process and HTTP 204. This test uses the configured local port and proves an end-to-end HTTPS request through the proxy; it is more useful than probing a sequence of guessed ports.

If it fails, inspect the existing log without opening an interactive pager:

tail -n 100 /home/aaron/clashctl/resources/mihomo.log

Do not use clashctl log in unattended work because it invokes less.

Three Independent States

Do not collapse these into one “proxy is enabled” judgment:

  1. clashctl status checks whether the mihomo core process exists.
  2. ._custom.system-proxy.enable is only the saved proxy preference in mixin.yaml.
  3. HTTP_PROXY, HTTPS_PROXY, ALL_PROXY, and NO_PROXY are environment variables inherited by the current shell or process.

Inspect the latter two without printing proxy URLs or authentication:

CLASH_HOME=/home/aaron/clashctl

"$CLASH_HOME/bin/yq" -r \
  '"saved_proxy_flag=" + ((._custom.system-proxy.enable // false) | tostring)' \
  "$CLASH_HOME/resources/mixin.yaml"

env | awk -F= \
  'BEGIN { IGNORECASE=1 } /^(http|https|all|no)_proxy=/{ print $1 }' | \
  sort -fu

It is valid for the core and explicit curl --proxy request to be healthy while a fresh non-interactive shell has no proxy variables. Do not call clashctl proxy on merely to make a diagnostic shell look enabled; that command changes saved state. Use an explicit per-command proxy unless the requested operation requires persistent shell proxy configuration.

Systemd Boundary

clashctl has no version subcommand. Query the installed core directly:

/home/aaron/clashctl/bin/mihomo -v

Do not use a systemd unit state as a substitute for clashctl status and the end-to-end request. ZJLAB currently has no clashctl-on.service. On 72602, clashctl-on.service is an enabled user-level Type=oneshot bootstrap; active (exited) means only that the bootstrap command completed. It does not supervise or prove the health of the current mihomo process.

Path Boundaries

  • Host-local tools on both machines use 127.0.0.1:<runtime-port>.
  • On 72602, Pods use http://192.168.0.25:17890 or http://argocd-egress-proxy.argocd.svc.cluster.local:17890. The socat bridge forwards to host-local mihomo.
  • Do not configure a 72602 Pod with 192.168.0.25:7890 while allow-lan is false.
  • The 72602 bridge is not evidence that the same Pod path exists in ZJLAB. Verify the target cluster’s live proxy path separately.

Command Safety

CommandBehaviorAgent policy
clashctl --helpShows locally installed command setRead-only
/home/aaron/clashctl/bin/mihomo -vShows the installed core versionRead-only
clashctl statusChecks the mihomo processRead-only; first diagnostic
clashctl logOpens less on the core logAvoid in automation; use tail
clashctl proxyShows proxy environment stateDo not capture raw output; it may include authentication
clashctl on / offStarts or force-stops the shared core and changes shell proxy stateRequires explicit authorization
clashctl uiShows the panel and starts the core if it is downNot read-only; requires authorization
clashctl proxy on / offChanges saved proxy state and current shell variablesRequires authorization
clashctl tunReads or changes host routing/TUN stateChanges require explicit authorization
clashctl mixinReads or edits merged configuration and can restart the coreDo not print full config; changes require authorization
clashctl subManages subscription sources and updatesURLs are sensitive; changes require authorization
clashctl upgradeUpgrades the running coreRequires reviewed maintenance window
clashctl secretReads or changes the controller secretNever print; changes require secure rotation approval

Do not stop or restart the proxy merely because an unrelated external endpoint is slow. Confirm core status, the configured port, one known generate_204 request, and the recent log first.

2026-08-14 Audit Snapshot

Read-only checks on both zjlab-ubuntu and 72602-minipc found:

  • the installed mihomo process active;
  • Mihomo Meta v1.19.17 on linux amd64;
  • HTTP/mixed port 7890, SOCKS port 7891, and controller port 9090;
  • allow-lan: false and TUN disabled;
  • the dynamic local-port preflight above returned HTTP 204 on each host.

ZJLAB had no clashctl-on.service. The 72602 user unit was enabled and active (exited), but was a Type=oneshot bootstrap rather than the supervisor of the live core. Fresh non-interactive shells did not inherit proxy environment variables, which did not prevent the explicit local proxy checks from passing.

Treat these as dated health observations. The runtime configuration remains authoritative for current ports and modes.