Headscale

Headscale is an open source, self-hosted implementation of the Tailscale control server.

It allows you to create your own private mesh VPN using the WireGuard protocol, providing secure connectivity between your devices without relying on a third-party service.


Note

For this guide you should be familiar with the basic concepts of

License

Headscale is released under the BSD-3-Clause License.

All relevant legal information can be found in the LICENSE file in the repository of the project.

Prerequisites

If you want to use Headscale with your own domain you need to add it first:

[isabell@stardust ~]$ uberspace web domain list
isabell.uber.space
[isabell@stardust ~]$

Installation

Download the latest Headscale binary from the official GitHub releases page. Replace 0.26.1 with the latest version:

[isabell@stardust ~]$ wget -O ~/bin/headscale \
  https://github.com/juanfont/headscale/releases/download/v0.26.1/headscale_0.26.1_linux_amd64
[isabell@stardust ~]$ chmod +x ~/bin/headscale

By default, Headscale loads the configuration from $HOME/.headscale/config.yaml, so we continue with creating the directory:

[isabell@stardust ~]$ mkdir -p ~/.headscale

Then download the example configuration file:

[isabell@stardust ~]$ wget -O ~/.headscale/config.yaml \
  https://github.com/juanfont/headscale/raw/v0.26.1/config-example.yaml

Configuration

Configure Headscale for Uberspace web backend

To run Headscale behind Uberspace’s native web backend (reverse proxy), you need to:

  • Set Headscale to listen on interface 0.0.0.0:8080 by setting listen_addr to 0.0.0.0:8080.

  • Disable TLS in Headscale (let Uberspace handle HTTPS) by setting tls_cert_path and tls_key_path to empty strings.

  • Set the correct server_url (your public domain, with https) by setting server_url to https://isabell.uber.space:443.

  • Set a encryption key for the Headscale connection by setting the private_key_path to private.key (will be generated after configuration).

Edit ~.headscale/config.yaml with your favourite editor and make the following adjustments:

Warning

Review and adjust the configuration to suit your environment. At minimum, set the server_url, private_key_path, and database.sqlite.

Note

TLS is handled by Uberspace’s web backend, do not set tls_cert_path or tls_key_path in your Headscale config. See Headscale’s TLS documentation for more information.

For a simple and minimal setup, set the following values:

server_url: "https://isabell.uber.space:443"
listen_addr: "0.0.0.0:8080"

tls_cert_path: ""
tls_key_path: ""

unix_socket: "headscale.sock"

noise:
  private_key_path: "noise_private.key"

database:
  type: "sqlite"

  sqlite:
    path: "db.sqlite"

Generate a private key (required for WireGuard):

[isabell@stardust ~]$ headscale generate private-key > ~/.headscale/private.key

Note

For further configuration options, see Headscale’s Configuration documentation.

To validate your configuration, run:

[isabell@stardust ~]$ headscale configtest

If you see no errors, you can continue with the next step.

Test daemon

Test the daemon by running headscale serve in a terminal.

If it’s not in state running without errors, check the shell output for errors.

Setup daemon

Create ~/etc/services.d/headscale.ini with the following content:

[program:headscale]
command=%(ENV_HOME)s/bin/headscale serve
directory=%(ENV_HOME)s/.headscale
stderr_logfile=%(ENV_HOME)s/logs/headscale.err.log
stdout_logfile=%(ENV_HOME)s/logs/headscale.out.log
autostart=true
autorestart=true
stopsignal=INT
startsecs=5

After creating the configuration, tell supervisord to refresh its configuration and start the service:

[isabell@stardust ~]$ supervisorctl reread
SERVICE: available
[isabell@stardust ~]$ supervisorctl update
SERVICE: added process group
[isabell@stardust ~]$ supervisorctl status
SERVICE                            RUNNING   pid 26020, uptime 0:03:14
[isabell@stardust ~]$

If it’s not in state RUNNING, check your configuration and the logs using supervisorctl maintail or tail -f ~/logs/headscale.out.log.

Configure Uberspace web backend

Now, connect the Uberspace web backend to your running Headscale instance (use the port configured in your configuration file, like 8080):

To make the application accessible from the outside, configure a web backend:

[isabell@stardust ~]$ uberspace web backend set / --http --port <port>
Set backend for / to port <port>; please make sure something is listening!
You can always check the status of your backend using "uberspace web backend list".
[isabell@stardust ~]$

Note

Uberspace’s web backend will handle HTTPS and proxy all requests (including WebSockets) to your Headscale service.

Usage

Once Headscale is running, you can begin managing users and nodes.

Create a user:

[isabell@stardust ~]$ headscale users create <USER>

Generate a preauth key for device registration:

[isabell@stardust ~]$ headscale preauthkeys create --user <USER>

Use the preauth key with the Tailscale client on your device:

[isabell@stardust ~]$ tailscale up --login-server https://isabell.uber.space --authkey <PREAUTHKEY>

For more commands, see headscale help or the official documentation.

Updates

Note

Check the releases page regularly to stay informed about the newest version.

To update Headscale, download the new binary and replace the old one. Then restart the service:

After creating the configuration, tell supervisord to refresh its configuration and start the service:

[isabell@stardust ~]$ supervisorctl reread
SERVICE: available
[isabell@stardust ~]$ supervisorctl update
SERVICE: added process group
[isabell@stardust ~]$ supervisorctl status
SERVICE                            RUNNING   pid 26020, uptime 0:03:14
[isabell@stardust ~]$

Tested with Headscale 0.26.1, Uberspace 7.16.7

Written by: Lukas Wolfsteiner <https://lukas.wolfsteiner.media>