Home / Servers / HEADSCALE VPS

Run headscale on a VPS that never asked who you are

Headscale is the open-source implementation of the Tailscale control server. Put it on a machine bought with Monero and your mesh answers to a 32-character credential, not a Google account.

Deploy a headscale VPS from $9.99 / month / 4 GB RAM minimum

What the control server holds, and what it never touches

The distinction decides your threat model and your plan size.
Public keys, not packets01

Tailscale calls its coordination server a shared drop box for public keys. Headscale is that box, run by you.

Names, addresses, policy02

It does hold the map: node names, the addresses it assigns out of 100.64.0.0/10 and fd7a:115c:a1e0::/48, expiry, approved routes, the policy. Whoever holds the box knows the network's shape.

One SQLite file03

The default database is one SQLite file at /var/lib/headscale/db.sqlite, beside the noise and DERP private keys.

DERP relays are blind04

A relay forwards traffic already encrypted end to end with WireGuard and cannot read it. Blind is not free: relayed bytes cross your link twice.

One tailnet, on purpose05

The project aims at self-hosters and hobbyists and implements a narrow scope: a single tailnet, for personal use or a small open-source organisation. It is not associated with Tailscale Inc.

The host still owns the box06

Self-hosting moves trust from a SaaS account to a hosting account. On Blackbox that account holds no identity and the machine has no guest agent.

Quick start: headscale 0.29.3 on Debian 13

Run as root on a fresh server. Sources are in the comments; check the releases page for the current tag.
# headscale 0.29.3 (released 2026-07-29). Sources:
#   https://headscale.net/stable/setup/install/official/
#   https://headscale.net/stable/setup/requirements/
#   https://headscale.net/stable/ref/tls/
#   https://github.com/juanfont/headscale/blob/main/config-example.yaml
#   https://github.com/juanfont/headscale/releases
#   https://raw.githubusercontent.com/juanfont/headscale/v0.29.3/cmd/headscale/cli/preauthkeys.go

apt update && apt install -y curl ufw

# 1. Install the official .deb.
HEADSCALE_VERSION=0.29.3
ARCH=amd64
curl -fsSLo /tmp/headscale.deb \
  "https://github.com/juanfont/headscale/releases/download/v${HEADSCALE_VERSION}/headscale_${HEADSCALE_VERSION}_linux_${ARCH}.deb"
apt install -y /tmp/headscale.deb

# 2. Edit /etc/headscale/config.yaml. The shipped defaults are loopback only:
#      server_url:  http://127.0.0.1:8080
#      listen_addr: 127.0.0.1:8080
#    Set the public name your clients will dial and listen on 443 directly,
#    so no reverse proxy sits in the path. Per the example config,
#    dns.base_domain must differ from the server_url domain.
#
#      server_url: https://vpn.example.net
#      listen_addr: 0.0.0.0:443
#      tls_letsencrypt_hostname: vpn.example.net
#      tls_letsencrypt_challenge_type: TLS-ALPN-01
#      dns:
#        magic_dns: true
#        base_domain: mesh.example.net

# 3. Firewall. tcp/443 is the control channel; udp/3478 comes later and only
#    if you enable the embedded DERP relay in step 6.
ufw allow 22/tcp
ufw allow 443/tcp
ufw --force enable

# 4. Start it.
systemctl enable --now headscale
systemctl status headscale

# 5. Create a user, mint a key, join a node.
headscale users create alice
headscale users list
# preauthkeys --user is a uint64: pass the numeric ID from the list above,
# not the name. A name is rejected at flag-parse time.
headscale preauthkeys create --user 1
# Pre-auth keys are single-use and valid for one hour by default; see
#   https://headscale.net/stable/ref/registration/
# On the client (official Tailscale app, v1.80.0 or newer for headscale 0.29.3):
#   tailscale up --login-server https://vpn.example.net --authkey <KEY>
headscale nodes list

