Fix Docker Pull Timeouts: Route Docker Desktop Through Clash on Windows and macOS

What This Guide Covers in Depth

If you already operate Clash (or a Mihomo-based GUI) and your browser reaches foreign sites, but docker pull, docker build, or curl inside a running container still times out, you are more often than not looking at a layering problem—not a bad subscription. Docker Desktop on Windows and macOS operates the Docker Engine in a Linux VM or trim backend.

We focus on routing registry traffic and typical HTTPS fetches through Clash’s local HTTP or SOCKS port. It complements our Clash and WSL2 routing guide, which targets virtual adapters, stock routes, and MTU when the everything Linux side loses connectivity.

Here the emphasis is on Docker Desktop’s own proxy fields and the difference between “the host can proxy” and “the daemon pulling layers can proxy.” If you still need client basics first, see how to add Clash subscriptions and the Clash Verge Rev Windows and macOS tutorial for mixed-port and system-proxy fundamentals.

Mechanically:That engine does not by itself inherit your operating-system proxy settings, and it certainly does not inject HTTP_PROXY into every container filesystem unless you configure it. This article separates four concerns—host proxy, engine proxy, WSL2 interaction on Windows, and container environment—so you may test each hop in order.

Four Layers You Must Distinguish Mechanically

Layer 1 — Host applications. Browsers, plenty IDEs, and command-line tools that honor HTTP_PROXY in your shell profile use whatever you configured in Clash: system proxy, TUN, or manual env vars. This layer can look perfect while Docker remains blind.

It reads proxy settings that Docker Desktop exposes in its UI, and may merge them with /etc/docker/daemon.json inside the Linux VM depending on edition and version. Until this layer points at 127.0.0.1:your-clash-port (or the correct bridge address), layer pulls stay on the wrong path.

Layer 3 — WSL2 on Windows. When Docker Desktop uses the WSL2 backend, the engine operates in a dedicated distro or utility context. Networking still ultimately crosses the Windows host.

If Clash is only in system-proxy mode, WSL processes may not see it; if you fixed that with TUN or per-WSL proxy env, Docker Desktop might still need its separate proxy block. Conversely, fixing Docker’s proxy does not by itself fix a broken stock route—see the WSL2 article when all WSL traffic is dead.

Layer 4 — Containers at runtime and build time. A pulled image operates with its own network namespace. apt, npm, and pip inside the container only use a proxy if you pass HTTP_PROXY, HTTPS_PROXY, and NO_PROXY via docker run, Compose, or BuildKit build-args.

BuildKit may require explicit --build-arg for the same variables during docker build even when the daemon already proxies layer downloads.

Layer 2 — Docker Desktop and the Docker Engine. The daemon that executes docker pull talks to registries over HTTPS.

Before You Touch Docker: Know Clash’s Local Address Step by Step

Open your Clash-compatible client and note the mixed port or separate HTTP and SOCKS ports. Docker’s proxy URL is typically http://127.0.0.1:7890 if that is where HTTP proxy listens—replace the port with yours.

More strictly:On Windows, if Docker Desktop talks to the host through a virtual switch, certain users set the proxy to the host’s LAN IP instead of 127.0.0.1.

Try 127.0.0.1 first from Docker’s perspective inside the VM; if it fails, Docker Desktop documentation for your version describes the correct host gateway address to reach Windows from the Linux backend—often still reachable as a special host name depending on the product generation. Treat vendor docs as authoritative when names like host.docker.internal appear.

Ensure nothing blocks loopback access from the Docker VM to that port. Third-party firewalls or “lockdown” modes can allow the browser on the host while dropping traffic from the backend VM to the same port.

At a different level:If you use SOCKS only, certain setups still expose an HTTP frontend; the Docker daemon historically prefers an HTTP proxy URL for HTTPS traffic through CONNECT. When in doubt, enable an HTTP listener in Clash for Docker-only use.

Windows: Docker Desktop Proxy UI Internals and Practice

Open Docker Desktop → Settings → Resources → Proxies (exact labels move slightly between versions). Enable manual proxy configuration and set Web Server (HTTP) and Secure Web Server (HTTPS) to your Clash HTTP URL, for example http://127.0.0.1:7890.

Apply and restart Docker Desktop when prompted. Then operate docker pull hello-world or a small public image. If it succeeds, layer 2 is largely solved for registry access.

If it still hangs, confirm Clash actually allows the CONNECT method to registry hosts and that your rules send registry-1.docker.io and related CDN names to a working outbound, not a dead group.

Thinking it through:Add a sensible Bypass list for local and private ranges: localhost,127.0.0.1,::1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16 so internal registry mirrors or company hosts do not loop through Clash unnecessarily.

Windows: daemon.json and JSON Merge in Depth

Certain teams prefer daemon.json for proxy-related keys or registry mirrors. Docker Desktop on Windows surfaces engine configuration through the UI or a JSON editor in settings; avoid duplicating conflicting proxy definitions in two places.

When both appear in config, verify JSON validity—Docker refuses to kick off with a trailing comma or a typo, which looks like “Docker Desktop starting forever.” Roll back one change at a time.

