A Surge profile decides more than which websites use a proxy. It answers three connected questions: how a request is captured, where the available outbound routes come from, and which route each request ultimately uses.
Proxy data flow
This profile does not define proxies statically in [Proxy]. Instead, it imports them from a remote subscription and organizes them into regional policy groups:
Remote subscription
├─ Hong Kong proxies -> HK ─┐
├─ Taiwan proxies -> TW │
├─ Singapore proxies -> SG ├─ Proxy ─┐
├─ Japan proxies -> JP │ ├─ Missing
└─ US proxies -> US ─┘ DIRECT ─┘
Optional Tailscale policy -> Tailnet
Request -> Custom rules -> Service rule sets -> China rules -> GEOIP -> FINAL
└─ Proxy / Tailnet / DIRECT / MissingHK, TW, SG, JP, and US are regional policy groups. Proxy is their shared entry point, while Missing handles requests that none of the preceding rules match. The rule layer only needs to refer to Proxy, DIRECT, and Missing; it does not need to know the protocol or address of any individual proxy.
The subscription supplies proxies, policy groups organize outbound routes, and rules express routing intent. Replacing a subscription or its proxies therefore usually does not require rewriting the entire rule set.
[General]: capture, DNS, and testing
The general portion of the profile can be summarized as follows:
[General]
loglevel = notify
dns-server = system, 114.114.114.114, 223.5.5.5
skip-proxy = 127.0.0.1, 192.168.0.0/16, 10.0.0.0/8, 172.16.0.0/12, \
100.64.0.0/10, 17.0.0.0/8, localhost, *.local, *.crashlytics.com
exclude-simple-hostnames = true
ipv6 = true
internet-test-url = https://example.com/connectivity-check
proxy-test-url = https://example.com/connectivity-check
test-timeout = 3Choosing DNS servers
dns-server combines the system resolver with 114.114.114.114 and 223.5.5.5. This favors compatibility: local services and domains hosted in mainland China are more likely to receive answers appropriate for the current network.
It does not mean that all DNS traffic goes through the proxy, nor does it provide the privacy properties of encrypted DNS. On an untrusted network, or when consistent encrypted resolution is required, evaluate encrypted-dns-server for the actual network environment. Do not replace resolvers merely because a public DNS service is popular. Surge treats traditional DNS, encrypted DNS, and name resolution for proxied destinations differently, so recheck both resolution and routing for domestic and international domains after making a change.
skip-proxy is not DIRECT
The list includes loopback addresses, common private networks, carrier-grade NAT space, Apple's address range, localhost, and .local targets. Its primary purpose is to avoid compatibility problems caused by system proxy capture.
A common mistake is to treat skip-proxy as a DIRECT routing rule. According to Surge's option reference, it mainly controls how a request bypasses Surge Proxy Server and is handled through mechanisms such as VIF. Once a request enters Surge, [Rule] still determines its outbound policy. If a destination must connect directly, express that requirement explicitly:
[Rule]
IP-CIDR, 192.168.0.0/16, DIRECT, no-resolve
IP-CIDR, 10.0.0.0/8, DIRECT, no-resolveVerify IPv6 behavior
ipv6 = true enables the corresponding IPv6 functionality. The setting alone does not guarantee the intended result: the proxy, DNS resolver, rule sets, and current network must all support the expected IPv6 path. In addition to opening an IPv6 test page, inspect recent requests in Surge and confirm which rules and policies matched the IPv4 and IPv6 connections separately.
Test URLs only measure availability
internet-test-url is used to test Internet connectivity and DIRECT, while proxy-test-url is the default target for proxy policy tests. test-timeout = 3 limits the wait to three seconds. A good test endpoint returns a small response, remains stable over time, and can be reached both directly and through the proxy.
Latency reflects performance to the test endpoint, not performance for every service. A proxy with a fast test result can still fail for a particular website because of its exit region, service-side restrictions, or routing differences.
[Proxy]: proxy policy declarations and Tailscale support
[Proxy] declares individual proxy policies. It can contain static HTTP, SOCKS5, WireGuard, and other proxies, as well as Surge's native Tailscale policy. See the Surge Proxy Policy documentation for protocol-specific formats. [Proxy Group] then combines these policies into manually selectable or automatically tested groups.
The proxies in this example come from a remote subscription and are referenced by the regional groups through policy-path, so the lack of static proxies in [Proxy] is intentional. Add entries here only when declaring a standalone proxy or Tailscale policy, or when a policy needs to be included directly in a policy group.
Tailscale support
Surge iOS 5.20.0+ and Surge Mac 6.7.0+ can use a Tailscale tailnet as an outbound policy. See the Surge Tailscale Policy documentation for the complete set of fields and behaviors. This is not the same as installing the system Tailscale client and letting it capture all device traffic. Only traffic that selects the policy through a Surge rule or manual policy choice passes through Tailscale. It is suitable for reaching devices in the tailnet, MagicDNS names, authorized subnet routes, and, when explicitly configured, an exit node.
The minimum configuration has two parts: a policy declaration in [Proxy] and a matching [Tailscale <section-name>] section. The section-name value must exactly match the latter section's name:
[Proxy]
Tailnet = tailscale, section-name=tailnet
[Tailscale tailnet]
auth-key = tskey-auth-<redacted>
hostname = <your-hostname>auth-key is a sensitive credential. Do not commit it to a public repository or include it in an unsanitized shared profile. In the Tailscale admin console, give it a short lifetime, preauthorize it, assign appropriate tags, and grant only the minimum ACL permissions. Surge does not open an interactive login page, so use an auth key that can register the node directly. Enabling the Reusable option is recommended for easier configuration.
To use an exit node, specify it explicitly:
[Proxy]
Tailnet Exit = tailscale, section-name=tailnet-exit, test-timeout=8
[Tailscale tailnet-exit]
auth-key = tskey-auth-<redacted>
hostname = surge-exit-client
exit-node = office-exit.example.ts.netWithout an exit node, do not arbitrarily use a public website as test-url: a regular tailnet policy is intended to reach tailnet resources, and public Internet addresses generally do not pass through it. For testing, omit test-url to use Tailscale's connectivity probe, or specify an address that is actually reachable through the tailnet. Only traffic assigned to an exit node can use that node to reach the public Internet.
underlying-proxy applies only to Tailscale's DERP and peer transport connections; the control server address is still routed by Surge's regular rules. A rule for the control server must therefore not select the same Tailscale policy, or it creates a recursive dependency in which the policy waits for the control connection while the control connection waits for the policy. Omit this option by default. Configure it only when DERP connections specifically need another upstream proxy.
Route tailnet traffic through Tailscale
After declaring the policy, explicitly select it for the appropriate traffic in [Rule]. For example:
[Rule]
DOMAIN-SUFFIX, example-tailnet.ts.net, Tailnet
IP-CIDR, 100.64.0.0/10, Tailnet, no-resolveexample-tailnet.ts.net is only a placeholder. Use the actual MagicDNS suffix and tailnet addresses supplied by the control server. 100.64.0.0/10 is commonly used for Tailscale addresses, but do not broaden the match to that entire range without understanding the local networks and routes involved. When only a few services are needed, prefer specific domain names or IP addresses/CIDRs. Rules still run from top to bottom and stop at the first match.
Whether the Tailscale policy can reach a destination also depends on the control server's ACLs, node availability, subnet route approval, and MagicDNS settings. A Surge rule matching Tailnet only confirms that the correct outbound path was selected; it does not mean the tailnet has granted access or that the destination service is listening.
[Proxy Group]: policy groups
The relevant policy groups are configured as follows:
[Proxy Group]
HK = smart, policy-path=<subscription-url>, policy-regex-filter="香港", update-interval=-1, hidden=true
TW = smart, policy-path=<subscription-url>, policy-regex-filter="台湾", update-interval=-1, hidden=true
SG = smart, policy-path=<subscription-url>, policy-regex-filter="新加坡", update-interval=-1, hidden=true
JP = smart, policy-path=<subscription-url>, policy-regex-filter="日本", update-interval=-1, hidden=true
US = smart, policy-path=<subscription-url>, policy-regex-filter="美国", update-interval=-1, hidden=true
Proxy = select, HK, TW, SG, JP, US, DIRECT
Missing = select, Proxy, DIRECTThese lines contain six important ideas:
policy-pathimports proxy policies from an external file or URL instead of hard-coding proxies in the main profile.policy-regex-filtermatches proxy names and includes only proxies for the corresponding region.update-interval=-1disables scheduled updates of the remote policy. Proxies are still fetched on first load and subsequently refresh only when external resources are updated manually.smartconsiders connectivity, handshake latency, RTT, packet loss, and historical performance for individual websites when choosing a proxy within a regional group.hidden=truehides a regional group from the policy selection interface without disabling it.ProxyandMissingremainselectgroups: the former chooses a region, while the latter determines whether otherwise unmatched traffic usesProxyorDIRECT.
See Surge's Policy Including documentation for the behavior of external policies.
Why automatic subscription updates are disabled
In this setup, automatic updates are disabled because the proxy provider requires its subscription endpoint to be enabled manually for security reasons. The endpoint remains available for only five minutes, so scheduled refreshes cannot work reliably. If a provider supports unattended updates, set update-interval=86400 to refresh the subscription every 24 hours and receive new proxies promptly.
update-interval=-1 only stops Surge from downloading a new remote proxy list. It does not stop smart from evaluating the current proxies, nor does it stop a url-test group from retesting existing proxies according to interval=600. The remote resource can still be refreshed manually in Surge.
Automatic selection within a region
Automatic selection inside each regional group is provided by smart. It evaluates connectivity, handshake latency, RTT, packet loss, and historical performance for individual sites, but it does not measure proxy bandwidth. Smart groups require Surge iOS 5.11.0 or later with the corresponding subscription feature unlocked, or Surge Mac 5.7.0 or later. See the Surge Smart Group guide for details.
After a regional group chooses a proxy automatically, the region itself is still selected manually through Proxy.
If the device does not support smart, use url-test for the regional groups instead:
HK = url-test, policy-path=<subscription-url>, policy-regex-filter="香港", update-interval=-1, interval=600, tolerance=100, timeout=5, evaluate-before-use=true, hidden=trueApply the same parameters to the other regions. url-test selects the available proxy with the lowest test latency, while tolerance=100 prevents frequent changes when results differ by only a small amount. It measures access to the test URL and, unlike smart, does not build destination-specific knowledge. Parameter definitions are available in the Surge Automatic Testing Group documentation. Use fallback instead when availability and fixed priority matter more than speed.
Matching regions by proxy name
This design depends on the naming convention used by the subscription. The Chinese regular expressions above match the original provider's names: 香港, 台湾, 新加坡, 日本, and 美国 mean Hong Kong, Taiwan, Singapore, Japan, and the United States respectively. If the provider changes “香港” to HK, for example, the corresponding group can become empty. When a subscription refresh succeeds but a group has no proxies, inspect the actual proxy names and update policy-regex-filter instead of repeatedly reimporting the profile.
The Missing group
Missing contains Proxy and DIRECT, allowing otherwise unclassified traffic to be switched independently without changing explicit Proxy rules for Microsoft, OpenAI, GitHub, and other services.
That separation is why Missing is worth keeping. Proxy answers “which region should proxy-required traffic use?” while Missing answers “should unclassified traffic use a proxy at all?” Replacing it with FINAL, Proxy would mean that temporarily directing unknown traffic requires changing Proxy, which would also affect every service rule that explicitly uses it.
[Rule]: routing rules
Surge evaluates rules from top to bottom and stops after the first match. The official Traffic Routing documentation describes the same first-match-wins behavior. Put custom exceptions before large remote rule sets.
The profile reserves space for two kinds of custom rule:
# Must use a proxy
DOMAIN-SUFFIX, example.com, Proxy
# Must connect directly
DOMAIN-SUFFIX, example.cn, DIRECTThen route tailnet traffic:
DOMAIN-SUFFIX, example-tailnet.ts.net, TailnetIt then loads third-party rule sets:
| Rule set | Policy | Intent |
|---|---|---|
| Apple | DIRECT | Prefer direct connections for Apple traffic |
| Microsoft | Proxy | Route Microsoft traffic through the proxy |
| OpenAI | Proxy | Route OpenAI traffic through the proxy |
| GitHub | Proxy | Route GitHub traffic through the proxy |
Proxy | Route Google traffic through the proxy | |
| Telegram | Proxy | Route Telegram traffic through the proxy |
| Discord | Proxy | Route Discord traffic through the proxy |
| Proxy | Proxy | Route generally proxied domains and addresses through the proxy |
| China_All | DIRECT | Prefer direct connections for services in mainland China |
These lists come from the Surge rules in blackmatrix7/ios_rule_script. RULE-SET references a remote file and assigns one policy to the entire file; entries inside that rule set do not independently choose between Proxy and DIRECT.
There are two maintenance tradeoffs:
- Remote lists can evolve while the main profile stays concise, but list changes can also change routing behavior immediately.
- Service-specific rules appear before
China_All, so a destination present in more than one list uses the earlier service policy.
Third-party rules are not permanent statements of fact. If a service suddenly changes routes after an update, inspect the matched rule in Surge's recent requests and review changes in the rule repository instead of diagnosing solely from whether the website opens.
GEOIP and the final fallback
The rule section ends with:
GEOIP, CN, DIRECT
FINAL, MissingGEOIP, CN, DIRECT connects directly when the destination IP is classified as mainland China. It is an IP-based rule and may trigger DNS resolution when the request still contains a hostname. Surge's IP-based Rule documentation explains the relationship between GEOIP, DNS resolution, and no-resolve.
FINAL, Missing is the required fallback: every request that did not match an earlier rule is delegated to Missing. Compared with FINAL, Proxy, this adds a manual switch that is useful when investigating an unfamiliar service.
Review LAN listener settings carefully
The original profile also includes these settings:
allow-wifi-access = true
http-listen = 0.0.0.0:8234
socks5-listen = 0.0.0.0:8235
wifi-access-http-port = 6152
wifi-access-socks5-port = 6153They allow other devices to use the HTTP or SOCKS5 proxy services exposed by Surge. 0.0.0.0 listens on every network interface, not only the local loopback interface.
If other devices on the LAN genuinely need the proxy, restrict exposure with the system firewall and router, and configure authentication where supported. Surge iOS provides wifi-access-http-auth. Even though current versions restrict these services to the LAN by default, never forward the ports to the public Internet or expose them without authentication on untrusted hotel or airport networks.
If proxy sharing is unnecessary, disable allow-wifi-access and remove the extra listeners or bind them only to 127.0.0.1. A profile can be shared between devices, but macOS listener options and iOS Wi-Fi access options have different scopes. Keeping a minimal profile for each platform is safer.
Verifying the imported profile
Successful import is not sufficient verification. A reliable check should include at least the following:
- Run Surge's profile check and confirm that there are no syntax errors, duplicate names, or external resource failures.
- In policy diagnostics, confirm that all five regional groups imported proxies and can complete a test. Because
hidden=trueremoves them from the regular selection menu, temporarily removehiddenwhile troubleshooting if necessary. - Select the intended policies for both
ProxyandMissinginstead of relying on selections retained from an older profile. - Visit one domestic website and one service that should use the proxy, then inspect recent requests to confirm the matched rule, policy group, and final proxy.
- Test IPv4 and IPv6 separately. If LAN proxy access is enabled, verify its scope and authentication from another device.
- Refresh external policies and remote rules once manually to verify that the subscription URL, GitHub resources, and current DNS setup are reachable.
Common failures can usually be narrowed down in this order:
- A regional group is empty: inspect proxy names, then adjust
policy-regex-filter. - A domestic service uses the proxy: check whether an earlier service-specific or general
Proxyrule matched first. - A service remains unavailable through the proxy: inspect the exit region, proxy availability, DNS, and service-side restrictions. Matching
Proxyonly confirms the routing decision. - A LAN device cannot connect: check the listen address, port, system firewall, subnet restriction, and authentication.
- LAN domains or simple hostnames behave incorrectly: inspect
skip-proxy,exclude-simple-hostnames, and explicit direct rules instead of changing only DNS.
Profile template
[General]
loglevel = notify
dns-server = system, 114.114.114.114, 223.5.5.5
skip-proxy = 127.0.0.1, 192.168.0.0/16, 10.0.0.0/8, 172.16.0.0/12, 100.64.0.0/10, 17.0.0.0/8, localhost, *.local, *.crashlytics.com
allow-wifi-access = true
enhanced-mode-by-rule = false
exclude-simple-hostnames = true
show-error-page-for-reject = true
ipv6 = true
replica = false
http-listen = 0.0.0.0:8234
socks5-listen = 0.0.0.0:8235
wifi-access-http-port = 6152
wifi-access-socks5-port = 6153
internet-test-url = http://baidu.com
proxy-test-url = https://www.gstatic.com/generate_204
test-timeout = 3
[Proxy]
Tailnet = tailscale, section-name=tailnet
[Tailscale tailnet]
auth-key = tskey-auth-<redacted>
hostname = <your-hostname>
[Proxy Group]
HK = smart, policy-path=<subscription-url>, policy-regex-filter="香港", update-interval=-1, hidden=true
TW = smart, policy-path=<subscription-url>, policy-regex-filter="台湾", update-interval=-1, hidden=true
SG = smart, policy-path=<subscription-url>, policy-regex-filter="新加坡", update-interval=-1, hidden=true
JP = smart, policy-path=<subscription-url>, policy-regex-filter="日本", update-interval=-1, hidden=true
US = smart, policy-path=<subscription-url>, policy-regex-filter="美国", update-interval=-1, hidden=true
Proxy = select, HK, TW, SG, JP, US, DIRECT
Missing = select, Proxy, DIRECT
[Rule]
DOMAIN-SUFFIX, example.com, Proxy
DOMAIN-SUFFIX, example.cn, DIRECT
DOMAIN-SUFFIX, example-tailnet.ts.net, Tailnet
RULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/Apple/Apple.list, DIRECT
RULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/Microsoft/Microsoft.list, Proxy
RULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/OpenAI/OpenAI.list, Proxy
RULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/GitHub/GitHub.list, Proxy
RULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/Google/Google.list, Proxy
RULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/Telegram/Telegram.list, Proxy
RULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/Discord/Discord.list, Proxy
RULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/Proxy/Proxy.list, Proxy
RULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/rule/Surge/China/China_All.list, DIRECT
GEOIP, CN, DIRECT
FINAL, Missing