I built a little self-hosted job-application tracker. When I needed to reach it from another device, I put it behind tailscale serve instead of opening a port — a real trusted cert, no 0.0.0.0, identity-based access. The fun part: I was dogfooding the exact product I'd just applied to.
My first instinct for remote access was the usual: bind the server to 0.0.0.0, slap Basic Auth on it, generate a self-signed cert. It works — but it means a publicly-listening port, a browser "not secure" warning, and a shared password as the only gate.
Tailscale flips that. The app stays bound to 127.0.0.1 — invisible to the network — and the tailnet becomes the boundary. Every device that should reach it is already authenticated to my tailnet; nothing else can even see it. And tailscale serve provisions a genuine Let's Encrypt cert for the machine's *.ts.net name, so the green padlock just works.
A few of these steps need sudo and your Tailscale login — by design. That's the onboarding worth paying attention to if you're learning the product.
The official one-liner detects your distro and installs the client + daemon. Needs sudo.
$ curl -fsSL https://tailscale.com/install.sh | sh
This prints a login.tailscale.com URL and opens a browser. First run is where you create the account (Google / GitHub / Microsoft / email). When it returns, the machine is on your tailnet — this is the whole onboarding flow, and it's genuinely a 30-second affair.
sudo tailscale up
By default the tailscale CLI needs root. Setting an operator lets your normal user drive the daemon, which makes the serve step (and day-to-day status checks) friction-free.
sudo tailscale set --operator=$USER
In the admin console under DNS, flip these on. They're what let tailscale serve mint a trusted cert for your <host>.<tailnet>.ts.net name — no warning, nothing to import on the client.
*.ts.net name instead of a raw IP.Now the good part. I bound the app back to 127.0.0.1 — the tailnet is the security boundary, so there's no reason to listen on anything public — and let tailscale serve front it with the trusted cert.
# app listens on 127.0.0.1:8765 — invisible to the LAN $ tailscale serve --bg https / http://127.0.0.1:8765 # confirm what's being served, and at what URL $ tailscale serve status
That's it. From any device on the tailnet I hit https://<host>.<tailnet>.ts.net — green padlock, no port, no password prompt, no 0.0.0.0 anywhere.
The other device has to be on the same tailnet to resolve the .ts.net name — so install Tailscale there too and log in with the same account. That's the access list; there isn't a second one.
install.sh).I came in having never used Tailscale, and an afternoon later my own app was reachable from anywhere I'm logged in — with a real cert and zero public surface. The mental model that clicked: the tailnet is the auth boundary, so the app doesn't need its own front door at all.
If you're evaluating it, the fastest way to "get it" is to put something you already run behind tailscale serve and watch the padlock go green. That beats reading about it.