Setting Up Headscale with Headplane UI and OIDC
Utku Toraman
·
2 minute read
Tailscale is incredible, but sometimes you want full control over your data, your network, and your limits. Enter Headscale: the open-source implementation of the Tailscale coordination server.
While Headscale is powerful, it is CLI-first. To make it user-friendly, we will pair it with Headplane, a modern web UI. We will wrap the UI in Nginx for SSL and configure Google OIDC so you can log in with your existing credentials.
Prerequisites
- A Linux server with Docker and Docker Compose installed.
- A domain name (e.g., vpn.example.com).
- SSL Certificates for your domain (fullchain and private key) placed in a _certs directory.
- Google Cloud Console access (to generate OIDC credentials).
________________________________
Part 1: The Directory Structure
To keep things clean, create a folder for your stack. We will map volumes relative to this folder.
Make sure your SSL certificates (fullchain.pem and privkey.pem) are located inside _certs/.
Part 2: Configuration Files
1. Headscale Configuration
Create _config/config.yaml. Crucial Note: We are running Headscale on port 28011. This is where your VPN clients (Windows, Mac, etc.) will connect. The Web UI will live on standard port 443.
2. Headplane (UI) Configuration
Create _headplane_config/config.yaml. This controls the Web Dashboard.
3. Nginx Configuration
Create _nginx/nginx.conf. This handles the web traffic for the UI.
4. Docker Compose
Create docker-compose.yaml.
Part 3: Initialization
- Start the containers:
docker compose up -d
- Generate an API Key for Headplane: Headplane needs a key to communicate with Headscale. Run this command:
docker exec headscale headscale apikeys create --expiration 90d
- Update Config: Copy the key output from the previous step. Open _headplane_config/config.yaml and paste it into headscale_api_key: "PASTE_HERE".
- Restart Headplane:
docker compose restart headplane
You can now visit https://vpn.example.com and log in via Google OIDC!
Part 4: Connecting Clients
Here is the critical part. Standard Tailscale clients try to talk to tailscale.com. We need to point them to https://vpn.example.com:28011.
🍎 macOS
- Install the official Tailscale Standalone client (avoid the Mac App Store version if possible, as the standalone version is easier to configure via CLI).
- Open your terminal.
- Tell Tailscale to use your server:
defaults write io.tailscale.ipn.macOS ControlURL https://vpn.example.com:28011
- Restart the Tailscale application.
- Click Log in. It should open a browser window directed to your Headscale OIDC page.
🪟 Windows
- Install the official Tailscale client.
- Open PowerShell as Administrator.
- Run the login command with the login-server flag:
tailscale login --login-server https://vpn.example.com:28011
- A browser window will open for you to authenticate with Google.
🐧 Linux
- Install Tailscale (curl -fsSL https://tailscale.com/install.sh | sh).
- Run the up command defining your server:
sudo tailscale up --login-server https://vpn.example.com:28011
- Follow the URL printed in the console to authenticate.