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

What This Guide Covers

If you already run 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 usually looking at a layering problem—not a bad subscription. Docker Desktop on Windows and macOS runs the Docker Engine in a Linux VM or lightweight backend. That engine does not automatically 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 can test each hop in order.

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, default routes, and MTU when the whole 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 import Clash subscriptions and the Clash Verge Rev Windows and macOS tutorial for mixed-port and system-proxy fundamentals.

Four Layers You Must Distinguish

Layer 1 — Host applications. Browsers, many 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.

Layer 2 — Docker Desktop and the Docker Engine. The daemon that executes docker pull talks to registries over HTTPS. 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 runs 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 default route—see the WSL2 article when all WSL traffic is dead.

Layer 4 — Containers at runtime and build time. A pulled image runs 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.

Before You Touch Docker: Know Clash’s Local Address

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. If you use SOCKS only, some 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.

On Windows, if Docker Desktop talks to the host through a virtual switch, some 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.

Windows: Docker Desktop Proxy UI

Open Docker DesktopSettingsResourcesProxies (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. 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.

Apply and restart Docker Desktop when prompted. Then run 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.

Windows: daemon.json and JSON Merge

Some 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. 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.

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

Windows: WSL2 Backend Specifics

With the WSL2 backend selected under Docker Desktop’s settings, the engine runs where Microsoft and Docker integrated it—not in your default Ubuntu distro’s network stack unless you use that integration explicitly. That is why “I set http_proxy in ~/.bashrc inside Ubuntu” does not automatically fix Docker Desktop’s pulls: different context.

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 default route—use the dedicated WSL2 routing write-up first; proxy settings will not fix a black-holed route.

macOS: Docker Desktop Proxy UI

On macOS, the flow mirrors Windows: Docker DesktopSettingsResourcesProxies. Enter the same http://127.0.0.1:PORT pattern. 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.

If you run Clash in TUN mode with a virtual utun interface, 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 some traffic bypasses TUN by design.

Container Runtime: HTTP_PROXY and NO_PROXY

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

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

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. Your Clash port must listen on an interface 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.

Build Time: Dockerfile and BuildKit

docker build runs 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. Many teams add an ARG block at the top of the Dockerfile for HTTP_PROXY and pass values from CI or local scripts.

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

Docker Compose

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

In some regions, registry mirrors improve speed without touching Clash. In others, mirrors are unreliable and a Clash-proxied connection to the official registry is more stable. You may combine both: mirror for latency, 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

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. 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.

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.

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

Readers who rely on Clash TUN mode for system-wide capture should 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

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. Compared with chasing random registry errors, 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.

When you want a maintained client and clear download entry without hunting scattered releases, start from one place. → Download Clash for free and experience the difference.

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