Build Tailscale

KINDAreplaces $8/mosaves $96/yrback to the verdict

0%0 of 19 items done

Saved on this device only. Tick prerequisites first, then work the phases in order · do not start one until the checks above it pass.

Your own Tailscale control plane: headscale on a VPS behind Caddy, the official Tailscale clients pointed at it, MagicDNS and a deny-by-default ACL, an embedded relay and an exit node, and a restore you performed before switching off the free account.

estimated effort weekendthe files for this build are in the project pack

Control planeheadscaleData planeWireGuard via the official Tailscale clientsTLSCaddy

Before step 1

Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.

  1. installfree

    Why Every step below is a command you type or a file you edit.

    Get it VS Code (code.visualstudio.com), Cursor or Zed. Open a folder for the project and use the editor's built-in terminal. open ↗

    Verify You can open a folder and run a command in its terminal

  2. installfree

    Why History for your code, and the way most hosts deploy.

    Get it Install from git-scm.com or with your package manager, then run git init in the project folder once it exists. open ↗

    Verify git --version prints a version

  3. decidefree

    Why The honest reason to do this is owning the control plane, not saving money.

    Get it Read tailscale.com/pricing once. open ↗

  4. about $5 a month

    Why This needs one process running all the time with a public address. The coordination server needs a public IP.

    Get it Hetzner Cloud (from about 4 EUR), DigitalOcean or Fly.io. Ubuntu 24.04, the smallest size. You need SSH access and a public IP. Only needed for the deploy phase; develop locally first. open ↗

  5. roughly $10 a year, or free on an existing domain

    Why hs.yourdomain.com

    Get it Register at Cloudflare Registrar, Porkbun or Namecheap, or use a subdomain of one you already own. You add one DNS record in the deploy phase. open ↗

  6. installfree

    Why Automatic HTTPS in front of the Node process. Without TLS the browser features this relies on (and your visitors' trust) do not work.

    Get it On the VPS: follow the install steps at caddyserver.com/docs/install for Ubuntu. One Caddyfile with your domain and a reverse_proxy line is the whole config. open ↗

    Verify caddy version prints a version on the server

  7. installfree

    Why The control server.

    Get it Download the .deb from github.com/juanfont/headscale/releases and install it on the VPS. open ↗

    Verify headscale version prints

  8. installfree

    Why The endpoints.

    Get it tailscale.com/download for each platform. open ↗

  9. cents

    Why The headscale database is the network's identity.

    Get it rclone to B2 or R2. open ↗

Environment variables

These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.

VariableNeededExampleWhere the value comes from
HEADSCALE_URLrequiredhttps://hs.yourdomain.comPublic server URL in config.yaml.
BASE_DOMAINrequiredts.yourdomain.internalMagicDNS base domain; must differ from the server's domain.

The build, in order

  1. The server

    headscale up behind Caddy with one user.

    1. Files /etc/headscale/config.yamlCaddyfile

    2. terminal
      sudo systemctl enable --now headscale
      headscale users create you
    done when · tick each as it passes
  2. First two devices

    A laptop and a phone reach each other directly.

    1. terminal
      headscale preauthkeys create --user you --reusable --expiration 24h
      tailscale up --login-server https://hs.yourdomain.com --authkey <key>
    done when · tick each as it passes
  3. DNS and ACLs

    Names that resolve and a policy that denies by default.

    done when · tick each as it passes
  4. Relays and exit node

    Hostile NATs still connect; one machine routes traffic.

    1. terminal
      tailscale up --advertise-exit-node
      headscale routes enable -r <id>
    done when · tick each as it passes
  5. Backup and restore drill

    The database off the box and a restore that keeps devices connected.

    1. terminal
      sqlite3 /var/lib/headscale/db.sqlite ".backup '/tmp/hs-$(date +%F).db'"
      rclone copy /tmp/hs-$(date +%F).db remote:headscale/
    done when · tick each as it passes
    watch out
    • Until the restore drill is done, keep the free Tailscale account.
what this build does not replace
after v1, if you want it

Need the files? The project pack on the verdict page hands your agent the whole brief · more security.