Skip to content

fix(tor): prevent tor_server crash-loop from silently pinning the CPU - #2177

Open
ptrinh wants to merge 1 commit into
getumbrel:masterfrom
ptrinh:fix/tor-server-crash-loop
Open

fix(tor): prevent tor_server crash-loop from silently pinning the CPU#2177
ptrinh wants to merge 1 commit into
getumbrel:masterfrom
ptrinh:fix/tor-server-crash-loop

Conversation

@ptrinh

@ptrinh ptrinh commented Jun 26, 2026

Copy link
Copy Markdown

Problem

Per-app Tor hidden-service sidecars (<app>-tor_server-1) can enter a silent, permanent crash-loop that pins a CPU core and thermally throttles the whole device — with nothing surfaced in the UI.

On one node, three apps that run network_mode: host (tailscale, adguard-home, watch-your-lan) accumulated 41,000+ failed restarts over 9 days, holding an Intel N100 at 95 °C and thermal-throttling ~63 % of uptime. docker stats/ps look innocent because every restart resets the per-process CPU counters; the tell is the container restart count and a context-switch storm.

$ docker inspect -f '{{.RestartCount}} {{.Name}}' ...
13713 /tailscale-tor_server-1
13699 /watch-your-lan-tor_server-1
13688 /adguard-home-tor_server-1

$ docker logs tailscale-tor_server-1
[warn] Unparseable address in hidden service port configuration.
[warn] Failed to parse/validate config: Failed to configure rendezvous options.
[err] Reading config failed--see warnings above.

Root cause

Two issues compound, both in packages/umbreld/source/modules/apps/legacy-compat/:

  1. Triggerapp-script sets the onion target to 80:${APP_PROXY_HOSTNAME}:${APP_PROXY_PORT} (i.e. app_proxy_<app>:<port>). For apps running network_mode: host, that proxy hostname isn't resolvable from the tor_server's network, so tor rejects the HiddenServicePort address and exits.
  2. The actual damagedocker-compose.tor.yml declares restart: on-failure (no retry limit) and tor-entrypoint.sh exits immediately on a bad config. Docker therefore recreates the container roughly once a minute, forever, generating continuous container-recreation churn that silently cooks the host.

Fix

This PR addresses #2 — the general, trigger-independent failure — in tor-entrypoint.sh: validate the generated config first and, if it's invalid, retry in place with a 60s backoff inside a single long-lived container instead of fast-exiting into an endless container-recreation loop.

  • Happy path is unchanged: tor --verify-config passes instantly, then exec tor makes tor PID 1 so it still receives signals cleanly on container stop.
  • Broken path no longer harms the host: one idle container that retries every 60s, with the real tor error visible in its logs, instead of ~1,440 container recreations/day pinning a core.

Minimal single-file change; no new files, no behavior change for working apps.

Note: the network_mode: host resolution issue (#1) — making onion services actually work for those apps — is left as a separate follow-up. This PR's goal is to ensure a bad tor config can never silently melt the device, whatever the cause.

🤖 Generated with Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant