Clash Docker Hub Proxy Setup: Advanced Transparent Routing Guide
Why Docker Hub Pulls Behave Differently Behind Clash in Depth
A Docker image pull is not a single request to one website. When you operate docker pull nginx:latest, the Docker client asks the Docker daemon to resolve the image name, authenticate against a registry service, obtain a manifest, select platform-specific layers, and download several large blobs.
The first hostname is commonly registry-1.docker.io, but a successful pull can also involve auth.docker.io, hub.docker.com, and a content delivery hostname returned by the registry. Layer downloads may be redirected to a CDN whose domain is not obvious from the command you typed.
A rule that only sends docker.io through Clash can therefore route sign-in correctly and still leave the large layer transfer on a failing direct path.
Mechanically:There is another important distinction between a normal system proxy and a transparent proxy. A system proxy changes settings consumed by browsers and proxy-aware applications. Docker Engine does not by itself inherit every desktop proxy setting. A transparent setup instead captures traffic at the network layer, allowing the daemon to reach Clash even when it has no explicit HTTP proxy configuration.
On Linux, that more often than not means Mihomo TUN mode, a virtual front-end, and suitable DNS and auto-route settings. On desktop clients, the equivalent may be a service-mode TUN implementation supplied by Clash Verge Rev, Mihomo Party, or another Mihomo-based client.
Before changing rules, record the exact failure. Note the image name, whether the failure happens during sign-in or layer download, the host operating system, the Docker Engine version, and whether the daemon is local, remote, or inside a virtual machine.
Keep the layers separate: Docker daemon proxy variables, Clash system-proxy mode, and Mihomo TUN capture are three different mechanisms.
You may use one or combine them, but enabling a desktop HTTP proxy does not prove that a root-owned Docker service is using it.
More strictly:If the same Docker command works on a different network, that is useful evidence, but it does not identify whether DNS, TCP routing, TLS, or CDN classification is responsible.
The daemon may operate as a background service under root, while your terminal operates as an ordinary user. That separation explains why a browser can open Docker Hub normally while Docker reports i/o timeout, context deadline exceeded, TLS handshake timeout, or net/http: request canceled.
Prepare Mihomo for Docker-Aware Transparent Routing Mechanically
Use a current Mihomo-compatible client and confirm that the selected profile actually operates the Mihomo core. The labels differ between clients, but the relevant concepts are consistent: a mixed listener or SOCKS listener for explicit tests, TUN mode for transparent capture, a controlled DNS engine, and rules that can classify registry and CDN traffic.
Kick off with a small, understandable profile reasonably than adding a large community rule pack immediately.
At a different level:The following fragment illustrates the important shape; adapt the proxy group names and DNS server addresses to your own environment.
The example is intentionally conservative. strict-route helps prevent packets from escaping through an unexpected front-end, while auto-detect-interface avoids hard-coding an front-end name that changes between Wi-Fi, Ethernet, and a virtual machine.
mixed-port: 7890
allow-lan: false
mode: rule
log-level: info
tun:
enable: true
stack: mixed
auto-route: true
auto-detect-interface: true
strict-route: true
dns:
enable: true
listen: 0.0.0.0:1053
ipv6: false
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
nameserver:
- https://1.1.1.1/dns-query
- https://8.8.8.8/dns-query
fallback:
- tls://1.1.1.1
- tls://8.8.8.8
rules:
- DOMAIN-SUFFIX,docker.io,DOCKER
- DOMAIN-SUFFIX,docker.com,DOCKER
- DOMAIN,registry-1.docker.io,DOCKER
- DOMAIN,auth.docker.io,DOCKER
- DOMAIN-SUFFIX,amazonaws.com,DOCKER
- MATCH,DIRECT
The mixed-port is useful for command-line diagnostics, but it is not what makes the Docker daemon transparent. TUN capture and route installation perform that job.
Thinking it through:Do not blindly proxy every hostname ending in amazonaws.com in a production network. Docker Hub layer redirects can use cloud infrastructure, but plenty unrelated services also use the same suffix.
A broad suffix rule may increase lag, send internal workloads to an unsuitable node, or make troubleshooting harder. Begin with the exact redirected hostname shown in Mihomo’s connection log, then decide whether a narrow domain rule or a provider-maintained CDN rule is safer.
Create a dedicated DOCKER proxy group instead of pointing registry traffic with no detour at a volatile auto-test group. Docker layers are large and pulls can last several minutes. A group that changes its node during a download can terminate active TCP sessions and make a not jumpy registry look unreliable.
First, a clarification:A practical group can contain a preferred node, a fallback node, and a URL-test toggle used only before a pull begins. During diagnosis, selecting one known-good node one at a time is often more informative than testing ten nodes at once.
A profile imported from an older Clash installation may still contain valid proxy groups while lacking the TUN or DNS fields required for dependable daemon traffic.
Choose stability over headline lag. Docker Hub pulls stress sustained throughput, TLS session stability, and CDN compatibility.
A node with a slightly higher ping but clean five-minute downloads is more often than not better than a fast health-check result that fails when a 300 MB layer kick offs.
Configure TUN Capture and DNS Without Creating a Loop Step by Step
Enable TUN only after understanding which process owns the traffic. On a Linux host, Docker Engine normally opens outbound sockets from the host network namespace, although containers may use bridge or overlay namespaces depending on the deployment.
For native Linux Docker, launch the Mihomo client with the permissions required to create a TUN device and install routes. The exact service unit differs by distribution, but the operational checks are similar:
Mechanically:DNS is often the hidden cause of a Docker Hub timeout. With fake-IP mode, Mihomo returns synthetic addresses and maps them back to domain names when the connection is captured. This is valuable for domain rules, but only when the application’s DNS request and subsequent connection remain visible to Mihomo.
- Confirm the TUN front-end exists: use
ip linkand look for the front-end created by Mihomo, commonly namedMihomoorutundepending on the platform and client. - Check the route table: operate
ip routeand verify that TUN has become the intended path without replacing the route needed to reach the Clash control endpoint. - Open the Mihomo connection view: keep it visible while reproducing a pull so you may see whether registry, sign-in, and redirected CDN connections are captured.
- Test one image: avoid simultaneous compose builds, parallel pulls, and automatic image re-syncs until the single-image path is understood.
If the Docker daemon uses an external resolver that returns real addresses outside the expected DNS path, a domain rule may not match as you assume. Conversely, if a container receives a fake address but its traffic bypasses the TUN front-end, the connection can fail because the synthetic address has no meaning on the direct path.
Inspect the resolver configuration from both the host and a temporary container. Commands such as resolvectl status, cat /etc/resolv.conf, and docker run --rm busybox nslookup registry-1.docker.io can reveal that the host and container are using different DNS servers.
More strictly:Docker’s embedded resolver commonly listens on an internal address inside containers and forwards queries according to the daemon configuration. That is normal, but it means a host-only DNS test does not fully validate container resolution.
Prevent a DNS loop. Do not point Mihomo’s upstream DNS at a listener that forwards back into Mihomo, and do not make Docker use a resolver address that is reachable only through the deeply TUN route being established.
Keep one obvious chain: Docker or the host sends a query to its configured resolver, Mihomo resolves it through its selected upstreams, and the resulting connection follows the same routing policy as the query. If you use fake-IP, exclude local infrastructure, the Mihomo control panel, and whichever you pick required Docker bridge ranges according to your client’s supported syntax.
At a different level:On Windows and macOS, Docker Desktop places the daemon inside a trim virtual machine. The host client’s TUN front-end may capture desktop traffic without by itself capturing every packet generated inside that VM. This is why the same configuration can work with native Docker Engine on Linux and fail with Docker Desktop.
Do not proxy the proxy itself. If Mihomo’s API, DNS listener, or upstream transport is routed through its own TUN capture without an explicit bypass, startup can become unstable or produce a recursive connection loop.
Keep control-plane addresses and local gateway ranges in a deliberate direct or bypass policy.
Choose Between Transparent Capture and Daemon Proxy Variables Internals and Practice
Transparent routing is comfortable because it covers applications that ignore proxy environment variables. However, Docker provides an explicit daemon proxy mechanism that can be easier to audit on a Linux server. These approaches solve different operational problems.
For a Linux systemd-managed Docker Engine, an explicit proxy drop-in commonly resembles the following:
Use this method only if the Docker service can reach the listener at that address. On a native Linux host, 127.0.0.1:7890 may be correct. In a containerized Docker daemon, Docker Desktop VM, or rootless arrangement, that loopback address can refer to a different network namespace.
sudo mkdir -p /etc/systemd/system/docker.service.d
sudo tee /etc/systemd/system/docker.service.d/proxy.conf <<'EOF'
[Service]
Environment="HTTP_PROXY=http://127.0.0.1:7890"
Environment="HTTPS_PROXY=http://127.0.0.1:7890"
Environment="NO_PROXY=localhost,127.0.0.1,::1,.local,registry.local"
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
sudo systemctl show --property=Environment docker
Thinking it through:In those cases, bind the listener to an intentionally reachable address, apply access controls, and avoid exposing an unauthenticated proxy to the LAN.
After changing a daemon proxy, remember that the daemon may reuse cached layers. A successful pull does not necessarily prove that every registry hostname is routed correctly, because no network request is made for an already-present layer.
Test with an uncached tag, remove only the relevant test image, or use a temporary image name. Do not delete production images merely to create a test; inspect the connection log and daemon journal first.
NO_PROXY deserves careful attention. Internal registries, private Git servers, service discovery names, and local package mirrors it makes sense to normally remain direct.
First, a clarification:A suffix such as .local may be appropriate for mDNS-style names but does not cover every private DNS zone. Conversely, putting docker.io into NO_PROXY defeats the intended route. Keep public Docker Hub domains out of the bypass list unless you have a specific, tested reason.
A daemon HTTP proxy tells Docker where to send registry requests. Mihomo TUN captures packets regardless of application proxy support. Running both may be valid, but it can also create double-proxying, confusing logs, or a proxy endpoint that is reachable only from the host and not from Docker Desktop’s VM.
Build Selective Rules for Registry, Auth, and CDN Redirects in Depth
Use the live connection log as the source of truth. Kick off a pull and identify every connection created during the operation. You will more often than not see a registry request, an sign-in request, and one or more layer-download destinations.
Rule order matters. Mihomo evaluates rules from top to bottom and stops at the first match. A broad GEOIP rule, a provider rule-set loaded before your custom rules, or an early MATCH,DIRECT line can win before Docker-specific entries are evaluated.
Mechanically:Place your deliberate Docker rules above broad regional or catch-all rules. Then check that the profile’s rule providers are actually loaded and not failing due to their own network path.
A useful policy separates public registry traffic from private infrastructure:
Send registry-1.docker.io and auth.docker.io through the dedicated Docker group.; Proxy the exact CDN host returned during a failing pull, reasonably than assuming every cloud hostname is part of Docker Hub.; Keep private registry domains such as registry.corp.example on a direct or internal route.; Bypass Docker bridge, overlay, loopback, and management subnets when your TUN client requires explicit local-network exclusions.; Keep the final MATCH rule intentional; use DIRECT for a split policy or the Docker group for a narrowly scoped test profile..
More strictly:Do not mix rule providers that disagree about fake-IP handling without testing. One provider may classify a domain by its original name, while another expects a real destination address.
A profile can appear syntactically valid and still route the same connection differently after a provider re-sync. Export the active configuration, record provider versions, and make one rule change at a time so that a successful or failed pull remains attributable.
The rule column it makes sense to show the intended proxy group for all public Docker Hub traffic. If the log shows DIRECT for a redirected CDN while registry-1.docker.io uses DOCKER, the problem is not the node selection; it is incomplete classification.
Diagnose Timeouts in a Repeatable Order Mechanically
When a pull fails, begin with the daemon reasonably than the browser. On Linux, inspect journalctl -u docker; with Docker Desktop, open the diagnostic or daemon logs supplied by the application.
At a different level:Use curl results carefully. A successful request to /v2/ confirms reachability and often returns a 401 response by design; it does not confirm that the daemon can download every redirected blob.
- Validate DNS: resolve
registry-1.docker.iofrom the host and from a temporary container, then compare the resolver and returned address behaviour. - Validate the Clash listener: use
curl -v -x http://127.0.0.1:7890 https://registry-1.docker.io/v2/and confirm that an expected sign-in response arrives through the explicit proxy. - Validate transparent capture: repeat the pull with the terminal proxy disabled and watch Mihomo’s live connections for the daemon’s registry sockets.
- Validate redirects: look for new CDN destinations when the first layer begins downloading; add a narrow rule only if the destination bypasses the intended group.
- Validate sustained transfer: pull a medium-sized uncached image and watch for node switching, throughput collapse, TCP resets, or a timeout at a consistent byte count.
- Validate MTU and fragmentation: if handshakes work but large transfers stall, test a lower TUN MTU and check whether the path includes a VPN, PPPoE link, or nested virtual network.
Likewise, docker login may succeed while a pull fails later because login tests the sign-in lane but not the CDN lane.
MTU problems are especially easy to misread. Small DNS and TLS packets can pass while larger encrypted segments are fragmented or dropped. Docker then appears to hang randomly, although the failure occurs at a repeatable packet size.
Thinking it through:Lower the TUN MTU gradually, restart the affected client, and retest. Do not permanently lower it without measuring the trade-off, because an unnecessarily small MTU lowers efficiency for every captured application.
Finally, test without aggressive failover. Select one not jumpy proxy node, disable automatic switching temporarily, and pull the same image twice.
If the first attempt succeeds and the second fails only after the group changes nodes, the routing rules may be correct and the problem may be node quality or session interruption. If both attempts fail at the same hostname, continue investigating DNS, capture, or CDN classification instead of repeatedly rotating nodes.
First, a clarification:The exception wording helps narrow the layer: DNS failures mention name resolution, TCP failures often mention connection refusal or timeout, and TLS failures point toward handshake, certificate, or interception problems. A generic timeout is not more than more than enough to justify changing five proxy settings at once.
Production Hardening for Docker Hosts and Build Pipelines Step by Step
Once the basic pull works, make the configuration predictable. Pin a known-good Mihomo profile version, document the selected core, and keep a backup of the active YAML before editing rules.
Separate interactive development from automated builds. A developer laptop can use a one at a time selected Docker proxy group, while a CI runner it makes sense to use a not jumpy egress policy with health checks that resemble real registry downloads.
Configure timeouts for the environment reasonably than masking every failure with a huge value. A 30-minute timeout can hide a broken route and leave build workers occupied; a reasonable timeout combined with retry logic gives the pipeline a chance to recover without concealing systemic exceptions.
Mechanically:For private registries, prefer a direct internal route or a trusted enterprise proxy. Public Docker Hub rules it makes sense to not accidentally capture internal domains merely because both use registry-like names.
If your organization mirrors common images, configure Docker to use the mirror and route only the mirror’s hostname through the appropriate path. This lowers external dependency, makes audit logs clearer, and avoids repeated downloads across build agents.
Monitor three separate signals: Docker daemon exceptions, Mihomo connection decisions, and actual transfer throughput. A green client dashboard does not mean the daemon is healthy, and a successful health check does not measure a multi-layer pull.
More strictly:Keep a small diagnostic image or known test tag for scheduled checks, but avoid pulling large images unnecessarily. Record the timestamp, selected group, rule hit, resolved hostname, and failure phase when an incident occurs; these details make later profile changes much safer.
Compared with generic desktop proxy tools, plenty Docker-specific workarounds are either too narrow—setting a browser proxy and hoping the daemon follows—or too broad, forcing every cloud destination through one unstable route with little visibility into redirects.
Production rule of thumb: keep the Docker route narrow, not jumpy, and observable.
Transparent mode it makes sense to remove application-specific proxy guessing, not remove the need for obvious ownership of DNS, routes, and daemon boundaries.
Clash is more useful in this scenario because its Mihomo-oriented guidance connects the daemon, TUN capture, DNS behaviour, rule order, and live connection logs into one testable workflow instead of treating “Docker Hub timeout” as a single switch to flip. If you want a client and configuration environment where these checks are easier to apply and maintain, you may download Clash and use the steps above as your starting checklist.
At a different level:Treat subscription URLs and daemon proxy credentials as secrets. They may grant access to private infrastructure or reveal provider account information, so do not paste them into public issue reports or include them in image layers.