Mac Troubleshooting: Why 'Auto Proxy Discovery' Causes Tailscale Connection Timeouts
A deep dive into why Tailscale in macOS Shadowrocket fails with fetch control server key timeout, tracing down to NSURLSession WPAD resolution hangs and terminal fix.
1. The Incident and BLUF (Bottom Line Up Front)
Today, while setting up the built-in Tailscale module in Shadowrocket on macOS, I encountered a baffling issue: the exact same Tailscale credentials and node configurations connected instantly on an iPhone, but stayed stuck on "Disconnected" on a Mac.
Looking into Shadowrocket's VPN diagnostic logs, every attempt to start the built-in Tailscale module threw the exact same error after 5 seconds:
failed to fetch control server key: 请求超时。
control server key fetch failed
Bottom line up front: The culprit was neither the proxy nodes nor the Tailscale servers, but the "Auto Proxy Discovery" (WPAD) toggle enabled by default in macOS Wi-Fi settings.
In home Wi-Fi or mobile hotspot environments, this setting forces macOS's underlying networking library (NSURLSession) to attempt to locate a non-existent PAC proxy script across the local network before initiating any handshake. This resolution step blocks for 5 seconds until it fails, dragging the Tailscale client's public key retrieval directly into a timeout.
Running a single terminal command to turn it off immediately restored sub-second connections to Tailscale:
networksetup -setproxyautodiscovery Wi-Fi off
2. Core Insights: Why Initial Hypotheses Failed
During initial troubleshooting, I followed conventional wisdom and explored two dead ends:
- Suspecting an expired Tailscale Auth Key: Checking the key status in the Tailscale admin console showed that while old keys must remain valid, the client hadn't even retrieved the server's public key yet—it had not reached server-side authentication at all.
- Suspecting DNS virtual IP poisoning: Shadowrocket typically resolves domain names to the reserved
198.18.x.xrange to intercept and route traffic. I addedalways-real-ipforcontrolplane.tailscale.comin the configuration, and DNS indeed returned the public IP, but startup still consistently timed out after 5 seconds. - Deceptive CLI curl success: Running
curl https://controlplane.tailscale.com/keydirectly in the terminal responded almost instantaneously, and standard web browsers also loaded it without any hitch.
Why did curl succeed while the embedded Tailscale in Shadowrocket timed out?
The crucial difference lies in the execution context: standard curl runs in a conventional user-space process network stack, whereas Shadowrocket on macOS runs as a MacPacketTunnel (Network Extension) system extension. Inside this extension, initializing Tailscale leverages the system's NSURLSession.
Inspecting detailed records from the macOS unified log finally caught the culprit:
MacPacketTunnel: proxy:start_resolve
MacPacketTunnel: unresolved proxies, waiting for resolution
MacPacketTunnel: nw_proxy_resolver_create_parsed_array [C11.1.1 proxy pac] Evaluation error: NSURLErrorDomain: -1003
Before the request could even touch a low-level TCP handshake, it was intercepted by macOS to perform WPAD auto proxy discovery. In typical consumer broadband environments, no WPAD server exists on the local network. The system simply hangs for 5 seconds waiting for a response before giving up with a -1003 error. Tailscale's public key retrieval timeout budget happens to be exactly 5 seconds, causing it to fail every time.
3. Step-by-Step Reproduction and Fix
If you encounter this mysterious 5-second timeout, follow these deterministic steps to inspect and resolve it.
Step 1: Check Wi-Fi Auto Proxy Discovery Status
Open Terminal and run:
networksetup -getproxyautodiscovery Wi-Fi
If the output is:
Auto Proxy Discovery: On
auto proxy discovery is enabled on that network interface.
Step 2: Disable Auto Proxy Discovery via Terminal
Without restarting your Mac, run:
networksetup -setproxyautodiscovery Wi-Fi off
Verify the status again:
networksetup -getproxyautodiscovery Wi-Fi
# Expected output: Auto Proxy Discovery: Off
Step 3: Reload Module and Verify
Return to Shadowrocket and toggle the Tailscale module off and on. In the diagnostic log, what previously hung for 5 seconds now succeeds instantaneously:
tailscale_client_new: initialised
tailscale: connected to network
The status immediately changes to "Connected", and the handshake drops from a 5-second failure to passing in milliseconds.
4. Troubleshooting Checklist and Pitfalls
| Symptom / Misconception | Root Cause | Recommended Action |
|---|---|---|
Terminal curl works, but in-app requests time out | curl does not necessarily trigger asynchronous system WPAD lookup, whereas NSURLSession in Extensions/Apps strictly adheres to system proxy discovery | Do not rely on curl alone; troubleshoot Network Extensions using the macOS unified log |
| Suspecting local proxy app blocking traffic | WPAD requests a PAC script from the LAN and does not conflict with local HTTP/SOCKS proxies | Disabling WPAD only halts LAN multicast/probes; existing routing rules remain untouched |
Confusing invalid key errors mixed with timeouts | Overlapping issues with expired Auth Keys and WPAD timeouts | Resolve the 5-second network-level timeout first, then verify an active Reusable Auth Key in Tailscale console |
5. Summary and Applicability Boundaries
- Best Fit: Personal MacBooks, home networks, mobile hotspots, and developer environments running tools like Shadowrocket, Surge, or Clash. In these scenarios, the system default "Auto Proxy Discovery" provides no benefit and often acts as a silent killer blocking specific network components (particularly Network Extensions). Keeping it
Offis strongly recommended. - When Not to Disable: Certain corporate intranets or university campuses where network administrators explicitly push proxy configurations via DHCP Option 252. Disabling WPAD there might prevent access to specific internal resources. Even in those environments, having the administrator provide a static PAC URL (Automatic Proxy Configuration) manually is generally preferred over open network discovery broadcasts.