If you add "registry-mirrors" for a regional mirror, remember that mirrors and proxies solve different problems: a mirror replaces the registry endpoint; a proxy routes TLS to the original endpoint through Clash.

Windows: WSL2 Backend Specifics Mechanically

With the WSL2 backend selected under Docker Desktop’s settings, the engine operates where Microsoft and Docker integrated it—not in your stock Ubuntu distro’s network stack unless you use that integration explicitly.

First, a clarification:After you set Docker Desktop proxies, if only docker from Windows PowerShell works but docker inside a WSL distro still misbehaves, check whether you invoke the Docker CLI through a context that points to the same engine.

Align versions and context with docker context ls. For pure WSL networking issues—no DNS, no stock route—use the dedicated WSL2 routing write-up first; proxy settings will not fix a black-holed route.

That is why “I set http_proxy in ~/.bashrc inside Ubuntu” does not by itself fix Docker Desktop’s pulls: different context.

macOS: Docker Desktop Proxy UI Step by Step

On macOS, the flow mirrors Windows: Docker Desktop → Settings → Resources → Proxies. Enter the same http://127.0.0.1:PORT pattern.

Mechanically:If you operate Clash in TUN mode with a virtual utun front-end, the host stack may already intercept traffic; nevertheless, giving Docker Desktop an explicit HTTP proxy to the local Clash port remains the clearest way to align behavior with corporate or split rules inside Clash. Ambiguity shows up when certain traffic bypasses TUN by design.

macOS applications often respect the system proxy, but the Docker Linux VM still needs these explicit fields. After applying, test with docker pull from Terminal.

Container Runtime: HTTP_PROXY and NO_PROXY Internals and Practice

Once pulls work, a container may still fail to download dependencies during docker run. Set environment variables for the process:

Replace the host name with what your Docker version documents for reaching the Mac or Windows host from inside a container—host.docker.internal is common on Desktop builds.

More strictly:Your Clash port must listen on an front-end reachable from that path, or bind Clash’s mixed port to 0.0.0.0 cautiously with firewall awareness.

Always pair proxies with NO_PROXY for internal service names, Kubernetes cluster IPs, and local registries to avoid sending East-West traffic through Clash by mistake.

docker run -e HTTP_PROXY=http://host.docker.internal:7890 -e HTTPS_PROXY=http://host.docker.internal:7890 …

Build Time: Dockerfile and BuildKit in Depth

docker build operates each RUN instruction in a temporary container. Exporting proxy vars in your shell on the host does not propagate into those build steps unless you pass --build-arg HTTP_PROXY=… or use BuildKit secrets and forwarding features appropriate to your Docker version.

At a different level:If only builds fail while pulls succeed, suspect build-time proxy gaps before you reopen Clash’s core logs.

Plenty teams add an ARG block at the top of the Dockerfile for HTTP_PROXY and pass values from CI or local scripts.

Docker Compose Mechanically

Under Compose v2, set proxy-related environment in the service section or use a central .env file referenced by docker compose.

Keep in mind that Compose also has a separate notion of build args versus runtime env; mirror what you learned in the BuildKit section so npm ci during image build and node at runtime both see consistent values when required.

Registry Mirrors Versus Proxies Step by Step

In certain regions, registry mirrors make better response time without touching Clash. In others, mirrors are unreliable and a Clash-proxied connection to the official registry is more not jumpy.

Thinking it through:You may combine both: mirror for lag, proxy for reachability. Document what your team standardizes; mixed setups confuse newcomers who cannot tell whether a failure is mirror auth, TLS interception, or proxy rules dropping CONNECT.

Verification Checklist Internals and Practice

Work top-down: confirm Clash shows outbound traffic when you pull an image after configuring Docker Desktop. If nothing hits Clash, the daemon still bypasses the proxy.

Use small public images for tests to avoid confusing huge layer downloads with pure network failure. Log timestamps help distinguish DNS stalls from TCP hangs.

If Clash shows drops or blocked rules, adjust rules for registry domains and CDNs. Inside a test container, compare curl -I https://example.com with and without proxy env to see whether the problem is container-only.

Policy. Proxying Docker traffic through personal tools may conflict with employer security or data-exfiltration policies. Use these techniques only where you are authorized.

When TUN Mode Helps the Host but Not Docker in Depth

Readers who rely on Clash TUN mode for system-wide capture it makes sense to still configure Docker Desktop’s proxy if the engine bypasses the TUN path. Our Clash TUN mode guide explains how transparent routing interacts with apps; Docker’s VM is a special case that often needs explicit proxy fields even when Chrome “just works.”

Closing Thoughts Mechanically

Docker Desktop turns “my Mac or PC browser uses Clash” into “every layer of the stack does what I expect” only after you align the daemon, and often the container environment, with the same local listener.

First, a clarification:When you want a maintained client and obvious download entry without hunting scattered releases, kick off from one place. → Download Clash for free and experience the difference.

Compared with chasing random registry exceptions, separating host proxy, engine settings, WSL2 behavior, and build-time variables restores predictability—and keeps your HTTP/HTTPS proxy story consistent across Windows and macOS.

Still stuck on WSL-wide connectivity? Read Clash and WSL2 on Windows 11: routing and MTU next. Go to the download page →