You have one personal VPS at a budget host, a NAS at home, and maybe a Raspberry Pi running Pi-hole. You want to reach all three from your laptop without exposing SSH on the public internet, without messing with port forwarding on your home router, and without paying for a corporate VPN you don’t need. The conventional answer used to be “stand up your own WireGuard server and write a config file for every device.” It works, but it’s three weekends of yak-shaving for a one-person infrastructure.
Tailscale is the answer the rest of us have been quietly switching to. This post is the setup, the small-but-real ACL gotchas, and an honest comparison against WireGuard, chisel, and OpenVPN for the kind of personal-fleet use case I just described.
What Tailscale actually is
It’s WireGuard underneath, with a hosted control plane that handles the parts WireGuard makes you do by hand: key exchange, peer discovery, NAT traversal, and a sane permission model. Your devices register with Tailscale’s coordination server (over TLS), get a Tailscale-assigned IP in the 100.64.0.0/10 CGNAT range, and then talk to each other directly over WireGuard. The control plane never sees your traffic — it just helps the peers find each other.
The free tier covers up to 100 devices and 3 users — which is, for a one-person infra, infinitely more than you need.
Setup on a fresh Linux box
# Install (Debian / Ubuntu — they publish a one-liner installer)
curl -fsSL https://tailscale.com/install.sh | sh
# Bring it up. The first time you run this, it'll print a URL to authenticate.
sudo tailscale up
# Confirm
tailscale status
tailscale ip -4 # this box's tailnet IPThe auth URL takes you to a browser. Sign in with your Google / Microsoft / GitHub account; from then on, this device is in your tailnet. Repeat on every other Linux box, your Mac (the GUI installer is fine), your iPhone (App Store), and your home router if it supports it.
The two flags worth knowing on day one
--ssh— Tailscale SSH. Replaces sshd’s auth with tailnet auth, so any device in your tailnet can SSH to this box without keys, with the user identity coming from your Tailscale account.sudo tailscale up --sshand you canssh user@nasfrom your laptop with zero key config.--advertise-exit-node— turns this device into an exit node so other tailnet devices can route their public-internet traffic through it. Useful for a self-hosted VPN-to-the-coffee-shop scenario. Combine withtailscale up --exit-node=<node>on the client.
ACLs — the part that bites
By default a tailnet is fully connected — every device can reach every other device on every port. For a one-person infra that’s usually fine, but the day you add a friend’s device or your kid’s iPad to the tailnet, you’ll want to scope it down.
The ACL editor is at login.tailscale.com/admin/acls. The shape of an ACL file:
{
"tagOwners": {
"tag:server": ["autogroup:admin"]
},
"acls": [
// I (admin) can reach my own devices fully
{ "action": "accept", "src": ["autogroup:admin"], "dst": ["*:*"] },
// Tagged servers can talk to each other on tcp 22, 80, 443 only
{ "action": "accept", "src": ["tag:server"], "dst": ["tag:server:22,80,443"] },
// Guests can only reach the home NAS on web ports
{ "action": "accept", "src": ["group:guests"], "dst": ["100.x.y.z:80,443"] }
],
"groups": {
"group:guests": ["friend@gmail.com"]
}
}The two non-obvious things:
- Once you save an ACL, the implicit default-allow disappears. If you forget to add a rule for your own admin account, you’ll lock yourself out of your own tailnet. Always include
{"action": "accept", "src": ["autogroup:admin"], "dst": ["*:*"]}as the first rule. - Tags are applied at
tailscale uptime, not via the ACL. You tag a device withsudo tailscale up --advertise-tags=tag:serveron the device itself. The ACL only declares which tags are allowed and what they can do.
Tailscale vs WireGuard vs chisel vs OpenVPN — for a one-person infra
- Vanilla WireGuard. Battle-tested, kernel-fast, free. But you write a config file per peer and rotate keys by hand. Adding a new device is a 10-minute task — fine for two devices, painful for ten. No NAT traversal — both sides need a routable address (or you need to write your own STUN-equivalent). Pick this if you have exactly one box and exactly one client and intend to keep it that way for years.
- chisel. A single-binary Go tool that tunnels TCP/UDP through HTTPS. Brilliant for “I’m on a hotel Wi-Fi behind aggressive NAT and need to reach my home box for an hour.” Not a long-term VPN — no full-mesh, no key rotation, no ACLs, no IP plan. Pick this for ad-hoc tunnels alongside Tailscale, not instead of it.
- OpenVPN. Mature, supported on every device that’s ever existed, including ancient routers. But the config is fiddly, the protocol overhead is real, and on modern Linux WireGuard outperforms it by 2-3× for the same CPU. Pick this if you have to integrate with a corporate VPN that already speaks it. Otherwise, no.
- Tailscale. WireGuard fast path, hosted-but-private control plane, sane web ACL editor, MagicDNS, exit nodes, free tier that covers a one-person fleet. The cost is that you’re trusting Tailscale’s coordination server (which never sees your traffic but does see metadata). For most people that’s a reasonable trade.
What I’d actually recommend
Tailscale on every device, with these settings on day one: ACL editor saved with the admin-allow-all rule on top, MagicDNS on (so you can ssh nas instead of remembering CGNAT IPs), and Tailscale SSH on the boxes you log into often. That’s a 30-minute setup that replaces three different VPN configs and an hour-long debugging session per new device.
If you’re allergic to hosted control planes, the open-source headscale reimplementation lets you self-host the coordination server while keeping the Tailscale client. It’s a more involved setup, but it preserves the ergonomics for a more paranoid threat model.
Photo: Modern server room with network rack by cookiecutter on Pexels.
