Open core · Apache-2.0 CLI macOS 12+ fail-safe by design

Keep working.
VPN up, tailnet up.

tailroute watches your Mac’s routing table and toggles Tailscale’s MagicDNS when your VPN connects—and back when it drops—internet through the VPN, peers through the mesh. A root daemon that is fail-safe, self-verifying, and entirely local.

$brew install --cask shrwnsan/tap/tailroute includes the CLI

Requires Tailscale · No account · No telemetry · Every install sha256-verified · Uninstall restores everything

tagged releases · public since mar ’26
31
shell tests · 348 → 417 in five weeks
417
telemetry · external calls · accounts
0
forever · apache-2.0 core
$0

What it does

A daemon that makes the call, so you don’t.

Every routing-table change lands in one of three states, and the response is always the same. You do nothing.

demo · the decision loop, replayed

tailroute daemon—demo loop
MAGICDNSoff PROXYup STATECOEXIST

the matrix

Three states, zero judgment calls

VPN + Tailscaledns off · proxy up
Tailscale onlydns on · proxy down
No Tailscalewatching…

Ambiguous? Two VPNs at once—it logs a warning and does nothing. Fail-safe first.

When the VPN connects—on hotel or café Wi-Fi, this is your Tuesday. The usual escape is a $100 travel router.

Every peer times out.

01SOCKS5 mesh proxy

A tsnet-based proxy on 127.0.0.1:1055 routes peer traffic through the mesh even when the VPN blocks the CGNAT range. Starts and stops with the VPN—never configured by you. Helpers included: sshproxy, curlproxy, generated SSH config.

When you need a peer’s dashboard

Cert warnings, extensions, luck.

02Browser tunnels

One command registers a launchd-managed tunnel and maps a managed /etc/hosts entry— a valid, real .ts.net certificate in Safari, Chrome, or Firefox. Adaptive path: SOCKS5 when the VPN is up, direct when it isn’t.

→ mypeer.yourtailnet.ts.net:8443

When it asks for root

Why trust a DNS-flipping daemon?

03Self-verifying install

An install-time SHA-256 integrity manifest is verified before any library loads—tampered files refuse to start, and say what changed. Strict validation, absolute paths, fail-safe on ambiguity, 417 tests and counting.

compatibility

Works with any utun-route VPN

The daemon classifies routing changes from any VPN that takes the default route—including corporate clients like Cisco AnyConnect, GlobalProtect or Zscaler (classified, not lab-tested: report yours ↗) —no per-VPN plugins, no allowlists.

Mullvad · tested NordVPN · tested ProtonVPN Surfshark ExpressVPN corporate VPNs · any utun default-route your VPN ↗

Built in the open

Shipped, not promised.

No stars to flex, no fake logos. The repo is six months old and the commit history is the pitch: a slow spring, then a hardening sprint that hasn’t stopped.

Tagged releases—cumulative 29 of 31 releases shipped since Aug 24
0 10 20 30 Mar Jun Sep 1 Oct 31
View data table
DateCumulative tagged releases
2026-03-271
2026-04-092
2026-08-243
2026-08-314
2026-09-0111
2026-09-0223
2026-09-0326
2026-09-1127
2026-09-2228
2026-09-2329
2026-09-2430
2026-09-3031
0.8.17

Log rotation actually rotates—staged at daemon startup for every layout; integrity manifest now layout-aware.

2026-09-30 · tests 408 → 417

0.8.16

Second peers stay removable—hosts mappings land inside the managed block.

2026-09-24 · tests 406 → 408

0.8.15

Proxy registry self-heals against reality—and the auth key no longer leaks through argv.

2026-09-23 · tests 383 → 405

0.8.14

Every tunnel verb accepts the ssh alias—no more dead ends on tunnel check prime.

2026-09-23 · tests 367 → 383

0.8.11

tunnel check—the browser’s truth: hosts → listener → TLS → HTTP, zero ssh.

2026-09-03 · read-only by construction

22 releases in 72 hours (Sep 1–3)—the v0.7→v0.8 hardening sprint: a burst of fixes after the 0.8.0 rewrite, each one tagged and tested. Full history: CHANGELOG.md ↗

The model

One engine. Two apps.

Open core, honestly drawn: the engine is free and open source forever. The app is polish on the same engine—free while we sand the edges, a one-time license when it’s v1.0.

The core—CLI daemon

Everything, in your terminal

The full engine: MagicDNS toggling, SOCKS5 proxy, browser tunnels, helpers, integrity gate.

$0 forever · Apache-2.0 · no account

  • Every feature, no gates—proxies, tunnels, helpers
  • Homebrew or source; runs as a root launchd service
  • Your traffic never touches our infrastructure (there isn’t any)

star it, fork it, audit it—that’s the point

The shell—menu bar app

Set it and forget it

The same engine behind a native macOS UI: onboarding, live state, proxy and tunnel controls, update alerts.

Free during early access · planned one-time license at v1.0—never a subscription

  • Menu bar icon with live connection state
  • First-run onboarding and a diagnostic panel
  • Brew-aware updates with DMG download

