Why developer traffic needs more than a browser proxy
A browser working through Clash does not prove that the rest of a development environment is using the same route. Chrome, Edge, and many desktop applications read the operating system proxy setting, while Git, npm, Docker, language package managers, IDE extensions, and AI coding tools may use their own networking libraries. Some read environment variables, some require an explicit proxy option, and some ignore both unless traffic is captured at the network layer.
This difference becomes visible in several familiar situations: GitHub opens in a browser but git clone times out, npm reports a registry connection error, Docker cannot pull an image, or an IDE extension cannot reach its model provider. The local Clash core may be healthy in all of these cases. The missing piece is often that the terminal process is connecting directly, resolving DNS through a different path, or using a stale proxy address.
For a developer workstation, there are three practical ways to connect applications to Clash:
- System proxy: Simple and useful for browsers and applications that follow the operating system setting.
- Command-line proxy variables: Precise for a terminal session and usually the easiest approach for Git, curl, npm, and similar tools.
- TUN mode: A virtual network interface that can capture traffic from applications which do not understand HTTP or SOCKS proxy settings.
TUN mode is not automatically better for every task. It adds a network layer, normally requires elevated permission, and can affect local services, container networking, DNS behavior, and corporate VPN software. A reliable setup uses the least invasive method that covers the application. Use explicit proxy variables when a tool supports them; use TUN when the application ignores those settings or when you need broader coverage.
Prepare a safe TUN configuration
TUN mode creates a virtual network interface and lets the Mihomo core process traffic that would otherwise bypass the system proxy. In Clash Nyanpasu, the exact menu names can vary by release, but the relevant controls are normally under “Settings” → “TUN Mode” or the core settings page. Enable the TUN feature, allow the operating system permission request, and confirm that the active profile supports the required fields.
A basic Mihomo configuration may look like this:
mixed-port: 7890
mode: rule
allow-lan: false
dns:
enable: true
ipv6: false
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
nameserver:
- https://1.1.1.1/dns-query
- https://dns.google/dns-query
tun:
enable: true
stack: mixed
dns-hijack:
- any:53
auto-route: true
auto-detect-interface: true
strict-route: true
rules:
- DOMAIN-SUFFIX,github.com,Developer
- DOMAIN-SUFFIX,githubusercontent.com,Developer
- DOMAIN-SUFFIX,npmjs.org,Developer
- DOMAIN-SUFFIX,npmjs.com,Developer
- DOMAIN-SUFFIX,docker.io,Developer
- DOMAIN-SUFFIX,openai.com,Developer
- DOMAIN-SUFFIX,anthropic.com,Developer
- MATCH,DIRECT
proxy-groups:
- name: Developer
type: select
proxies:
- Auto Select
- DIRECT
- name: Auto Select
type: url-test
url: http://www.gstatic.com/generate_204
interval: 300
tolerance: 80
proxies:
- "Node 01"
- "Node 02"
The node names in this example are placeholders and must exactly match names defined elsewhere in the profile. If the subscription provider generates the proxy list and groups automatically, do not paste this entire example over the subscription configuration. Instead, add compatible rules through the client’s profile override or edit a local copy. A YAML indentation error can prevent the core from starting, and a rule referring to a nonexistent group may send traffic to an unexpected destination.
Choose routing and DNS deliberately
auto-route: true allows the TUN interface to install routes for captured traffic. auto-detect-interface: true helps Mihomo select the active physical interface when a computer has Wi-Fi, Ethernet, and a VPN adapter. strict-route: true can reduce accidental bypasses, but it may also interfere with local networks, virtual machines, or another VPN. If the workstation loses access to printers, internal Git services, or a company VPN after enabling TUN, temporarily test with strict routing disabled and review the exclusions rather than assuming the node is broken.
DNS deserves separate attention. In fake-IP mode, Clash returns synthetic addresses and maps them back to domain names inside the core. This can improve rule matching, but some development tools, local service discovery systems, and applications that expect real DNS answers may behave differently. If a local hostname such as registry.local, host.docker.internal, or an internal company domain stops working, add an appropriate fake-IP filter or use a dedicated nameserver policy. Do not route every internal domain to a public DNS service.
- Keep
allow-lan: falseunless another device genuinely needs to use this computer as a gateway. - Start with
mode: ruleso domestic, local, and private traffic can remain direct. - Use a stable test URL for automatic groups, and avoid changing nodes while diagnosing a command failure.
- Check whether the client has a separate “Service Mode” or administrator permission requirement for TUN.
- Disable other transparent proxy tools while testing to avoid route loops and competing DNS interception.
Configure terminal proxy variables for predictable commands
Even with TUN enabled, explicit proxy variables are valuable. They make the intended route visible in shell scripts and provide a quick comparison between application-level proxying and packet capture. Clash’s mixed port commonly accepts both HTTP proxy requests and SOCKS5 connections. For tools with inconsistent SOCKS support, use the HTTP form first.
On macOS, Linux, and a POSIX-compatible shell, set variables for the current terminal session:
export HTTP_PROXY=http://127.0.0.1:7890
export HTTPS_PROXY=http://127.0.0.1:7890
export ALL_PROXY=socks5://127.0.0.1:7890
export NO_PROXY=127.0.0.1,localhost,::1,.local
On Windows PowerShell, the equivalent session variables are:
$env:HTTP_PROXY = "http://127.0.0.1:7890"
$env:HTTPS_PROXY = "http://127.0.0.1:7890"
$env:ALL_PROXY = "socks5://127.0.0.1:7890"
$env:NO_PROXY = "127.0.0.1,localhost,::1,.local"
Environment variable names are not handled identically by every program. Many Unix tools accept lowercase and uppercase forms, while some Windows applications inspect only one spelling. If a program ignores the variables, test its own proxy option or rely on TUN. Keep NO_PROXY narrow: adding an entire public domain by mistake can send the very traffic you wanted to proxy directly.
Verify the local port before blaming the remote node:
curl -I --proxy http://127.0.0.1:7890 https://github.com
curl -I https://github.com
curl -I --noproxy "*" https://github.com
The first command explicitly uses Clash, the second tests the current environment, and the third deliberately bypasses proxy variables. Compare the results with the Clash connection log and rule hit information. A successful HTTP status is not the only useful result; a timeout, TLS error, DNS error, or connection refusal points to a different layer.
| Symptom | Likely layer | First check |
|---|---|---|
| Connection refused on 127.0.0.1:7890 | Local core or port | Clash status and the current mixed port |
| Browser works, Git fails | Application proxy settings | Git proxy configuration and shell variables |
| Domain resolves but HTTPS times out | Route, node, or rule | Clash logs, selected group, and target rule |
| Only local services fail after TUN | Route or DNS interception | Private-network rules, DNS filters, and VPN conflicts |
Route Git, npm, and package managers without breaking local work
Git has its own configuration and does not consistently inherit the browser’s system proxy. To configure a global HTTP proxy through Clash, run:
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|version)'
If the proxy is needed only for one repository, omit --global. This is useful when an organization’s internal Git server must remain direct while GitHub uses the proxy. A temporary one-command setting is also possible:
git -c http.proxy=http://127.0.0.1:7890 \
-c https.proxy=http://127.0.0.1:7890 clone https://github.com/example/project.git
Do not put a proxy username or password directly into a shared Git configuration file. If authentication is required, protect the credential through the operating system’s credential manager and remember that the local Clash port itself normally does not require authentication. For SSH remotes such as [email protected]:example/project.git, Git’s HTTP proxy setting does not automatically proxy the SSH connection. Use an HTTPS remote, configure a supported SOCKS-based SSH method, or route the SSH process through TUN.
npm can use the same mixed port:
npm config set proxy http://127.0.0.1:7890
npm config set https-proxy http://127.0.0.1:7890
npm config get proxy
npm config get https-proxy
Prefer project-specific or session-specific settings when you regularly switch between public and private registries. A global proxy may cause an internal registry to fail, while a project-level .npmrc can define the intended registry and proxy behavior for that project. Also check whether npm, pnpm, or yarn is reading a different configuration file. Clearing an obsolete setting is better than stacking multiple proxy URLs:
npm config delete proxy
npm config delete https-proxy
For Python, Rust, Go, and JavaScript tooling, the same principle applies but the variable names differ. Common examples include PIP_INDEX_URL, CARGO_HTTP_PROXY, and GOPROXY. Do not assume that setting HTTP_PROXY changes a package registry URL or authentication policy. First identify whether the tool is failing during DNS lookup, TLS negotiation, registry authentication, or archive download.
Handle Docker, containers, and AI coding tools separately
Docker has more than one network path. The Docker client may need a proxy to contact a registry, while containers may need separate proxy variables for commands executed inside them. On Docker Desktop, the daemon and the Linux virtual machine are managed separately from the host shell. Setting HTTP_PROXY in PowerShell therefore does not guarantee that the daemon can pull an image.
For a command-line test, pass proxy variables explicitly to a container:
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 \
alpine:latest wget -qO- https://example.com
The hostname host.docker.internal is commonly available in Docker Desktop, but its behavior differs on native Linux installations and custom bridge networks. A container cannot use its own 127.0.0.1 to reach the host’s Clash process. On Linux, you may need a host gateway mapping, a reachable host address, or TUN rules that cover the container network. Exposing Clash with allow-lan: true should be treated as a deliberate security change: bind only to a trusted interface, restrict firewall access, and never expose an unauthenticated proxy to the public Internet.
AI-assisted coding tools introduce another layer of uncertainty. An IDE extension may run inside the editor process, a helper process, a remote development host, or a container. The extension may follow the IDE’s proxy setting, use system settings, read environment variables, or open connections through a runtime that ignores all of them. Configure the proxy in the tool’s documented network settings when available, then verify the actual process path with Clash logs.
- Local IDE extension: Check the IDE’s HTTP proxy setting and restart the extension host after changing it.
- CLI assistant: Test
HTTP_PROXY,HTTPS_PROXY, andNO_PROXYin the same shell that launches the command. - Remote development: Configure the proxy on the remote host, not only on the laptop running the IDE window.
- Containerized assistant: Pass proxy variables into the container and confirm that the container can reach the host port.
- Model API failure: Check the provider domain, TLS handshake, request timeout, and response status separately; a successful browser login does not validate API access.
Use Clash’s connection panel or logs while starting one operation at a time. A request to an AI provider should appear with the expected domain and policy group. If no connection appears, the process may be using a separate network namespace, a hard-coded endpoint, or a proxy setting that points to another local port.
Test the complete developer workflow and recover safely
After enabling TUN or changing proxy variables, test real operations in a controlled order. Start with a lightweight request, then test authentication, package metadata, an archive download, and finally a container or AI request. This separates basic reachability from larger transfers and application-specific behavior.
- Confirm that Clash is running, the intended profile is active, and the selected proxy group has a healthy node.
- Run
curlthrough the mixed port and inspect the request in the Clash connection log. - Check the egress address with a trusted IP-check endpoint if the target service is region-sensitive.
- Run
git ls-remoteagainst a test repository before attempting a large clone. - Query the configured npm registry with
npm pingand verify that the request matches the intended rule. - Pull a small, known image and test a container request separately from the Docker daemon.
- Launch the IDE or AI tool only after the terminal path is known to work, then watch for its actual domains in the log.
When a test fails, change one variable at a time. Pin one node instead of using a rapidly switching group, keep Rule mode enabled, and avoid changing DNS and TUN stack simultaneously. Compare direct, explicit-proxy, and TUN results. For example, if explicit curl --proxy works but a package manager fails, the node is probably usable and the package manager configuration needs attention. If both explicit proxy and TUN fail, inspect the rule, remote route, TLS error, and node health.
Common recovery actions are straightforward:
- Disable TUN temporarily if a corporate VPN, virtual machine, or local development cluster loses connectivity.
- Remove stale Git or npm proxy settings when switching to an internal network.
- Restart the terminal, IDE, or container after changing environment variables; already-running processes keep their old environment.
- Check for port conflicts if the client silently disables TUN or the core stops listening.
- Review
NO_PROXYwhen localhost, private registries, or internal APIs behave differently from public services. - Restore the previous profile before editing a subscription-generated configuration if a YAML change prevents startup.
The most maintainable developer setup is usually layered: use Clash Rule mode with a dedicated developer proxy group, enable TUN only when applications bypass normal proxy settings, and retain explicit command-line variables for reproducible scripts. Keep private domains direct where necessary, verify Docker and remote-development environments independently, and use Clash logs to confirm the real route instead of judging success from a browser alone.