# 6. Optional: the embedded DERP relay, disabled by default. Fill in this
#    server's real public addresses. The standard line has no IPv6, so drop
#    the ipv6 line there; Blackbox has a routed /64.
#    https://headscale.net/stable/ref/derp/
#      derp:
#        server:
#          enabled: true
#          region_id: 999
#          region_code: "headscale"
#          region_name: "Headscale Embedded DERP"
#          stun_listen_addr: "0.0.0.0:3478"
#          ipv4: 203.0.113.10
#          ipv6: 2001:db8::10
#          verify_clients: true
ufw allow 3478/udp
systemctl restart headscale

Nodes, routes and an exit node

Commands as documented at headscale.net/stable/usage/getting-started/ and headscale.net/stable/ref/routes/.
01Register a node interactively

On the client: tailscale up --login-server https://vpn.example.net. It opens a browser page that prints an auth id, which you approve on the server with headscale auth register --user alice --auth-id <AUTH_ID>. Nothing joins until you approve it.

02Or hand out a pre-auth key

For machines with no browser: headscale users list to get the numeric user ID, then headscale preauthkeys create --user 1, then tailscale up --login-server https://vpn.example.net --authkey <KEY>. That flag takes the ID, not the name. Keys are single-use and valid one hour by default.

03Advertise a subnet

On the machine that fronts a LAN: sudo tailscale set --advertise-routes=10.0.0.0/8. Approve it with headscale nodes approve-routes --identifier 1 --routes 10.0.0.0/8, then sudo tailscale set --accept-routes on the clients. A subnet router needs IP forwarding.

04Turn the VPS into an exit node

Install the Tailscale client on the same server, join it to its own headscale, enable IP forwarding as you would for a subnet router, run sudo tailscale set --advertise-exit-node, then approve it with headscale nodes approve-routes --identifier 1 --routes 0.0.0.0/0.

05Back up the whole control plane

Copy /etc/headscale/config.yaml and /var/lib/headscale, which holds db.sqlite and the noise and DERP private keys. Restore it elsewhere, point DNS at it, and the nodes come back.

Sizing a headscale VPS, and the DERP question

Headscale is a control plane, not a tunnel. It is an open-source control server aimed at self-hosters and hobbyists that implements one tailnet, and the project is not associated with Tailscale Inc. Tailscale describes its coordination server as a shared drop box for public keys, and states that the private key never leaves its node, so only the two machines in a session can decrypt it. Everything else goes device to device, so sizing has one real variable: whether you also run the relay.

Control server only. The headscale requirements page asks for a reasonably modern Linux or BSD system, a public IP address and tcp/443, with tcp/80 needed only for the HTTP-01 certificate challenge. It sets no CPU, RAM or disk number. State is one SQLite file, /var/lib/headscale/db.sqlite by default, per the project's example configuration. Any plan on the pricing page clears that bar.

With the embedded relay. Headscale can run its own DERP server, and the DERP reference is honest about it: it wants udp/3478 for STUN on top of the HTTPS port, client verification is on by default, and "there are no speed or throughput optimisations, the main purpose is to assist in node connectivity". Relays are used when a direct connection is not possible and carry traffic that is already encrypted, so the operator sees ciphertext and volume. Volume is what costs: a few phones behind carrier NAT are noise, two sites copying backups through the relay are not. Blackbox ports are 10 Gbps unmetered.

What Servury does not offer. There is no DDoS protection on any line, which matters once udp/3478 faces the internet. There is no IPv6 on the standard line, while the headscale docs recommend a dual-stack host; Blackbox carries 1 IPv4 and a routed /64. Fleet-wide availability is 99.9%, with per-node uptime on the status page. If the control server goes down, existing devices keep talking until a node key expires, cached firewall rules stay enforced, and no new device can join.

Why not a hosted tailnet. Tailscale does not support sign-up with email addresses and is by design not an identity provider, so a hosted tailnet hangs off a Google, Microsoft, GitHub, Apple, Okta or OneLogin account. Self-hosting moves that binding to whoever sold you the server.

