Installing headscale on OpenBSD
In this post I’ll detail the steps I took to install and configure headscale, an open-source self-hostable implementation of the Tailscale control server, on OpenBSD.
Code blocks prefixed with
# imply that the command should be run as a privileged user/root.
If you get stuck, it’ll be probably worthwhile to have a read of headscale’s documentation available in their GitHub repo: https://github.com/juanfont/headscale/tree/main/docs .
Since my server is on OpenBSD-stable, headscale is only available via
pkg_add on -current, I need to compile the headscale binary by hand and upload it to the server.
I’m doing this on an OpenBSD machine, so compiling and uploading it to the server
should be a breeze.
$ git clone email@example.com:juanfont/headscale.git $ cd headscale $ make generate $ make build $ sftp user@server <<EOF > put ./headscale > bye EOF
Then login, get root access, and copy the binary to
$ ssh user@server $ doas -s ... # cp ./headscale /usr/local/bin # chown root:bin /usr/local/bin/headscale
Next we need to setup:
_headscaledaemon user that headscale will run as.
- directories for headscale to store its sqlite database, private key, and socket (making sure they have the correct permissions/owner).
- copy the example config from GitHub, and edit it to our liking
First we setup some directories:
# mkdir -p /etc/headscale # touch /etc/headscale/config.yaml # mkdir -p /var/headscale
Then we add our
_headscale daemon user, and
chown all the necessary dirs.
Here we also run
doas to get us a shell as
_headscale so I can create the db.sqlite file. Note doing it this way requires some
# useradd -L daemon -s /sbin/nologin -d /var/headscale _headscale # chown -R _headscale:_headscale /var/headscale # doas -u _headscale /bin/ksh $ touch /var/headscale/db.sqlite
Finally we can edit the headscale config. I highly recommend copying the example config and using that as a starting point.
# vi /etc/headscale/config.yaml # # copy the example config # # change domain, IPs, ports # # change sock location to /var/headscale/headscale.sock
I’m currently using relayd(8) as a TLS proxy, so I don’t need to configure any TLS-related stuff.
headscale serve to see if the config works, and all the directories and permissions are correct:
# doas -u _headscale headscale serve ...
If all is well we can move onto setting up an init script for the headscale daemon.
I’ve made an init script to making stopping/starting and running at boot
a lot easier. Drop this simple script into
#!/bin/ksh # # /etc/rc.d/headscale daemon_user="_headscale" daemon="/usr/local/bin/headscale" daemon_flags="serve" . /etc/rc.d/rc.subr rc_cmd $1
chmod, enable and start it as usual:
# chmod +x /etc/rc.d/headscale # rcctl enable headscale # rcctl start headscale headscale(ok)
So here’s where you may run into some problems. Depending on the OS your client is going to be running on, it might be a little difficult to get Tailscale to use your custom control server. On Android, this editing the hardcoded Tailscale control server URL, and compiling the client from source.
It’s pretty easy to get the Tailscale client on OpenBSD to use your control server.
# pkg_add tailscale # rcctl enable tailscaled; rcctl start tailscaled # tailscale --login-server "https://headscale.example.com:443" ...
https://headscale.example.com:443 is your control server URL.
You can find the instructions for patching and building the custom APK here.
I didn’t bother even attempting to install the android sdk, ndk, and all the other required (garbage) on OpenBSD to compile the Android client. So I booted into Windows, then logged into Ubuntu on WSL, then had to install Go manually (since Ubuntu 20.04 packages are old AF and I can’t be bothered to move all the junk I’ve accumulated in my WSL distro’s $HOME). Then i installed the sdkmanager manually, then i installed the ndk through that manually, then I ran
Quite frankly this was painful, but it isn’t supposed to be. Wrangling with old documentation I found online about installing the android sdk on the outdated WSL Ubuntu setup I have set me back a few hours.
In the end it was quite rewarding to install the APK file, open it up and see it all working!