Getting started
Headtower needs two things to come online: the URL of a reachable Headscale instance, and an API key it can use to talk to it. Everything else is optional.
Prerequisites
- A running Headscale control plane that Headtower can reach over the network.
- A Headscale API key (Headtower authenticates to the control plane with it).
- Node.js 22.5+ (24 recommended) and pnpm if you are running from source - Headtower uses the built-in
node:sqlite, which needs 22.5 or newer.
Generate an API key from your Headscale host with headscale apikeys create.
Treat it like a password - it grants full control-plane access.
Install and run
Get the code
git clone https://github.com/rnihesh/headtower.git
cd headtower
pnpm installSet the environment
Headtower reads its configuration from the environment. Only two variables are required to start:
export HEADSCALE_URL="https://headscale.example.com"
export HEADSCALE_API_KEY="<your-headscale-api-key>"You can also drop these into a .env.local file at the project root.
Start the console
pnpm devOpen http://localhost:3000 . Headtower opens on the Machines readout - the core operational view.
You don’t have to set these at all. Start Headtower with no connection and it
opens a /setup wizard to enter and test the Headscale URL and API key in
the browser. Setting the env vars just skips that step. A value you do
provide is validated - a malformed HEADSCALE_URL is named rather than
silently ignored.
Run with Docker
For a long-running deployment, use Docker Compose - it wires the app, its persistent volume, and the optional agent together:
git clone https://github.com/rnihesh/headtower.git
cd headtower
cp .env.example .env # set HEADSCALE_URL + HEADSCALE_API_KEY at minimum
docker compose up -dOpen http://<your-host>:3000. The named volume (/app/data in the container)
keeps Headtower’s own state - operators, roles, audit log - across restarts.
See Configuration for the full set of variables, including
single sign-on and the agent.
The browser SSH terminal and device metadata come from an optional agent,
off by default. Enable it with docker compose --profile agent up -d after
setting HEADTOWER_AGENT_AUTHKEY and HEADTOWER_AGENT_LOGIN_SERVER in .env.
Headscale remains the source of truth for tailnet data. The Headtower volume only persists Headtower-specific state, so it is safe to recreate the container as long as the volume is preserved.
Next steps
- Skim the Concepts so the vocabulary lines up with Headscale.
- Walk the Features to see what each view does.
- Lock down access and sign-in in Configuration.