How to connect two Tailscale tailnets
Reach across two tailnets with node sharing, user switching, a two-daemon VPS bridge or one tailnet with ACLs. See what each option exposes to the other side.
How do you connect two Tailscale tailnets?
To connect two Tailscale tailnets, you reach across them one machine at a time. Tailscale's docs on sharing, user switching and multiple tailnets do not describe any step that merges two tailnets. They also do not describe a way to peer them like two LANs behind routers. So the real question is which crossing point you can afford, and what it exposes to the other side.
This guide ranks the options from the least work to the most. Every statement about Tailscale behaviour comes from its docs and source code, read on 2026-10-09. The two-daemon bridge is a pattern you build and test yourself. Tailscale does not document it.
The options, from least work to most
- Node sharing. Share one machine into the other tailnet. You install nothing extra, but the admins on both sides must agree.
- Fast user switching. One device holds logins for both tailnets and switches between them. Only one tailnet is active at a time.
- Multiple tailnets. An alpha feature that gives one organisation several tailnets under one identity provider. It organises tailnets. Its docs do not describe it connecting them.
- A VPS bridge. One server runs two
tailscaleddaemons, one per tailnet, and relays chosen ports from one side to the other. - One tailnet with access rules, or one self-hosted control plane with Headscale. This is often the honest answer.
If Tailscale is new to you, read what Tailscale is and how a tailnet works first, then come back.
Share a single machine into the other tailnet
Node sharing is available on all Tailscale plans. It lets you invite another tailnet to reach one of your machines. These rules come from Tailscale's sharing page:
- To share a machine, you must be an Owner, Admin or IT admin of your tailnet.
- To accept the invitation, the recipient must also be an Owner, Admin or IT admin of their tailnet. A normal member cannot accept it.
- Tailscale quarantines shared machines by default. A shared machine can receive incoming connections from the other tailnet, but it cannot start connections.
- Shared machines can only be reached by their fully qualified domain name (FQDN), in the form
<hostname>.<tailnet-name>.ts.net. This applies to Tailscale v1.4 and later. - Shared machines do not advertise subnets to the tailnets they are shared into.
- Sharing strips tags, groups and subnet information from the recipient tailnet. A machine with a tag cannot be shared, and tagged machines on another tailnet cannot reach a share.
- A node shared into a tailnet that uses Tailnet Lock needs a signature before it is accessible.
You share from the Machines page of the admin console. Pick the machine, choose Share, then send an invite. Link-based sharing is in beta. A reusable invite link can be used up to 1,000 times, and unused links expire in 30 days.
Quarantine is the rule that surprises people. Say you share your nas into a friend's tailnet. Their laptop can open nas. But nas cannot open their laptop, because a share only allows connections towards the shared machine. If both sides need to start connections, the docs describe mutual sharing: each side shares its machine with the other, so the two machines can make outbound connections to each other.
Check a share from the receiving side, using the full name:
tailscale ping nas.tailnet-a.ts.netReplace tailnet-a with the real tailnet name of the machine's owner. A working share should print a line that starts with pong from. If the short name nas does not resolve, that is expected. Shared machines answer only to the FQDN.
To revoke a share, open the same Share dialog, open its menu and choose Revoke invite. After that, the recipient can no longer reach the machine.
What node sharing exposes: one machine, to the users of one other tailnet. Their admins decide who on their side can reach it. Your subnets stay private, because a shared machine does not advertise them. Inviting a user into your tailnet is different. An invited user does get access to subnet routers, and a Tailscale subnet router on a VPS is the usual way to publish a private network that way.
Can you share an exit node with another tailnet?
Yes. Sharing an exit node exposes it to the other tailnet, so the other side can send its internet traffic through your machine. The steps from the docs:
- Advertise the machine as an exit node.
- If you do not use
autoApprovers, allow the exit node in the admin console. - When you share the machine, check Allow use as an exit node.
sudo tailscale set --advertise-exit-nodeThe server side is covered in running a Tailscale exit node on a VPS. Think about the cost before you tick the box. Every page the other tailnet loads leaves from your server's public IP address, and that traffic counts against your bandwidth allowance.
Fast user switching: one tailnet at a time
Fast user switching lets one device hold logins for two or more accounts and move between them without logging in again. On Linux, macOS and Windows you can do it from the CLI (command-line interface). On Linux these commands need sudo unless you made your user the operator, which running tailscale without sudo using set --operator explains.
sudo tailscale switch --list
sudo tailscale switch alice@example.com
sudo tailscale set --nickname=work
sudo tailscale switch worktailscale switch --list should print every account this device knows. After you set a nickname, you can switch with the nickname. You are asked to log in again only if the device's node key for the target tailnet has expired, or if the account was never used on this device.
The limit is stated in the docs. A client lets only one account be active at a time, and a device cannot send packets on several tailnets at once. So when you switch, anything you had open to the old tailnet stops getting traffic. This suits a person who works in one tailnet and then the other. It does not suit a server that must serve both.
What switching exposes: nothing new. Each tailnet sees the device only while it is active there, under that tailnet's rules.
Does the multiple tailnets feature connect them?
The multiple tailnets feature is in alpha. It gives one organisation extra tailnets, and its docs set firm conditions:
- All additional tailnets must use the same domain and identity provider (IdP) as your existing tailnet.
- You cannot create them yourself. You contact Tailscale's sales team, and your Account Executive or Solutions Engineer creates the extra tailnet on your behalf.
- A GitHub organisation account cannot be used to enable or create them.
- Each tailnet has its own policy file, and you control access tailnet by tailnet.
The docs describe a separate policy file for each tailnet. They do not describe any way for a device in one tailnet to reach a device in another. So treat this feature as a way to organise tailnets. To connect them, you still need one of the other methods in this guide.
Why two tailnets can hand out the same address
Tailscale gives each device an IPv4 address from 100.64.0.0/10. That block is the CGNAT (carrier-grade network address translation) range, set aside for special use. Each device gets a unique address inside its tailnet.
The uniqueness stops at the edge of the tailnet. Maisem Ali's exe.dev post of 2026-07-24, "tailmix: Connect to Multiple Tailnets at Once", says it directly: "Tailscale allocates IPv4 addresses independently within each tailnet." It follows that "two nodes in two different tailnets can end up with the same IPv4 address." You can see this yourself. Run tailscale status in both tailnets and compare the address column.
This matters the moment one machine joins both tailnets. If a peer in tailnet A and a peer in tailnet B hold the same address, a packet to that address has two possible owners. The bridge below avoids the problem. Tailnet B's traffic never goes through the kernel's routing table. It goes through a local SOCKS5 proxy, so each tailnet's addresses live in a separate place.
Build a VPS bridge with two tailscaled daemons
Here is the pattern. One VPS joins tailnet A with the normal packaged tailscaled. A second tailscaled joins tailnet B with its own state file, its own socket, its own UDP port and no TUN device. Then socat listens on the VPS's tailnet A address and relays one port to one machine in tailnet B.
The second daemon uses userspace networking (--tun=userspace-networking). With no TUN device, it creates no network interface, so it adds no routes for the kernel to mix up with tailnet A's routes. Programs reach tailnet B through a SOCKS5 proxy that this daemon serves on localhost.
Pin the release and read the flags
The flags below were checked against the Tailscale v1.104.1 source, which was the latest release on 2026-10-09. Install Tailscale with the official script, then confirm which version you got:
curl -fsSL https://tailscale.com/install.sh | sh
tailscale version
tailscaled --help 2>&1 | grep -E -- '-(state|statedir|socket|tun|port|socks5-server) 'If tailscale version prints a newer release, read the help output before you copy anything below. This is what each flag does in v1.104.1:
--state: the absolute path of the state file. This file holds the node's keys, so each daemon needs its own.--statedir: the directory for config state, TLS (transport layer security) certificates and incoming Taildrop files. If you leave it empty, it is derived from--state.--socket: the path of the Unix socket that thetailscaleCLI talks to. On Linux the default is/var/run/tailscale/tailscaled.sock. The CLI has its own--socketflag, so every command for the second daemon must carry it.--tun: the tunnel interface name. The Linux default istailscale0. The valueuserspace-networking(beta) means no TUN device at all.--port: the UDP (user datagram protocol) port for WireGuard and peer-to-peer traffic.0means pick a port automatically.--socks5-server: the address where a userspace daemon serves its SOCKS5 proxy.
The packaged daemon already owns the defaults. Run systemctl cat tailscaled to see its unit. It reads /etc/default/tailscaled, which sets PORT="41641", and it puts its socket under /run/tailscale/. The second daemon must use a different state file, socket and port.
Join tailnet A with the packaged daemon
sudo tailscale up --hostname=bridge-a
tailscale ip -4tailscale up prints a login URL. Open it and log in to tailnet A. After that, tailscale ip -4 should print one address that starts with 100..
Run a second daemon for tailnet B
Create /etc/systemd/system/tailscaled-b.service:
[Unit]
Description=Second tailscaled for tailnet B (userspace)
Wants=network-online.target
After=network-online.target
[Service]
Type=notify
ExecStart=/usr/sbin/tailscaled --state=/var/lib/tailscale-b/tailscaled.state --socket=/run/tailscale-b/tailscaled.sock --tun=userspace-networking --port=41642 --socks5-server=127.0.0.1:1055
Restart=on-failure
RuntimeDirectory=tailscale-b
RuntimeDirectoryMode=0755
StateDirectory=tailscale-b
StateDirectoryMode=0700
[Install]
WantedBy=multi-user.targetStateDirectory and RuntimeDirectory make systemd create /var/lib/tailscale-b and /run/tailscale-b with the modes shown. The packaged unit also runs tailscaled --cleanup after it stops. This copy leaves that line out, because a userspace daemon has no interface or routes to clean up.
Start the daemon and log in to tailnet B through its own socket:
sudo systemctl daemon-reload
sudo systemctl enable --now tailscaled-b
sudo tailscale --socket=/run/tailscale-b/tailscaled.sock up --hostname=bridge-bOpen the printed URL and log in to tailnet B, not tailnet A. If your browser still holds the tailnet A session, use a private window.
Check that the two daemons stay apart
sudo tailscale status
sudo tailscale --socket=/run/tailscale-b/tailscaled.sock status
ip -brief link | grep tailscaleThe first status should list tailnet A's machines. The second should list tailnet B's machines. ip -brief link should show one interface, tailscale0. A second Tailscale interface means the B daemon started without --tun=userspace-networking. If the second status cannot connect, the socket path in the command does not match the path in the unit.
The B daemon listens on UDP 41642. If your firewall blocks that port, connections can fall back to Tailscale's relays, which are slower. How to tell a direct Tailscale connection from a relayed one shows how to check.
Reach a tailnet B machine through the proxy
Find the tailnet B address of the machine you want, here nas. Then fetch a page from it through the SOCKS5 proxy:
B_IP=$(sudo tailscale --socket=/run/tailscale-b/tailscaled.sock ip -4 nas)
echo "$B_IP"
curl --socks5 127.0.0.1:1055 "http://$B_IP/"curl should return the page that nas serves on port 80. Without --socks5, the request goes to the kernel, and only the B daemon talks to tailnet B. So that request never reaches nas.
Relay one port with socat
socat 1.8 in Ubuntu 24.04 has a SOCKS5-CONNECT address type. It takes <socks-server>:<socks-port>:<target-host>:<target-port>. The man page marks this address type as experimental, so test the relay before you rely on it.
Install socat and save both addresses in one file:
sudo apt install -y socat
printf 'A_IP=%s\nB_IP=%s\n' "$(tailscale ip -4)" "$B_IP" | sudo tee /etc/default/tailnet-bridgeCreate /etc/systemd/system/tailnet-bridge.service:
[Unit]
Description=Relay tailnet A port 8080 to nas in tailnet B
After=tailscaled.service tailscaled-b.service
Requires=tailscaled-b.service
[Service]
EnvironmentFile=/etc/default/tailnet-bridge
ExecStart=/usr/bin/socat TCP-LISTEN:8080,bind=${A_IP},fork,reuseaddr SOCKS5-CONNECT:127.0.0.1:1055:${B_IP}:80
Restart=on-failure
RestartSec=5
DynamicUser=yes
[Install]
WantedBy=multi-user.targetbind=${A_IP} makes socat listen only on the tailnet A address, so the relay is not open on the public interface. At boot, tailscale0 may get its address after this unit starts. Then socat exits with Cannot assign requested address, and Restart=on-failure tries again until the address exists.
sudo systemctl daemon-reload
sudo systemctl enable --now tailnet-bridge
sudo ss -ltnp | grep 8080ss should show socat listening on the tailnet A address, port 8080. From any device in tailnet A, curl http://bridge-a:8080/ should now return the same page as the proxy test. The short name bridge-a needs MagicDNS in tailnet A. Without MagicDNS, use the address that tailscale ip -4 printed on the bridge.
Why does the address collision not matter here? Tailnet A traffic arrives on tailscale0 through the kernel. Tailnet B traffic leaves through the proxy, inside the B daemon. The two address spaces never meet in one routing table. So the relay still works if a tailnet A laptop holds the same address as nas in tailnet B.
What the bridge exposes, and to whom
Explain these points to the other tailnet's admins before you build it.
- Tailnet B sees one machine,
bridge-b. Every relayed connection arrives from the address ofbridge-b. Tailnet B's access rules cannot tell which tailnet A user is behind it. - Tailnet A reaches whatever you relay. Anyone that tailnet A's policy lets reach
bridge-aon port 8080 also reachesnason port 80. A new tailnet's default policy file allows communication between all devices, so write a rule that limits port 8080 to the people who need it. - The VPS holds keys for both tailnets. Root on the VPS can read both state files and act as a member of either tailnet. Protect it like your most sensitive node, and read what Tailscale's security model protects and what it does not.
- The bridge only needs to dial out into tailnet B. Tailscale rules are directional: allowing a source to connect to a destination does not let the destination connect back. Tailnet B's admins can allow
bridge-bto reachnason port 80, and nothing else.
tailmix: a third-party alternative
tailmix, by Maisem Ali, takes a different route on a single device. It runs several tsnet.Server instances behind a single TUN interface. Each peer from every tailnet gets a new IPv4 address from a pool you configure on the machine, and MagicDNS is changed to return those addresses. Traffic to one of those addresses then goes through the tailnet that owns that peer.
Know what you are installing. The README says tailmix is an independent project and is not affiliated with, sponsored by or endorsed by Tailscale Inc. It uses the BSD 3-Clause License, except for the forked tsnet/ and netns/ code, which keeps Tailscale's copyright and licences. The README makes no security audit claim, and we have not audited the code. The README also tells you to disconnect the regular Tailscale client before you start tailmix, because the two can compete for routes and DNS.
When is one tailnet with ACLs the honest answer?
Every method above adds a crossing point that someone must run and watch. If the two groups trust the same admins, one tailnet with access rules is often simpler.
ACLs (access control lists) are available on all plans, though some functions are limited on some plans. A new tailnet's default policy file allows communication between all devices. With a default-deny policy, devices cannot talk to each other unless a rule gives them access. So one tailnet can hold two teams that each see only what you allow. Each team can also keep its own subnet router, because invited users get access to subnet routers and shared machines never advertise subnets.
Sometimes the real problem is that you do not want a hosted control plane at all. Then self-hosting is the other honest answer. Headscale is an open source, self-hosted implementation of the Tailscale control server. Its docs say it implements "a single Tailscale network (tailnet)", and they describe it as suitable for personal use or a small open-source organisation. So Headscale also runs one tailnet, with you as the only admin. Running Headscale as a self-hosted Tailscale control server covers the setup.
Pick node sharing when a single machine needs to cross. Pick the bridge when the two tailnets must stay separate, with separate admins, and one or two services need to cross. Pick one tailnet when the separation was never really needed.
FAQ
Can I merge two Tailscale tailnets into one?
Tailscale's docs on sharing, user switching and multiple tailnets do not describe a merge or peering step. To move a machine, log it out of the old tailnet with tailscale logout, then join the new one with tailscale up. Until every machine has moved, node sharing lets single machines cross, and a VPS running two tailscaled daemons can relay chosen ports between the two tailnets.
Why can't I reach a shared machine by its short name?
Tailscale's sharing docs say shared machines can only be reached by their fully qualified domain name, <hostname>.<tailnet-name>.ts.net, on Tailscale v1.4 and later. Use the full name, which includes the owner's tailnet name. Run tailscale ping with that full name to check that the share works.
Why can't a shared machine connect back to my devices?
Tailscale quarantines shared machines by default. A shared machine can receive connections from the other tailnet, but it cannot start them. If both sides need to start connections, share in both directions, so each tailnet shares its machine with the other. Tailscale's docs call this mutual sharing.
Can one device be in two tailnets at the same time?
A normal Tailscale client lets only one account be active at a time, and a device cannot send packets on two tailnets at once. Fast user switching moves between them without a new login. A Linux server can run a second tailscaled with its own state file, socket, port and --tun=userspace-networking, which keeps both tailnets up at once. Tailscale does not document that setup, so test it on the release you run.