A tailnet where every device reaches every other device is already useful. Three additions make it a network rather than a set of tunnels, and all three share one property that trips people up: the client advertises a capability, and the server must approve it. A route that is advertised but not approved simply does not exist, silently, and the symptom is that you can ping the router but nothing behind it.
A subnet router — put a whole LAN on the tailnet. One machine on a home or office network advertises the network's range; every other device then reaches the printers, the NAS and the management interfaces behind it without anything else being installed there. Turn on forwarding in the kernel first, or the packets stop at the router without an error message.
# On the machine that sits inside the LAN:
echo 'net.ipv4.ip_forward = 1' | sudo tee /etc/sysctl.d/99-ts.conf
echo 'net.ipv6.conf.all.forwarding = 1' | sudo tee -a /etc/sysctl.d/99-ts.conf
sudo sysctl -p /etc/sysctl.d/99-ts.conf
sudo tailscale up --login-server https://vpn.example.com \
--advertise-routes=192.168.1.0/24 --accept-routes
# On the control server — approve it, or it does not exist.
# The subcommand moved between releases; check `hs nodes --help` first.
hs nodes list
hs nodes approve-routes --identifier 3 --routes 192.168.1.0/24
An exit node — send everything out through the VPS. The same mechanism with a wider route: a device that advertises itself as an exit node offers to carry another device's entire internet connection. On an untrusted café or hotel network that is exactly what you want, and it is the closest thing in this guide to a personal VPN.
# On the VPS that will do the exiting (forwarding must be on, as above):
sudo tailscale up --login-server https://vpn.example.com --advertise-exit-node
# Approve it on the control server, then on the laptop:
tailscale set --exit-node=100.64.0.1 --exit-node-allow-lan-access
tailscale set --exit-node= # turn it off again
An exit node is not a commercial VPN and should not be sold to yourself as one. Its address is yours alone and it is stable, which is excellent against the café Wi-Fi and useless against long-term correlation across sites — the trade-off is spelled out in the pillar guide. Note also that you can run the exit node on a second, cheaper VPS and keep the control server free of forwarded traffic entirely.
Access rules — write them before the second person joins. The default policy is allow-everything, which is correct for a tailnet of one and wrong the moment somebody else is on it. The policy is a small HuJSON document: groups of users, tags for machines, and a list of rules that say which sources may reach which destinations on which ports. Point the configuration at the file, keep the file in version control, and reload after each edit.
{
"groups": {
"group:admin": ["alice"],
"group:contractor":["bob"]
},
"tagOwners": {
"tag:server": ["group:admin"],
"tag:exit": ["group:admin"]
},
"acls": [
// Admins reach everything.
{ "action": "accept", "src": ["group:admin"], "dst": ["*:*"] },
// The contractor reaches one machine, on two ports, and nothing else.
{ "action": "accept", "src": ["group:contractor"],
"dst": ["tag:server:22,443"] }
],
"autoApprovers": {
"routes": { "192.168.1.0/24": ["tag:server"] },
"exitNode": ["tag:exit"]
}
}
Two notes on that file. The policy language is Tailscale's, and Headscale implements a large and growing subset of it rather than all of it — check the documentation for your version before relying on an exotic rule. And where the policy lives has moved: older releases named a path in the top-level configuration, newer ones group it under a policy section with a mode that can also keep the rules in the database. Both are documented; the one that matters is the one your pinned version ships.
MagicDNS — short names, and your own resolver everywhere. With MagicDNS on, every device answers to a short name inside the suffix you chose in step 02, so ssh nas works from anywhere without a hosts file. The second half is the interesting one: the control server also pushes a nameserver list to every client, which means the resolver you built in the private DNS resolver guide can serve your phone on mobile data — filtering, caching and logging nothing — while listening on a tailnet address that is not reachable from the internet at all.
dns:
magic_dns: true
base_domain: ts.example.com
override_local_dns: true # beat whatever DHCP handed the device
nameservers:
global:
- 100.64.0.5 # your resolver, on the tailnet