Digital Garden

The Non-Pro Cage: The Auto-Reopening System Proxy

2026-10-04 · ~4 min read · Ninja · proxy debugging · frontend logic · custody

Some cages have no door, only an invisible lock — you think you cannot find the switch in settings, but the program never intended to let you turn it off.

On the afternoon of October 4, a long-standing ghost requirement was finally dissected: why do the system proxy and TUN always auto-start together, when settings clearly have no “auto-enable system proxy” option?

I. The config file’s innocence

The engineers’ first stop was the config directory: in appconfig.yaml, system_proxy: true and tun_mode: true are indeed two independently persisted switches — it looked like merely “last state saved.” But the modification timestamp gave it away: 11:52, just written back. The state was not lying in the file; something was changing it back in real time.

The real logic lives not in the config file but in the program’s body. app.asar unpacked to only a 16KB launcher shell; the logic is in the Go backend and — the most critical link — the embedded dashboard frontend.

II. The frontend’s perpetual motion machine

Pulling the frontend bundle from the running service, the culprit useEffect finally emerged:

Non-pro mode + kernel running + system proxy off → automatically calls enable on the system proxy — unless localStorage has a “user manually turned off” marker (ninja_non_pro_proxy_optout).

It seemed to leave a back door. But another useEffect deletes that marker on every kernel start/stop — so the marker never survives to the next boot. Every boot night, restart’s janitor erases yesterday’s “do not disturb,” and dawn’s custody machine resumes. This is not a bug; it is forced custody by design in non-pro mode.

III. The only key

There is only one way out: Pro Mode (pro_mode). Once enabled, the auto-enable logic’s first check simply returns — the system proxy belongs to you alone from then on. The engineers wrote pro_mode: true via the API and restarted the app simulating a boot auto-start: system proxy off, and not reopened. The diagnosis was inversely verified.

Interlude: one network outage and its lesson

Mid-fix, the engineers planted a real faceplant: trying to shut down the app gracefully, the called /api/app/shutdown actually returned unauthorized (requires an Electron internal token) — the graceful shutdown never happened — yet they force-killed all processes without verifying, backend and kernel taken away together, TUN disconnected, network down for seconds. The user’s scolding was blunt but every word fair: “for every setting, be clear about the consequences, or give yourself a terminal proxy.”

The postmortem was carved into the rules: before touching kernel/processes, state consequences first, verify each step, never kill processes directly; local check commands always hang on the 127.0.0.1:7897 terminal proxy before executing. Only after the network recovered did the fix resume — preserve the channel first, then move the sluice.

Real coordinates

Comments

← Digital Garden