Treat “Docker pull works once” as a routing hypothesis, not proof
Registry outage posts spike whenever Docker Hub hiccups, yet standing up OpenHands exercises more than a single TLS session to registry-1.docker.io. The compose stack pulls runtime images, spawns sandbox containers that may run their own apt, pip, or npm fetches, clones target repositories through GitHub HTTPS or the GitHub API, and only then begins the agent loop that fans out across Anthropic, OpenAI, and Google model API hosts. When any segment rides a congested domestic path while another accidentally exits through a healthier offshore hop, wall clocks mislead: one engineer sees a fast docker pull hello-world while OpenHands runtime images still expire, and another blames model outages when the real issue is asymmetric policy ordering in Clash profiles.
Before rewriting subscriptions or opening upstream tickets, log the failure shape. Connection attempts that never produce HTTP status lines usually indicate routing exhaustion or handshake blackholing rather than application-layer denial. Immediate HTTP 401 or 403 payloads often trace to tokens, organization policy, or sandbox permissions—not geographic routing. Clone the failing environment into narrow probes: run verbose docker compose pull with plain progress output, compare against curl -Iv https://registry-1.docker.io/v2/ from the same login shell, exercise curl -I https://api.github.com/rate_limit, and repeat against whichever provider host your config.toml references. If curl succeeds while Docker still stutters, inspect whether the daemon uses a different DNS path or bypasses userland proxy exports entirely—a pattern that dominates Docker Desktop on Windows and macOS.
Why OpenHands multiplies outbound surfaces beyond IDE agents
Tools like Cline or Copilot CLI primarily stress npm, IDE marketplaces, and REST model calls from Node processes on the host. OpenHands adds an orchestration layer: a controller container schedules sandbox workers, mounts workspace volumes, executes shell commands that may themselves call package managers, and streams large repository contexts back to cloud reasoning endpoints. That architecture means three semi-independent routing worlds must agree: your workstation shell launching compose, the Docker engine pulling and networking images, and ephemeral sandboxes that may not inherit host TUN tables when attached to bridge networks.
Teams migrating from the OpenDevin name often underestimate this multiplication. Documentation emphasizes “clone and docker compose up,” which sounds monolithic until logs show Git LFS assets, GitHub release binaries, Hugging Face model weights, or custom pip indexes each resolving through different CDN edges. Transparent TUN capture on the host remains the foundation because it elevates policy beneath debates about who exported HTTPS_PROXY, but you must also plan for what happens after packets enter Docker NAT. Browser-based provider dashboards can look flawless while agent tasks starve, because Chromium reads system proxy tables reliably whereas the Docker CLI and in-container curl may consult only daemon-level configuration knobs.
Enable Meta-class Clash TUN before micromanaging compose or API keys
Start with a clean capture story on the machine that actually runs docker compose. In Clash Verge Rev, Mihomo Party, or headless systemd deployments documented elsewhere on this site, enable TUN using the stack your security reviewers accept—kernel system mode where permitted, or isolated gvisor stacks when you need fewer kernel entitlements—and confirm helper services survived reboots on macOS or elevated installs on Windows. Our Clash Verge Rev TUN guide walks through permission prompts that commonly block first-time adopters.
After toggling TUN, open the live connection list and trigger trivial curls to Docker registry metadata, GitHub rate-limit endpoints, and your default npm registry from the same shell that previously timed out. You should see predictable outbound tags rather than silent leakage to unintended interfaces. Avoid stacking unrelated VPN clients that also manipulate default routes; conflicting daemons manifest as intermittent successes whenever race conditions shuffle metric order. Once host tunnels behave consistently, rerun a medium-sized docker pull for an OpenHands dependency image and spot-check npm packument JSON. Only after those baselines stabilize should you invest time editing API base URLs or corporate registry mirrors, because misconfigured mirrors often masquerade as proxy failures when a GEOIP rule grabbed GitHub traffic domestically while model API calls rode a different path with disparate latency budgets.
Docker Desktop note: On Windows and macOS, image pulls often traverse a Linux VM that host-only TUN does not see. Forward Clash Mixed port into Docker Desktop proxy settings, or run compose inside WSL with Linux TUN as described in our WSL2 proxy guide, before concluding OpenHands images are unreachable.
Reorder split routing so Docker Hub, GitHub, npm, and model APIs stay paired
Most community profiles end with broad GEOIP or MATCH directives intended to send domestic destinations direct. That pattern is reasonable for general browsing yet dangerous for autonomous agents: Docker registry CDNs, GitHub raw and LFS edges, npm tarball hosts, and multi-cloud model API anycast can resolve to addresses GEOIP databases still label as onshore even when your organizational policy demands exporting them through an inspected offshore egress for reliability. A healthier approach dedicates a narrowly tested outbound group—call it DevTool-Proxy with latency-aware failover—to scoped DOMAIN-SUFFIX lines covering namespaces you justify from telemetry instead of copy-pasting ancient rule dumps from forums.
Baseline coverage for OpenHands workflows typically includes Docker distribution hosts (docker.io, registry-1.docker.io, and any CDN hostnames docker pull logs reveal), GitHub namespaces (github.com, githubusercontent.com, api.github.com, objects.githubusercontent.com when LFS appears), npm registry hosts (npmjs.org plus tarball subdomains from npm view output), and whichever LLM providers you enable. Anthropic traffic commonly centers on api.anthropic.com; OpenAI on api.openai.com and related CDN hosts; Google AI on generativelanguage.googleapis.com or region-specific endpoints documented for your API version. Place these directives above blunt domestic defaults so first-match semantics cannot accidentally send one leg of a multi-request workflow direct while another leg proxies, producing subtle timing failures inside long agent loops that look like model unavailability.
# Example developer-tooling block — replace DevTool-Proxy with your group
DOMAIN-SUFFIX,docker.io,DevTool-Proxy
DOMAIN-SUFFIX,github.com,DevTool-Proxy
DOMAIN-SUFFIX,githubusercontent.com,DevTool-Proxy
DOMAIN-SUFFIX,npmjs.org,DevTool-Proxy
DOMAIN-SUFFIX,anthropic.com,DevTool-Proxy
DOMAIN-SUFFIX,openai.com,DevTool-Proxy
DOMAIN-SUFFIX,googleapis.com,DevTool-Proxy
# Add custom model gateway DOMAIN lines from OpenHands logs.
Iterate using evidence: export CSV snippets from Clash dashboards, line them up with timestamps from Docker events or OpenHands verbose logs, and annotate which rule IDs first matched. Teams that skip this documentation step rediscover the same YAML puzzles after every intern onboarding wave. If your enterprise runs internal mirrors for containers or npm, add their suffixes explicitly and verify certificate trust; MITM appliances frequently surface as hung TLS rather than crisp HTTP errors, which wastes hours chasing “OpenHands” tickets that were always interception policy drift.
Bridge Clash policy into Docker Compose sandboxes
Host TUN cannot magically steer every packet that originates inside a bridge-networked sandbox. Once base images pull successfully, OpenHands runtime containers still execute git fetch, pip install, and occasional npm ci from environments that start with empty proxy variables. The fix is deliberate bridging, not hope. Point Docker Desktop or daemon-level HTTP proxies at your Clash Mixed listener documented in client settings, or inject HTTP_PROXY and HTTPS_PROXY into the compose services OpenHands documents, ensuring values reference a host-accessible IP (host.docker.internal on Docker Desktop, gateway IP on Linux) rather than 127.0.0.1 inside the container network namespace.
When security policy forbids global daemon proxies, scope env vars only to the OpenHands controller and sandbox services, leaving unrelated stacks untouched. Pair env bridging with NO_PROXY lists for internal registries and metadata endpoints your orchestrator must reach directly. After edits, exec into a running sandbox and curl GitHub and npm metadata to confirm the same outbound tags appear in Clash logs as on the host. Our Mihomo Docker compose guide explains port mapping patterns that keep Mixed listeners reachable from container networks without exposing them broadly on LAN.
Evidence discipline: When a teammate reports “OpenHands worked yesterday,” ask for Clash logs with rule identifiers plus docker compose logs in the same incident folder. Correlating timestamps removes guesswork about whether the regression was DNS, registry mirror drift, GitHub rate limiting, or an API quota change.
GitHub clones and API traffic deserve first-class rules
Autonomous agents touch GitHub constantly: cloning repositories, opening pull requests via API, downloading Actions artifacts, and fetching release assets. Each operation may hit a different hostname even though operators mentally bucket everything as “GitHub.” A clone might succeed through github.com while LFS or release downloads stall on githubusercontent.com because only the former matched your DevTool group. Worse, unauthenticated API calls may traverse a domestic path with aggressive rate limiting while authenticated REST calls proxy successfully, producing confusing “works in curl, fails in agent” reports.
Add explicit suffix coverage for API and CDN hosts, then verify with both anonymous rate-limit probes and token-backed requests using the same credentials OpenHands stores. If your organization routes GitHub Enterprise Server separately, mirror those domains in YAML rather than assuming public suffix lists apply. Cross-read our Cursor, GitHub, and npm split routing article when OpenHands shares a workstation with other AI editors that also hammer GitHub and the npm registry.
npm and language package managers inside sandboxes
Even Docker-first workflows still invoke Node tooling. OpenHands plugins, evaluation harnesses, and local dev setups may run npm install on the host before compose starts, or trigger JavaScript tooling inside sandboxes when tasks target frontend repositories. Treat npm metadata and tarball hosts as peers to Docker and GitHub in your DevTool group. When installs succeed on the host but fail in containers, compare resolver output and proxy env vars side by side—nine times out of ten the container still lacks bridging while host TUN works perfectly.
Corporate npm mirrors deserve the same explicit YAML entries as public npmjs.org. Postinstall scripts that reach GitHub Releases or S3 artifact buckets need log-derived DOMAIN lines; agents amplify those fetches across hundreds of tasks per day, turning a rare timeout into a constant outage signal.
Align Clash DNS, FakeIP, and Docker’s embedded resolver
FakeIP remains one of the sharpest tools in Meta-class cores when domain-based rules must steer traffic deterministically, yet it fails quietly when Docker’s internal DNS forwards to upstream resolvers that disagree with Clash’s answers. Misaligned paths produce symptoms where TLS handshakes start against unexpected IPs, causing split rules to miss until caches expire—exactly the nondeterminism that makes OpenHands agent sessions feel “flaky” despite a stable outbound node.
Reconcile resolver policy with the suffix list you maintain for Docker Hub, GitHub, npm, and provider APIs. When adjusting fake-ip-filter or nameserver policies, retest both bare domain curls on the host and equivalent curls from inside a sandbox container because each layer may resolve hostnames at different moments in the task lifecycle. Our deeper walkthrough on Meta core DNS leak prevention expands the mechanics; treat DNS as part of routing, not an afterthought bolted on once YAML snippets compile.
Multi-provider model APIs are separate budgets from image pulls
Successful docker compose up does not guarantee comfortable API headroom across every LLM you configure in OpenHands. Anthropic, OpenAI, and Gemini endpoints enforce distinct rate limits, TLS behaviors, and regional routing. Agentic loops can fan out into hundreds of metadata fetches per task when repositories are large or tools return verbose JSON. When those requests traverse a policy path with smaller effective bandwidth or higher loss than tarball downloads, operators observe “agent stalls” unrelated to model quality. Monitoring rate-limit headers during scripted checks clarifies whether throttling is structural rather than geographic.
Combine API probes with authenticated contexts: exercise the same API keys OpenHands stores in secret files, not anonymous curls that paint an unrealistically rosy picture. If you route OpenAI traffic through compatible gateways, add their hostnames explicitly rather than assuming a single openai.com suffix covers every redirect. Cross-read provider-specific guides on this site—Claude routing, ChatGPT and OpenAI API splits, and Gemini CLI timeouts—when you mix providers inside one OpenHands deployment.
Verification playbook you can rerun after every profile edit
Adopt a written checklist so network tweaks stay reproducible. Begin with a cold baseline: briefly note timeout frequencies without Clash to understand ambient ISP noise, then enable TUN and disable competing VPN overlays that fight over routing tables. Reload YAML after inserting Docker, GitHub, registry, and provider suffix lines and confirm via preview tools that representative URLs select the outbound group you expect before touching production tokens.
- Registry sanity: query Docker Hub v2 API metadata and pull a medium OpenHands-related image tag twice, comparing layer download speeds.
- GitHub sanity: call rate-limit endpoints with and without tokens OpenHands uses; clone a small public repo from the same environment compose employs.
- npm sanity: fetch packument JSON for a package your evaluation harness imports; download one tarball referenced in metadata.
- Provider authentication: call a lightweight authenticated endpoint per enabled model API and capture rate-limit headers.
- Sandbox bridge check: exec into a running OpenHands worker and repeat GitHub and npm curls, confirming Clash logs show the DevTool group.
- Agent smoke task: run a short OpenHands scenario that clones a repo, installs a dependency, and completes at least one LLM turn.
- DNS cross-check: compare answers from Clash-internal resolvers, OS stub, and Docker embedded DNS for each critical hostname.
- Regression logging: archive connection CSV exports alongside compose stdout so the next engineer inherits context.
Repeat the battery whenever subscriptions rotate, interns change default profiles, or IT pushes new TLS inspection roots. Stability for open source agent platforms rarely comes from heroic one-off tweaks; it comes from boring reproducibility that survives staff churn and hardware refreshes without rediscovering the same asymmetric routing traps between host, daemon, and sandbox.
FAQ
Why does the OpenHands UI load but compose pull hangs?
The UI may be served locally while image layers still fetch through Docker infrastructure that bypassed your shell proxy exports. Fix daemon or Desktop proxy settings, or bridge Mixed port into compose services, then confirm pulls in Clash logs.
Are environment variables a substitute for TUN?
They can unblock quick tests but rarely cover docker pull, nested sandboxes, and background workers your CI uses in production-like setups without consistent bridging into containers.
Which domains deserve explicit YAML entries for OpenHands?
Anchor on Docker Hub suffixes, GitHub API and CDN hosts, npm registry lines, provider API domains you enable, and any custom gateways from config—then refine with log-derived entries for SSO or corporate mirrors.
Does Windows TUN steer Docker Desktop automatically?
Expect manual bridging into the Docker VM or WSL-side Clash; verify with pull logs and traceroutes from both host and container before blaming OpenHands releases.
Tradeoffs, compliance, and realistic expectations
Transparent tunnels increase the security review surface: kernel extensions on macOS, privileged helpers on Windows, and routing table ownership on Linux all attract scrutiny from desktop teams balancing usability against supply-chain risk. Routing all developer and container traffic through offshore inspection nodes may collide with data residency policies, especially when OpenHands touches proprietary repositories or exfiltrates code context to cloud LLMs. Document dual-control approvals alongside YAML diffs so compliance partners understand why Docker Hub, GitHub, and model API hosts share an express lane distinct from general browsing defaults.
Clash cannot salvage exhausted API quotas, revoked tokens, Docker Hub pull rate limits on anonymous accounts, or genuine outages on provider infrastructure. It can, however, remove the pervasive class of intermittent failures driven by uneven terminal proxy coverage—where half the toolchain whispers through SOCKS while Docker and sandboxes stumble over domestic paths never sized for large image layers, Git LFS transfers, or bursty multi-provider model API traffic. That separation matters because the OpenHands narrative in 2026 assumes always-on autonomous assistance; networks that treat containers as second-class citizens silently undermine that promise.
Closing perspective
Community excitement around OpenHands emphasizes seamless pairing between local sandboxes, GitHub-backed repositories, and cloud reasoning—yet the operational truth remains stubbornly mechanical: if Docker Hub cannot deliver images, if GitHub API calls gasp behind mis-sorted rules, or if npm and LLM endpoints time out inside bridge networks, no amount of prompt tuning rescues the experience. Elevating interception with Clash TUN on the host, pairing registry suffix coverage with GitHub and provider APIs, bridging proxy policy into compose, and treating DNS as a first-class routing input converts mystifying timeouts into logged, reproducible incidents analysts can close.
Competing one-click VPN clients often excel at browser traffic while leaving Docker daemons and sandboxes behind, and hand-rolled proxy exports degrade the moment compose spawns workers without inherited environments. Clash centralizes policy and live connection logs so browsers, terminals, and containers can ride the same Meta YAML instead of arguing over duplicated exports. If OpenHands installs or agent tasks still drop mid-flight after the May 2026 hype cycle, download Clash, enable TUN using the steps above, refine split routing and DNS deliberately, then bake the verification playbook into your team runbook.