Why developers need more than the system proxy
A browser working through Clash does not prove that a development environment is correctly proxied. Browsers usually follow the operating system proxy, while terminal programs, Git, SSH, package managers, Docker, language runtimes, and AI coding tools often use their own connection libraries. Some read HTTP_PROXY and HTTPS_PROXY; some understand only SOCKS5; some ignore proxy variables entirely; and some open connections through a virtual network interface instead.
For development work, the most reliable approach is to separate two functions. Use the local HTTP or mixed port when a command-line tool explicitly supports proxy variables, and use TUN mode when an application does not cooperate with ordinary proxy settings. TUN creates a virtual network interface and routes selected device traffic through the Clash or mihomo core. It can therefore cover more programs, but it also affects DNS, routing, local-network access, permissions, and sometimes container networking.
A typical desktop setup uses a local mixed port such as 127.0.0.1:7890. The actual value depends on the active configuration and client settings. Do not assume that every client uses port 7890, and do not confuse the traffic port with the external controller port. Before changing shell files or Docker settings, confirm the active port under the client’s “Settings” → “Ports” area and verify that the core is running.
| Traffic source | Recommended first method | Why |
|---|---|---|
| Browser or GUI application | System Proxy | Most desktop browsers already read the operating system proxy settings |
| curl, Git, npm, pip, and similar tools | HTTP proxy variables | These tools commonly support HTTP_PROXY, HTTPS_PROXY, and NO_PROXY |
| Programs with no proxy support | TUN mode | Traffic can be intercepted at the network interface and routed by the Clash core |
| SSH | SOCKS5 ProxyCommand or TUN | SSH does not normally use HTTP proxy variables |
| Docker CLI and containers | Separate host and container proxy settings | The Docker daemon, CLI, and each container may use different network paths |
Configure TUN mode safely
Open the client’s “Settings” → “TUN” or equivalent network settings. In Clash Verge Rev, Mihomo Party, and similar mihomo-based clients, the exact labels depend on the release, but the important controls are usually TUN enablement, auto route, strict route, DNS hijack, stack type, and access permissions. TUN mode may require administrator privileges on Windows, a privileged helper on macOS, or root and a suitable service configuration on Linux.
For a first test, use the client’s default TUN settings unless there is a specific reason to change them. A common configuration concept looks like this:
tun:
enable: true
stack: mixed
auto-route: true
strict-route: true
dns-hijack:
- any:53
- tcp://any:53
dns:
enable: true
enhanced-mode: fake-ip
The available fields and supported values vary between mihomo versions and clients. Treat this as a model rather than a configuration to paste blindly. The active client may generate part of the TUN configuration itself, and duplicate or conflicting DNS sections can cause startup errors. Check the client’s rendered configuration or logs after saving changes.
Understand routing and DNS together
TUN mode handles more than the destination address visible in a browser. DNS resolution can determine which address an application connects to, while routing determines whether that address enters the virtual interface. If an application resolves a domain through the operating system DNS and then connects directly to the returned address, the result may differ from a request resolved by Clash. This is why a TUN test can fail even when the proxy node itself is healthy.
Fake-IP mode returns synthetic addresses for domain queries and lets the core map those addresses back to domain names. Redir-host mode returns real addresses and can be simpler for some local-network environments, but domain-based rules may have less information after resolution. Do not switch DNS modes repeatedly without checking the logs. First determine whether the failure is DNS resolution, rule matching, route installation, or the remote connection.
- Core does not start: check administrator permission, TUN driver installation, and whether another VPN application owns the virtual interface.
- Internet works but local devices fail: review
DIRECTrules, private-address handling, and the client’s bypass settings. - Domains resolve but connections time out: inspect the selected policy group, IPv6 behavior, and whether the application bypasses the expected route.
- Every domain fails: check DNS servers, DNS hijack settings, and whether the TUN interface was actually installed.
After enabling TUN, open the Connections page and run a single request. A new entry for the target domain should appear with a rule such as PROXY, DIRECT, or a named policy group. If no connection appears, the process may be excluded, the route may not be active, or the application may be using a separate network namespace.
Set terminal proxy variables deliberately
Terminal proxy variables are useful even when TUN is available. They make a command’s network behavior explicit, work well in remote shells, and avoid routing unrelated local traffic through the virtual interface. A mixed port normally accepts both HTTP proxy requests and SOCKS5 connections, but the URL scheme still matters. For common HTTP-based tools, begin with an HTTP proxy URL:
export HTTP_PROXY=http://127.0.0.1:7890
export HTTPS_PROXY=http://127.0.0.1:7890
export ALL_PROXY=http://127.0.0.1:7890
export NO_PROXY=localhost,127.0.0.1,::1,.local
Some tools distinguish uppercase and lowercase variable names. Setting both forms improves compatibility, but it can also make debugging less obvious if an old value remains in the shell environment.
export http_proxy="$HTTP_PROXY"
export https_proxy="$HTTPS_PROXY"
export all_proxy="$ALL_PROXY"
export no_proxy="$NO_PROXY"
On PowerShell, use environment variables for the current session like this:
$env:HTTP_PROXY = "http://127.0.0.1:7890"
$env:HTTPS_PROXY = "http://127.0.0.1:7890"
$env:ALL_PROXY = "http://127.0.0.1:7890"
$env:NO_PROXY = "localhost,127.0.0.1,::1,.local"
Test the path before changing project configuration. The following commands help separate DNS, proxy, and TLS problems:
curl -I https://example.com
curl -v https://example.com
env | grep -i proxy
On Windows PowerShell, use Get-ChildItem Env: to inspect environment variables. A successful HTTP status proves that the request reached a server, but it does not prove that every development tool will use the same path. Compare the command with the Clash Logs and Connections pages.
Keep local services out of the proxy
NO_PROXY is important for development. Without it, requests to local APIs, loopback services, database ports, Kubernetes endpoints, or internal domains may be sent to Clash unnecessarily. Useful entries commonly include localhost, 127.0.0.1, ::1, .local, private network ranges, and internal company domains. The exact syntax differs between libraries, so verify the behavior of the specific tool.
Do not add a broad entry such as * unless you intentionally want to bypass the proxy for everything. Also remember that NO_PROXY may match hostnames but not every unusual port or address format consistently. If a local request fails after proxy variables are enabled, temporarily unset the variables and compare:
unset HTTP_PROXY HTTPS_PROXY ALL_PROXY http_proxy https_proxy all_proxy
curl -v http://127.0.0.1:3000/health
Configure Git, SSH, and package managers
Git can use the environment variables above, but repository operations are easier to diagnose when the proxy is visible in Git’s own configuration. To set a global HTTP proxy:
git config --global http.proxy http://127.0.0.1:7890
git config --global https.proxy http://127.0.0.1:7890
git config --global --get-regexp 'http.*proxy'
This setting affects HTTP and HTTPS remotes. It does not automatically configure SSH remotes such as [email protected]:org/project.git. For an SSH remote, either use TUN mode or configure a SOCKS5-based ProxyCommand. OpenSSH with a local SOCKS5 listener can use a helper such as nc or a platform-specific equivalent:
Host github.com
HostName github.com
User git
ProxyCommand nc -X 5 -x 127.0.0.1:7890 %h %p
ServerAliveInterval 30
ServerAliveCountMax 3
Not every nc implementation supports -X 5. If the command fails immediately, check the installed netcat variant, use a compatible SOCKS helper, or let TUN route SSH directly. Test the connection with ssh -vT [email protected] and inspect whether Clash records the destination. A successful SSH handshake may still be followed by a repository permission error, which is an authentication issue rather than a proxy issue.
Package managers often need separate configuration because they may run background processes or use their own HTTP libraries:
- npm: use
npm config set proxy http://127.0.0.1:7890andnpm config set https-proxy http://127.0.0.1:7890. Check withnpm config get proxy. - pnpm: review the npm-compatible proxy settings and any project-level
.npmrcfile. - pip: use
pip install --proxy http://127.0.0.1:7890 package-namefor a one-time test, or configure the relevant user settings after confirming the path. - Python requests: it commonly reads proxy environment variables, unless the session explicitly disables environment trust.
- Go: the module downloader commonly uses
HTTPS_PROXY,HTTP_PROXY, andNO_PROXY; private module domains should usually be excluded withGOPRIVATEas well. - Rust Cargo: review
~/.cargo/config.tomland environment variables separately, especially when a project uses a custom registry.
Handle Docker Hub and container networking
Docker has several independent network paths. The Docker CLI communicates with the Docker daemon; the daemon pulls images from Docker Hub; and a running container makes its own outbound requests. Configuring a proxy in the terminal may affect the CLI but not the daemon. Configuring TUN on the host may help host applications while still failing to route traffic from a Linux virtual machine, Docker Desktop VM, or isolated container network.
When image pulls fail, first determine whether the failure occurs during docker pull or inside the container. Check the daemon logs and test a small public image:
docker pull hello-world
docker run --rm curlimages/curl:latest -I https://example.com
For a Linux Docker daemon, proxy settings are commonly configured through the daemon’s service environment, often with a systemd drop-in. The exact file location depends on the distribution and installation method. A conceptual configuration looks like this:
[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,registry.local"
Using 127.0.0.1 here is correct only when the daemon can reach the host proxy at its own loopback address. In Docker Desktop or a virtualized environment, the daemon may run inside a VM, where 127.0.0.1 points to the VM rather than the host. The client may provide a host gateway name or a dedicated proxy setting. Do not expose a proxy with allow-lan: true merely to make Docker work unless you understand the firewall and authentication consequences.
For a container’s own outbound traffic, pass proxy variables explicitly during testing:
docker run --rm \
-e HTTP_PROXY=http://host.docker.internal:7890 \
-e HTTPS_PROXY=http://host.docker.internal:7890 \
-e NO_PROXY=localhost,127.0.0.1 \
curlimages/curl:latest -I https://example.com
The hostname host.docker.internal is commonly available in Docker Desktop, but Linux installations may require an explicit host-gateway mapping. If the container uses a corporate certificate, private registry, or internal DNS, proxy reachability alone will not solve certificate or name-resolution errors.
Use the same workflow for AI coding tools
AI coding tools may include a desktop interface, a terminal command, an extension, and background helper processes. These components do not necessarily share the same proxy settings. A terminal command may read HTTPS_PROXY, while an editor extension follows the editor’s network setting, and a desktop application may use system proxy or TUN. Diagnose each process separately.
Start with a small request from the same terminal session that launches the tool. Confirm the tool’s executable can resolve its service domain, establish TLS, and maintain a long-lived connection if it uses streaming responses. A short request that returns an HTTP status does not fully test WebSocket, server-sent events, or long-running HTTPS behavior.
- Check whether the tool documents HTTP proxy variables, SOCKS5 support, or an application-specific setting.
- Do not assume that a browser extension and its command-line companion use the same process environment.
- Inspect Clash Connections for the exact service domain instead of testing only a general website.
- Keep local model servers such as
127.0.0.1:11434inNO_PROXYwhen they should remain local. - If a request starts successfully and then stops, inspect idle timeouts, policy-group switching, and long-lived connection handling.
A repeatable troubleshooting sequence
- Confirm the core: make sure the active profile is selected, the core is running, and the chosen policy group has a usable node.
- Confirm the port: check the current mixed or HTTP port rather than relying on an old shell configuration.
- Test one direct command: run
curl -vwith an explicit proxy URL and compare the result with the Clash log. - Test TUN separately: clear temporary proxy variables, enable TUN, and repeat the same request.
- Check the rule: verify whether the destination matched
DIRECT, a proxy group,REJECT, or a fallback rule. - Check DNS and IPv6: compare the resolved address and determine whether the failing application prefers IPv6 or uses its own resolver.
- Test the application: only after the basic path works, configure Git, SSH, Docker, or the AI tool individually.
When a request never appears in Clash logs, changing nodes is unlikely to help. The application probably bypasses the configured path, the TUN route is inactive, or the request is being made from another network namespace. When the request appears but fails, inspect the matched rule, DNS result, handshake error, and policy-group status. This division prevents a local environment problem from being mistaken for a bad subscription or an unavailable node.
FAQ: developer proxy and TUN questions
Should I use TUN mode or terminal proxy variables?
Use terminal variables when the command supports them and you want explicit, per-session control. Use TUN mode for applications that ignore proxy settings or use multiple network libraries. Many developers use both, but they test them separately and keep NO_PROXY accurate.
Why does Git work over HTTPS but fail over SSH?
HTTPS Git remotes can usually use HTTP proxy variables or Git’s proxy configuration. SSH does not normally read those settings. Configure a SOCKS5 ProxyCommand, use TUN mode, or change the remote to an HTTPS URL if that fits the project’s authentication workflow.
Why does Docker still fail when the host browser works?
The Docker daemon or container may run in a VM or separate network namespace. Host loopback addresses are not automatically reachable from that environment. Configure the daemon separately, use the correct host gateway address, and test container traffic independently.
Can TUN mode replace all application proxy configuration?
Not always. VPN software conflicts, privileged network services, containers, custom DNS resolvers, excluded routes, and applications with their own network namespace can bypass TUN. Keep explicit proxy configuration available for tools that need predictable behavior, and verify each important workflow in the Clash connections view.