headscale_lht/README.md

111 lines
3.5 KiB
Markdown

# Headscale + Headplane + Traefik
This repository contains privacy-safe example files for running a self-hosted
Headscale control plane with the Headplane web UI behind Traefik and automatic
Let's Encrypt certificates.
Only `README.md`, `.gitignore`, and files ending in `.example` are published.
Real configuration, credentials, databases, generated keys, certificates,
backups, and container images are ignored by design.
## Architecture
- **Headscale** provides the Tailscale-compatible control plane and embedded DERP/STUN.
- **Headplane** provides the administration UI at `/admin`.
- **Traefik** terminates HTTPS and routes requests to Headscale or Headplane.
The example pins Headscale `v0.29.2`, Headplane `0.7.0`, and Traefik `v3.7.9`.
## Requirements
- A Linux server with Docker Engine and Docker Compose v2
- A public IPv4 address
- A domain such as `headscale.example.com` pointing to that address
- Inbound `80/tcp`, `443/tcp`, and `3478/udp` allowed by the firewall
## Prepare configuration
Clone the repository, then create the ignored runtime files from the examples:
```bash
cp docker-compose.yml.example docker-compose.yml
cp headscale/config/config.yaml.example headscale/config/config.yaml
cp headscale/config/acl.hujson.example headscale/config/acl.hujson
cp headplane/config/config.yaml.example headplane/config/config.yaml
cp traefik/traefik.yml.example traefik/traefik.yml
cp traefik/dynamic/headscale.yml.example traefik/dynamic/headscale.yml
mkdir -p headscale/data headscale/run headplane/data traefik/letsencrypt
touch traefik/letsencrypt/acme.json
chmod 600 traefik/letsencrypt/acme.json
```
Replace the example values in the copied files:
- `headscale.example.com`: the public control-plane domain
- `dns.example.com`: the MagicDNS base domain
- `203.0.113.10`: the server's public IPv4 address
- `admin@example.com`: the Let's Encrypt account email
- `REPLACE_WITH_OPENSSL_RAND_HEX_32`: output of `openssl rand -hex 32`
Do not put real credentials in a file ending in `.example`.
## Start and configure
Validate the Compose model, then start Headscale and Traefik first:
```bash
docker compose config --quiet
docker compose up -d headscale traefik
```
Create an API key for Headplane:
```bash
docker compose exec headscale headscale apikeys create --expiration 365d
```
Set the resulting key as `headscale.api_key` in the ignored
`headplane/config/config.yaml`, set a random cookie secret, and start Headplane:
```bash
docker compose up -d headplane
docker compose ps
```
Headscale is served at `https://headscale.example.com`; Headplane is served at
`https://headscale.example.com/admin`.
## Add a user and client
```bash
docker compose exec headscale headscale users create default
docker compose exec headscale headscale preauthkeys create \
--user default --reusable --expiration 24h
```
Join a client with the generated pre-auth key:
```bash
tailscale up \
--login-server https://headscale.example.com \
--auth-key YOUR_PREAUTH_KEY
```
## Optional OIDC
The Headscale and Headplane examples include commented OIDC sections. Copy and
uncomment them only in the ignored runtime configuration files. Keep the OIDC
client secret out of Git and use the same public issuer and client details in
both services.
## Operations
```bash
docker compose logs -f headscale headplane traefik
docker compose pull
docker compose up -d
```
Back up `headscale/data`, `headplane/data`, and `traefik/letsencrypt` securely.
These directories contain private state and are intentionally never published.