early adopters shape the v1.0 roadmap—file issues

Honest limits

What it can’t fix

Told up front, not discovered later.

Network Extensions can still block the mesh

Modern macOS VPN apps intercept all outbound traffic—including packets to Tailscale’s CGNAT range (100.64/10). tailroute fixes the DNS conflict and can bridge peers through its proxy, but it cannot bypass Network-Extension packet interception. When direct mesh traffic is blocked, use the SOCKS5 proxy or a browser tunnel.

Mullvad—CGNAT blocked NordVPN—CGNAT blocked older VPNs—often fine

Also on the record: VPN active → MagicDNS names don’t resolve (use IPs or tunnels) · Firefox DoH bypasses /etc/hosts · won’t-fix by research: split-DNS, multi-VPN, IPv6. Report your VPN’s behavior ↗

FAQ

Asked, answered

Can I use Tailscale and my VPN at the same time on a Mac?
Yes—that’s exactly what tailroute does. When your VPN connects, the daemon toggles MagicDNS off and brings up a local SOCKS5 proxy, so internet flows through the VPN while peers stay reachable through the mesh—and it reverses itself when the VPN disconnects. Any VPN that takes the default route works; VPNs that also block Tailscale’s CGNAT range at the packet level (Mullvad, NordVPN) still need that proxy or a tunnel for direct peer traffic—next question covers those.
Does it work with Mullvad or NordVPN?
The DNS fix works—internet stays up through the VPN with Tailscale connected. But both VPNs block direct traffic to Tailscale’s CGNAT range at the Network-Extension layer, so direct peer connections fail; use the built-in SOCKS5 proxy (automatic) or a browser tunnel instead. Details in the compatibility notes.
What about corporate VPNs—Cisco AnyConnect, GlobalProtect, Zscaler?
The daemon classifies routing changes from any VPN that takes the default route—no per-VPN plugins, no allowlists. The DNS conflict is fixed automatically either way; if the corporate client also blocks the CGNAT range at the Network-Extension layer, the same proxy-and-tunnel path bridges your peers.
Which Tailscale install does it need?
The CLI daemon (brew install tailscale) is fully supported—tailroute toggles DNS over its unix socket. The GUI app works with limitations (fall-back MagicDNS detection), and the Mac App Store version is not supported.
Does it phone home?
No. No telemetry, no external network calls, no account, no traffic interception or logging. The only network activity is the proxy and tunnels you configure, pointing at your own tailnet.
It runs as root—why should I trust it?
Because it shows its work: install-time SHA-256 integrity manifest verified before any library loads, strict input validation, absolute paths only, fail-safe on ambiguous state, and a public threat model. The whole thing is ~7,400 lines of auditable bash and Go (7,194 sh + 217 Go, wc -l, Oct 2026). Prefer the manual? Read the full man page—shipped with this site.
What happens when I quit the VPN or uninstall?
VPN disconnects → MagicDNS is restored automatically (within ~60s, event-driven). Uninstall restores MagicDNS state, removes the daemon, tunnels, and hosts entries—and preserves logs for review.
Who is tailroute for—and who is it not for?
For one Mac running two networks at once: Tailscale alongside a second VPN—the corporate client (Cisco AnyConnect, GlobalProtect, Zscaler), a commercial privacy VPN (NordVPN, ProtonVPN, Surfshark), or a travel setup where hotel Wi-Fi meets your tailnet. Not for: Tailscale-only setups—if Tailscale is your only VPN or exit node, there is no conflict to manage—and Tailscale’s Mullvad exit-node add-on, which already solves coexistence inside Tailscale. Also out of scope: MagicDNS split DNS while on a VPN, multiple simultaneous VPNs, IPv6.
What’s the best way to run Tailscale and a VPN together on a Mac?
There are two working approaches. If your privacy VPN is Mullvad, Tailscale’s Mullvad exit-node add-on is the first-choice route—buy it inside Tailscale and skip a second app. For every other VPN (NordVPN, ProtonVPN, Surfshark, corporate clients), run tailroute alongside your VPN: it fixes the DNS conflict automatically and bridges peers through a local proxy when the VPN blocks Tailscale’s address range. Other paths—gluetun containers, VPS bridges, travel routers—work but demand constant upkeep.

Support the work

Open source isn’t free to build.

The CLI stays free and open source. If tailroute saved your sanity mid-deadline, a star or a sponsorship keeps the hardening sprint going.

Next milestone

Notarized, Gatekeeper-clean builds Apple Developer ID ($99/yr) buys signed + notarized DMGs—no more right-click-to-open for new users. Sponsorship goes here first.

Two minutes. Then never
think about it again.

Install, run one command, connect your VPN and Tailscale like you always do. There is no daily usage—that’s the whole point.

Menu bar app $ brew install --cask shrwnsan/tap/tailroute
CLI daemon $ brew install shrwnsan/tap/tailroute-cli

no account · no telemetry · uninstall restores everything