The classic remote-work situation: internal company systems have to go over the VPN, local sites should go direct, and overseas services need a proxy. All three at once, none stepping on the others.
Here is a configuration that does it.
First, three classes of traffic
The hard part: intranet domains typically resolve to private IPs, but the names themselves look no different from public ones. Judging by GEOIP alone gets it wrong.
The full configuration
Step 1: define the policy groups
proxy-groups:
- name: "🚀 Overseas"
type: select
proxies: ["♻️ Auto", "🇭🇰 Hong Kong", "🇯🇵 Japan", "🇺🇸 US"]
- name: "♻️ Auto"
type: url-test
include-all: true
exclude-filter: "(?i)remaining|expiry|website"
url: "http://www.gstatic.com/generate_204"
interval: 300
tolerance: 50
- name: "🏢 Intranet"
type: select
proxies: [DIRECT] # intranet exits through the local interface (VPN already up)
- name: "🇨🇳 Local direct"
type: select
proxies: [DIRECT, "🚀 Overseas"] # switchable when needed
- name: "🐟 Fallthrough"
type: select
proxies: ["🚀 Overseas", DIRECT]Making intranet and local into policy groups rather than writing DIRECT inline means you can flip them in the interface while diagnosing, with no config edit.
Step 2: intranet rules (first in the list)
rules:
# ===== 1. loopback and private ranges =====
- IP-CIDR,127.0.0.0/8,DIRECT,no-resolve
- IP-CIDR,192.168.0.0/16,🏢 Intranet,no-resolve
- IP-CIDR,10.0.0.0/8,🏢 Intranet,no-resolve
- IP-CIDR,172.16.0.0/12,🏢 Intranet,no-resolve
- IP-CIDR,100.64.0.0/10,DIRECT,no-resolve
- IP-CIDR6,fc00::/7,DIRECT,no-resolve
# ===== 2. corporate intranet domains =====
- DOMAIN-SUFFIX,mycompany.com,🏢 Intranet
- DOMAIN-SUFFIX,corp.internal,🏢 Intranet
- DOMAIN-SUFFIX,intra,🏢 Intranet
- DOMAIN-KEYWORD,gitlab-internal,🏢 Intranet
- DOMAIN-SUFFIX,local,DIRECT
- DOMAIN-SUFFIX,lan,DIRECTStep 3: overseas rules
# ===== 3. explicitly proxied =====
- DOMAIN-SUFFIX,github.com,🚀 Overseas
- DOMAIN-SUFFIX,githubusercontent.com,🚀 Overseas
- DOMAIN-SUFFIX,docker.io,🚀 Overseas
- DOMAIN-SUFFIX,npmjs.org,🚀 Overseas
- DOMAIN-SUFFIX,pypi.org,🚀 Overseas
- DOMAIN-SUFFIX,openai.com,🚀 Overseas
- RULE-SET,proxy-list,🚀 OverseasStep 4: local and catch-all
# ===== 4. local direct =====
- RULE-SET,direct-list,🇨🇳 Local direct
- RULE-SET,cn-ip,🇨🇳 Local direct,no-resolve
- GEOIP,CN,🇨🇳 Local direct
# ===== 5. catch-all =====
- MATCH,🐟 FallthroughDNS has to be routed too
This is the piece most often missed. Intranet names must be resolved by the company's DNS, otherwise they either fail to resolve or resolve to the wrong thing.
dns:
enable: true
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
fake-ip-filter:
- "*.lan"
- "*.local"
- "+.mycompany.com" # intranet names skip fake-ip
- "+.corp.internal"
- "+.pool.ntp.org"
default-nameserver: [223.5.5.5, 119.29.29.29]
nameserver:
- 223.5.5.5
- 119.29.29.29
# the key part: send specific names to specific resolvers
nameserver-policy:
"+.mycompany.com": "10.10.0.53" # the corporate DNS server
"+.corp.internal": "10.10.0.53"
"geosite:cn": [223.5.5.5, 119.29.29.29]
"geosite:geolocation-!cn": [https://1.1.1.1/dns-query]
fallback:
- https://1.1.1.1/dns-query
- tls://8.8.4.4:853
fallback-filter:
geoip: true
geoip-code: CNnameserver-policy is the heart of this arrangement. Without it, intranet names are sent to a public resolver, and the answer is either NXDOMAIN or a carrier's landing page.
Common conflicts and what to do
Conflict 1: the corporate VPN and TUN fight over routes
Enterprise VPN clients (Cisco AnyConnect, FortiClient, SSL VPN products) generally rewrite the routing table. Clash Verge's TUN mode rewrites it too, and they clash easily.
The exclude-interface syntax:
tun:
enable: true
stack: mixed
auto-route: true
auto-detect-interface: true
exclude-interface: ["ppp0", "Cisco AnyConnect"]Find the adapter name with ipconfig on Windows, ifconfig or ip link on Linux and macOS.
Conflict 2: your employer runs endpoint management software
EDR products may treat a virtual adapter as anomalous. In that case:
- Do not enable TUN; use the system proxy only
- Or simply handle personal matters on a personal device and keep the work machine clean
Conflict 3: an internal service went through the proxy
Symptom: the internal system times out, and the connections page shows an overseas node.
Investigation:
- Read the "Rule" column on the connections page to see what matched
- If it matched
MATCHorGEOIP, your intranet rules did not fire - Check the spelling of the intranet domain rules; check whether some broader rule above intercepted them
- Use
prepend-rulesto force the intranet rules to the very top
Conflict 4: a local site went through the proxy and tripped fraud detection
Symptom: your bank reports a login from an unusual location, or a payment platform demands a second factor.
Cause: those sites are not in direct-list, and their resolved IPs are not inside GEOIP CN (they may sit on an overseas CDN).
Fix: add rules by hand
prepend-rules:
- DOMAIN-SUFFIX,icbc.com.cn,🇨🇳 Local direct
- DOMAIN-SUFFIX,alipay.com,🇨🇳 Local direct
- DOMAIN-SUFFIX,unionpay.com,🇨🇳 Local directRouting per device (LAN scenarios)
If Clash runs on a soft router or is shared with other devices, you can distinguish by source IP:
prepend-rules:
# work laptop: only overseas services get proxied
- AND,((SRC-IP-CIDR,192.168.1.100/32),(GEOIP,CN)),DIRECT
# TV box: everything proxied
- SRC-IP-CIDR,192.168.1.200/32,🚀 Overseas
# IoT devices: everything direct
- SRC-IP-CIDR,192.168.1.0/24,DIRECTMatching is still top to bottom, so specific devices go above the subnet rule.
Verifying that it works
In short
The keys to making all three coexist:
- The intranet needs all three: domain rules, IP-range rules and nameserver-policy
- Rule order: intranet → explicit overseas entries → local lists → GEOIP → MATCH
- When the VPN and TUN conflict, prefer the system proxy alone
- Make each class a policy group so you can flip it in the interface while diagnosing
Related: DNS configuration explained and the rule type reference.
Related docs
Syntax, matching behaviour and relative cost for every rule type, what no-resolve actually does, why rule order decides everything, and how to find which rule a connection matched.
Replacing hundreds of hand-written rules with external lists. The difference between the domain, ipcidr and classical behaviors, text versus yaml, how to set the update interval, and what to check when a rule set does nothing.
The complete picture for per-process routing: enabling find-process-mode, finding the process name, PROCESS-NAME versus PROCESS-PATH, the performance cost, and why a rule you wrote does nothing.