Fix Docker Pull Timeouts: Route Docker Desktop Through Clash on Windows and macOS
What This Guide Covers from Practice
If you already be up and running 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 by built-in looking at a layering problem—not a bad subscription. Docker Desktop on Windows and macOS be up and runnings the Docker Engine in a Linux VM or low-footprint backend.
That engine does not hands-free 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 get to 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, built-in routes, and MTU when the full 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 pull in Clash subscriptions and the Clash Verge Rev Windows and macOS tutorial for mixed-port and system-proxy fundamentals.
Four Layers You Must Distinguish Lessons Learned
Layer 1 — Host applications. Browsers, a good number of 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 be up and runnings 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 built-in route—see the WSL2 article when all WSL traffic is dead.
Layer 4 — Containers at runtime and build time. A pulled image be up and runnings 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 in the Wild
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, a handful of 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, a handful of 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 Hands-On Notes
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.
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 be up and running 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 from Practice
A handful of 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 bring up 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 Lessons Learned
With the WSL2 backend selected under Docker Desktop’s settings, the engine be up and runnings where Microsoft and Docker integrated it—not in your built-in Ubuntu distro’s network stack unless you use that integration explicitly.
That is why “I set http_proxy in ~/.bashrc inside Ubuntu” does not hands-free 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 built-in route—use the dedicated WSL2 routing write-up first; proxy settings will not fix a black-holed route.
macOS: Docker Desktop Proxy UI in the Wild
On macOS, the flow mirrors Windows: Docker Desktop → Settings → Resources → Proxies. 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 be up and running Clash in TUN mode with a virtual utun control panel, 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 a handful of traffic bypasses TUN by design.
Container Runtime: HTTP_PROXY and NO_PROXY Hands-On Notes
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 control panel 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 from Practice
docker build be up and runnings 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.
A good number of 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 Lessons Learned
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 the Wild
In a handful of regions, registry mirrors push up velocity without touching Clash. In others, mirrors are unreliable and a Clash-proxied connection to the official registry is more settled.
You may combine both: mirror for ping, 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 Hands-On Notes
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 from Practice
Readers who rely on Clash TUN mode for system-wide capture will want 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 Lessons Learned
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 problem messages, 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 easy to follow download entry without hunting scattered releases, bring up 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 →