On this page · name · the problem · synopsis · description · states · browser tunnels · what it cannot fix · security · diagnostics · see also
Name
tailroute—automatic Tailscale + VPN coexistence daemon for macOS
The problem
Most commercial VPNs on macOS don't support split tunneling. The moment the
VPN connects, it takes the default route and the DNS path with it:
MagicDNS becomes unreachable, *.ts.net names stop resolving, and
some VPNs also drop traffic to Tailscale's CGNAT range entirely. You are left
choosing between internet and your peers—or hand-editing
--accept-dns every time.
tailroute refuses the choice. It watches the routing table and makes the same call a careful admin would make, every time:
fig. 1—the decision state machine; route-monitor events replayed below
…
Synopsis
Menu bar app (same engine, native UI, free during early access):
brew install --cask shrwnsan/tap/tailroute
No Homebrew? Download the DMG ↗ · sha256 published on the release · unsigned—macOS will ask you to approve the first launch
Description
tailroute is a launchd daemon that watches the macOS routing table. When a
commercial VPN connects, it disables Tailscale's MagicDNS so internet traffic
keeps flowing through the VPN, and starts a SOCKS5 proxy on
127.0.0.1:1055 so Tailscale peers stay reachable through the mesh.
When the VPN disconnects, it re-enables MagicDNS and stops the proxy.
Decisions are event-driven (route monitor) with a 60-second re-assert.
It manages exactly one thing and touches nothing else. If state is ambiguous (e.g. two VPNs active), it logs a warning and changes nothing.
States
| Condition | MagicDNS | SOCKS5 proxy | Else |
|---|---|---|---|
| Tailscale + VPN active | off | up (127.0.0.1:1055) | — |
| Tailscale only | on | stopped | — |
| No Tailscale | — | — | keeps watching |
Browser tunnels
Register a peer's Tailscale Serve dashboard once and open it in any browser
with a valid .ts.net certificate—no extensions, no warnings.
Tunnels are launchd-managed and adapt automatically: SOCKS5 path when the
VPN is up, direct otherwise.
→ https://mypeer.yourtailnet.ts.net:8443
What it cannot fix
VPN Network Extensions may still block traffic to Tailscale's CGNAT range
(100.64/10) at the packet level. Tested and blocked:
Mullvad (WireGuard), NordVPN (NordLynx, OpenVPN, NordWhisper).
The SOCKS5 proxy and tunnels are the supported paths when that happens.
While the VPN is active, MagicDNS names do not resolve—use
100.x addresses or a tunnel.
Report your VPN's behavior: open a vpn-compat issue
Security
- Runs as a root launchd daemon; install writes a SHA-256 manifest
(
/var/db/tailroute/installed.checksums) verified before any library loads. - No telemetry, no external network calls, no account, no traffic logging.
- Interface names validated against
utun[0-9]+; absolute paths only. - 417 tests as of v0.8.17. Source: github.com/shrwnsan/tailroute-cli
Diagnostics
daemon: running · tailscale: utun4 · vpn: utun3 · magicdns: disabled (vpn_active) · last check: 12s ago
Preview without changes: tailroute --dry-run.
Logs: tail -f /var/log/tailroute.log.
See also
- CHANGELOG.md—release history
- architecture.md—system design
- Releases · Issues · Full manual on GitHub