On this page
Network: reachability, not security
What it is
All my devices and all development environments sit in one shared private network, a tailnet based on WireGuard. I use Tailscale as the client. Coordination is done by Headscale, the open-source implementation of the Tailscale control server. I run it myself and log in through my own identity provider. To get started, Tailscale’s free tier is just as good; Headscale is a side note for people who want to self-host everything.
Its role
Every development environment joins the tailnet as a machine of its own, with its
own name. They all listen on the same ports and differ only by name:
hatchery-levino-shipyard, hatchery-levino-levinkeller-de and so on. Instead of
remembering which environment is on which port of the server, I address it directly.
I don’t hand out ports on the server, don’t maintain port forwards and don’t open
anything to the internet. To look at an environment’s dev server in the browser, I
just open its name plus the port, from the laptop or the phone.
The environments are registered as ephemeral nodes: delete one, and after a while it disappears from the device list by itself.
What it is not
The tailnet is not my security layer. It’s convenient and it reduces the attack surface, but I don’t rely on it. Being in the tailnet doesn’t get anyone into an environment: each one requires my key for SSH login, and that key needs my fingerprint (see Identity and access). Password login is off.
There’s a practical reason for that: a network that gets misconfigured once, a device that gets lost, a share you forgot about – all of that happens. If security depends on a single layer, that’s one too few.
A back door, on purpose
The server itself is also reachable via plain SSH from the internet. That’s deliberate: when the tailnet acts up (and it occasionally does), I can still get in and fix it. A network that can only be repaired through itself is a trap.
Alternatives
- Opening ports on the host and working through SSH tunnels. Works, but scales poorly: every environment needs its own ports and you have to remember them.
- A classic VPN (OpenVPN, plain WireGuard). Works, but you maintain keys and IP addresses by hand, and new environments don’t show up on their own.
- ZeroTier, Nebula, NetBird. Similar idea to Tailscale. Tailscale won for me because there’s a ready-made devcontainer feature and because Headscale exists as a free control server.