Files
57_Wolve 1ca79938cd feat(headscale): add headplane web UI at /admin
Integrate headplane (ghcr.io/tale/headplane) into the headscale stack, served
by Caddy at /admin. API-only (no Docker socket); deploy.sh mints a headscale
API key on first run, generates headplane.yaml, and wires optional OIDC login
via pocket-id (second client, /admin/oidc/callback). Adds HEADPLANE_* env,
compose service, Caddy routing; rebuild embedded archive.
2026-06-12 16:15:34 -05:00

83 lines
2.5 KiB
YAML

# headscale stack -- caddy (TLS) + headscale (Tailscale-compatible coordinator)
#
# Topology:
# Tailscale clients -> caddy:443 -> headscale:8080
#
# No Anubis here: Tailscale clients speak HTTP/2 control protocol, not HTML,
# so a PoW challenge would break them. Headscale's API surface is what
# clients hit; treat it like any other API service.
#
# OIDC login is delegated to pocket-id at $POCKETID_DOMAIN. Register a
# client there first; copy the client_id + client_secret into .env.
name: headscale
volumes:
headscale-data:
headplane-data:
caddy-data:
caddy-config:
services:
caddy:
image: caddy:${CADDY_TAG:-2-alpine}
container_name: caddy
restart: unless-stopped
ports:
- "80:80"
- "443:443"
# - "443:443/udp" # HTTP/3 -- disabled until Caddy QUIC + reverse_proxy
# placeholder bug is fixed (X-Real-IP comes through
# empty on some streams). Re-enable later.
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy-data:/data
- caddy-config:/config
environment:
HEADSCALE_DOMAIN: "${HEADSCALE_DOMAIN}"
ACME_EMAIL: "${ACME_EMAIL}"
depends_on:
headscale:
condition: service_healthy
healthcheck:
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:2019/config/"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
headscale:
image: headscale/headscale:${HEADSCALE_TAG:-0.28.0}
container_name: headscale
restart: unless-stopped
command: serve
read_only: true
tmpfs:
- /var/run/headscale
volumes:
- ./config.yaml:/etc/headscale/config.yaml:ro
- ./policy.hujson:/etc/headscale/policy.hujson:ro
- headscale-data:/var/lib/headscale
healthcheck:
test: ["CMD", "headscale", "health"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
# ---------------------------------------------------------------------------
# Headplane — web UI for headscale, served by Caddy at /admin. API-only:
# talks to the headscale API with a key (no Docker socket, no host control).
# config.yaml is generated by deploy.sh from .env.
# ---------------------------------------------------------------------------
headplane:
image: ghcr.io/tale/headplane:${HEADPLANE_TAG:-latest}
container_name: headplane
restart: unless-stopped
volumes:
- ./headplane.yaml:/etc/headplane/config.yaml:ro
- headplane-data:/var/lib/headplane
depends_on:
headscale:
condition: service_healthy