Which line to put it on. The noise key, the DERP key and the database are the identity of your tailnet, and they sit on this disk. On the standard line the panel can reset the root password, so treat it as a machine an operator could reach. On Blackbox there is no guest agent at all, memory is encrypted with AMD SEV-SNP (debug disabled in the launch policy), and LUKS2 is unlocked by you over SSH into the initramfs, so the passphrase never touches Servury. For the tunnel side, see WireGuard on a VPS and the self-hosted VPN page.

Why the control plane belongs on a host that asks nothing

The identity binding moves to the hosting account. Here there is no identity in it.

A 32-character credential is the account01

No email, no phone, no name, no ID, and no KYC at any amount. Nothing to correlate with the tailnet you are about to run.

Pay without a bank knowing02

Monero, Bitcoin, Litecoin, Ethereum, BNB, Tron, USDT and USDC on Servury's own nodes, not a third-party gateway. Cards via Stripe, or cash by mail.

No logs to subpoena03

No access logs anywhere, no analytics, no third-party scripts on public pages, and no session cookie until you log in or open a form. Support messages are deleted after 72 hours.

8 locations for the coordination point04

New York City, Montreal, London, Paris, Frankfurt, Eygelshoven, Singapore (currently sold out) and Hong Kong. Put it near the nodes that reconnect most.

Blackbox for the key material05

Montreal hardware Servury owns: AMD EPYC 7543, SEV-SNP encrypted memory, no guest agent, 10 Gbps unmetered, 1 IPv4 and a routed /64.

Terms from 7 to 365 days06

A week or a year. Blackbox billing is pure pro-rata; the standard line adds a 10% short-term fee under 31 days.

Your mesh, your control server.

Deploy in one of 8 locations, pay in Monero, never type an email address.

Deploy a headscale VPS

Fair questions

What does a headscale control server actually see?

Public keys and metadata, not traffic. Tailscale calls its coordination server a shared drop box for public keys, and a node's private key never leaves that node. Headscale holds the public keys, names, assigned addresses and the policy.

How big a VPS does headscale need?

Smaller than anything worth buying. The official requirements page names an operating system, a public IP address and a few ports, and sets no CPU, RAM or disk figure. Size matters only if you enable the embedded DERP relay.

Which ports have to be open?

TCP 443 for the clients. TCP 80 as well with the Let's Encrypt HTTP-01 challenge, which TLS-ALPN-01 avoids by answering on the same listen address. UDP 3478 for STUN, only with the embedded DERP server enabled. gRPC on 50443 is optional.

Should I turn on the embedded DERP server?

Only if your nodes actually fail to connect directly. It is disabled by default and the documentation is blunt: there are no speed or throughput optimisations, the purpose is to assist in node connectivity. It also cannot answer Tailscale's captive portal check on port 80.

Can I still use the official Tailscale apps?

Yes. A client points at a different control server with tailscale up --login-server https://your.host, and headscale 0.29.3 lists v1.80.0 as the minimum supported Tailscale client. Android, Apple and Windows need extra setup to accept a custom control server.

Do I get IPv6 for the control server?

On Blackbox in Montreal, yes: 1 IPv4 plus a routed /64. The standard line is IPv4 only. Headscale's requirements page recommends a dual-stack host, so put the control server on Blackbox if IPv6 matters to your mesh.

Can the same VPS be my exit node?

Yes. The node runs tailscale set --advertise-exit-node, you approve 0.0.0.0/0 with headscale nodes approve-routes, and clients select it with tailscale set --exit-node. That traffic leaves under the server IP, so the acceptable use terms apply. Running a node or a relay is fine; cryptocurrency mining is prohibited on every Servury machine.

Why buy the control server from an anonymous host?

Because the alternative is a name. Tailscale is by design not an identity provider, so a hosted tailnet hangs off a Google, Microsoft, GitHub, Apple, Okta or OneLogin account (https://tailscale.com/docs/integrations/identity). A Servury account is a 32-character credential, so the control server binds to nothing.

Guides on this

Related use cases