Skip to main content

Building Headscale from Source

· 4 min read
Larktun Contributor

This post is adapted from my personal blog and documents a practical workflow to build Headscale from source on Windows + WSL2 + Ubuntu, including common build errors and fixes.

Original post: Using Headscale Source Code to Build and Package

Context

  • OS: Windows 11 + WSL2 Ubuntu 24.04 LTS
  • Example version: Headscale v0.26.1
  • Repository: github.com/juanfont/headscale
  • Recommendation: clone with Git instead of downloading a source archive

Environment Setup

1) Clone the source

git clone https://github.com/juanfont/headscale.git

# Checkout v0.26.1
git checkout -b release-v0.26.1 v0.26.1

Then copy config-example.yaml to config.yaml in the project root.

2) Configure WSL

Create .wslconfig in your Windows user directory (for example, C:\Users\XXX):

[wsl2]
nestedVirtualization=true
ipv6=true

[experimental]
autoMemoryReclaim=gradual
networkingMode=mirrored
dnsTunneling=true
firewall=true
autoProxy=true

Restart WSL before continuing.

3) Install Nix (Multi-user)

sh <(curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install) --daemon

Reference: nixos.org/download

Build Flow

Run build steps as a regular user (do not run make build as root):

# Enter source directory
cd /mnt/c/Users/XXX/Documents/develop/0me/headscale

# Enter dev shell
nix develop

make generate
make test
make build

# Check build output
ls -la result/
cd result/bin
./headscale version

After a successful build, a result directory is generated.

headscale build result headscale build result on windows

Running the Binary

After copying the built binary to a target server, check dependencies first:

ldd headscale
file headscale

If your binary points to a Nix interpreter path, prepare the required path and linker file based on ldd output. Also verify that config.yaml, /root/.headscale/, and /var/lib/headscale/ exist with correct permissions.

Packaging as Docker Image

If you want to package the source-built binary into a Docker image, see: Headscale series: package source-built headscale as Docker image

Common Build Errors

Issue 1: dirtyShortRev missing

When make build fails with attribute 'dirtyShortRev' missing, add a fallback in flake.nix:

headscaleVersion = if self ? shortRev
then self.shortRev
else if self ? dirtyShortRev
then self.dirtyShortRev
else "v0.26.1";

Issue 2: missing config.yaml during test phase

If build fails in checks, prepare config and build binary directly:

cp config-example.yaml config.yaml
go mod tidy
go build -o headscale ./cmd/headscale

Issue 3: nix-command disabled

echo 'experimental-features = nix-command flakes' >> /etc/nix/nix.conf

Run the config command with root.

Issue 4: flake.nix not found

If nix develop reports no flake.nix, switch to the source directory first, then retry.

Issue 5: initdb cannot run as root

PostgreSQL init in tests cannot run as root. Use a regular user for the build and test flow.

Manual Dependencies

# Install Buf
go install github.com/bufbuild/buf/cmd/buf@v1.55.1

# Install Protobuf
sudo apt update
sudo apt install protobuf-compiler

This article is mirrored on the Larktun blog. For source updates and original context, refer to: Using Headscale Source Code to Build and Package