Documentation

Work & personal tailnet on one Mac

Keep a company tailnet and a home tailnet reachable at once on a single Mac, routed by hostname suffix — without logging out of either or switching the official Tailscale account.

View as Markdown

The setup#

You have a company tailnet for work infrastructure and a personal tailnet for your home lab. Account switching is useful if one tailnet is needed at a time, but it does not provide one local client with a concurrent path to both environments. TailMux gives each configured tailnet its own profile: an embedded tsnet node with its own identity, state, and key. It does not change the official Tailscale client session.

The mapping is by hostname suffix. A practical split:

  • work owns .corp.example.com and .work-tailnet.ts.net
  • personal owns .home-lab.ts.net

Each suffix belongs to exactly one profile, so a name like nas.home-lab.ts.net always resolves through the personal tailnet and db.corp.example.com always through work. Your official Tailscale account and session are never touched.

Define & validate#

Generate a starter config with tailmux init, then declare a profile per tailnet and the suffixes each one owns. The config lives at ~/.config/tailmux/config.yaml.

In the app there is no YAML: Open → Profiles, add a work and a personal profile, give each its suffixes, save, and restart the router when prompted. The config below is the same thing expressed in config.yaml for CLI/Linux setups.

config.yaml
1profiles:2  work:3    backend: tsnet4    accept_routes: true5    suffixes:6      - .corp.example.com7      - .work-tailnet.ts.net8  personal:9    backend: tsnet10    suffixes:11      - .home-lab.ts.net

Set accept_routes: true on a profile only when its hosts sit behind a tailnet subnet router. Then validate:

zsh — validate
$tailmux config validate
Each suffix must be owned by exactly one profile. If work and personal ever claim an overlapping suffix, validation rejects the config — this is what guarantees a work name can never silently resolve through your home tailnet.

Log each profile in#

Start the router, then authenticate each profile against its own tailnet. Each login opens that tailnet's Tailscale admin approval page, where the device appears under the hostname you set in config.

zsh — bring both up
$tailmux up$tailmux profile login work$tailmux profile login personal$tailmux profile list

Both profiles are now live at the same time. There is no active/inactive toggle and no logout — profile list shows each one connected to its own tailnet.

How routing stays apart#

TailMux routes at the proxy layer (router on 127.0.0.1:43100, loopback only), with the hostname suffix as the routing key. The decision is made while the original hostname is still intact, before it can collapse into an ambiguous IP address.

  • A name owned by work dials only through the work node; a name owned by personal dials only through the personal node.
  • There is no cross-profile fallback — if the owning profile cannot reach a host, the request fails rather than retrying on the other tailnet.
  • The official Tailscale client's account and session are never read or mutated.
Because each profile is an independent embedded node, the two tailnets never see each other. Work infrastructure stays isolated from your home lab even though both are reachable from the same Mac.

Using both at once#

Once both profiles are up, documented hostname-preserving access paths choose the right tailnet from the hostname suffix. Some paths are suffix-selected while a local tunnel can be pinned to one explicit profile; check the reference for the client you use.

  • Browser — the app points the system proxy at TailMux's PAC automatically, so Safari just works; configured suffixes route through TailMux and public web traffic stays DIRECT. See browser routing.
  • CLI HTTP — wrap a single command with tailmux run -- <cmd>, or export the proxy into the current shell with tailmux env. Routing is still by suffix, so the same shell can hit work and personal hosts in turn.
  • SSH & native clients — use tailmux connect for a single stream or tailmux tunnel for a loopback listener. See SSH, RDP & SMB.
zsh — same shell, both tailnets
$tailmux run -- curl https://ci.corp.example.com/health$tailmux run -- curl https://grafana.home-lab.ts.net/
TailMux does not create a second system-wide VPN interface. Review the limitations and routing model before treating a raw-IP, UDP, or proxy-bypassing client as a multi-tailnet workflow.

Verify#

Confirm each hostname classifies to the profile you expect, then open a raw connection to check reachability:

zsh — test both
$tailmux test db.corp.example.com$tailmux test nas.home-lab.ts.net$tailmux connect nas.home-lab.ts.net 8080

For a full report — owning profile, peer visibility, direct vs. DERP path, and HTTP timing — run a path diagnostic:

zsh — diag
$tailmux diag path \$  http://grafana.home-lab.ts.net:3000/ \$  --netcheck

New to TailMux? Start with getting started, read the background on two Tailscale accounts on one machine, or see pricing.