Recently, I discovered an interesting project called Headscale. It promises to be an open-source, self-hostable version of Tailscale (a managed mesh networking solution like ZeroTier – more info here).
Each Tailscale network requires what is called a “Control server”, which handles authentication for its child network(s). This is one of the few components of the Tailscale stack that is not open source. Most users will simply use the proprietary “control server” that Tailscale itself provides. However, this comes with limitations like having to pay for the number of devices you connect and obvious security/privacy concerns with your networks being controlled by a third party. Headscale provides a control server that can be run on-premises and without any device limits.
The documentation for Headscale is sparse, but it looks to be a promising addition to what is already a very solid commercial project. So, I will document how to set up a Headscale control server.
On the control server
Complete some basic steps to get started with Headscale, like provisioning a server (preferably with a dedicated external IP address). Also make sure you have an available domain/subdomain pointed to your server’s IPs – we will use this later (I will refer to this as your-domain.com throughout this guide). This is outside of the scope of this guide. Note that I tested this guide on a Ubuntu 20.04 server.
After preparing your server, download the Headscale binary from here and place it into your $PATH (
/usr/local/bin works well on most Linux distros).
Create a folder
/etc/headscale and save
config.json.sqlite.example from the GitHub repo linked above as
config.json in that directory. (You can also use PostgreSQL with the corresponding config file, but I am just using a SQLite database). Also download
What to edit:
# It will automatically fetch a certificate from Let's Encrypt for your-domain.com server_url: https://your-domain.com:443 tls_letsencrypt_hostname: your-domain.com tls_letsencrypt_cache_dir: letsencrypt # by default this is a hidden folder, which could cause difficulty when trying to backup/restore listen_addr: 0.0.0.0:443
Leave everything else as default.
If you are a new Headscale user, use the WireGuard tools (can be installed as
wireguard-tools package) to generate a private key at
wg genkey > /etc/headscale/private.key chmod 077 /etc/headscale/private.key
Then run the following command to create a new namespace (equivalent to a user on Tailscale.com):
headscale namespaces create myfirstnamespace
Daemonizing & starting
Copy the following contents to
/etc/systemd/system/headscale.service to have SystemD keep the Headscale service running all the time:
[Unit] Description=headscale After=network.target [Service] WorkingDirectory=/etc/headscale ExecStart=/usr/local/bin/headscale serve # Disable debug mode Environment=GIN_MODE=release [Install] WantedBy=multi-user.target
Then execute the following commands to start and enable the service (start at boot):
systemd daemon-reload systemd enable --now headscale #Enable & start service
Now you should be able to visit https://your-domain.com/key and see the control server’s key!!
On your clients
Configuring clients is actually very simple. Simply download the appropriate client for your OS from tailscale.com and install it. Then, instead of logging in directly, execute the following command on your machine:
tailscale up --login-server https://your-domain.com
This makes the Tailscale client authenticate through your Headscale server rather than Tailscale’s SaaS control server.
Click on the link generated when you run the command and following the instructions presented. Your machine will be connected a few moments after you run the command! Try pinging another machine within the same namespace.
Note that Tailscale’s mobile clients do not support a custom login URL at the time of writing, and are therefore not compatible with Headscale!
Migrating control server
Sometimes you might need to migrate your Headscale control server to a new machine. Don’t worry, this guide covers that too.
Migration is actually quite simple. Simply zip up the contents of
/etc/headscale and transfer it to
/etc/headscale on your new server. Follow the above instructions to download the Headscale binary and install the systemd service. After starting the service, everything will work automagically!