Skip to content

v1.7.0 — Headscale control plane + resume.sh

Choose a tag to compare

@bogdandragosvasile bogdandragosvasile released this 21 Apr 07:58
· 5 commits to main since this release

Highlights

Free, self-hosted VPN mesh for the landing zone via Headscale (BSD-3) — point the official Tailscale mobile apps at http://headscale.local, mesh your phone with the cluster, demo mobile apps against backends running on your laptop. No Tailscale account, no paid tier, no phoning home.

Also ships scripts/resume.sh — fills the gap left by v1.5.1 where the Colima daemon-DNS pin only ran during fresh bootstrap, never on resume.

What's new

Added — Headscale app (app-of-apps pattern)

New Gitea repo platform/headscale carries everything the app needs; the only reference from gitops-infra is gitops-repo/apps/headscale.yaml:

  • ConfigMap'd config.yaml (embedded DERP STUN on UDP 3478, Magic DNS *.landingzone.local, SQLite persistence)
  • PVC for the DB + private keys
  • Deployment (headscale/headscale:0.26.1, ARM64-native) + Services (ClusterIP for API, LoadBalancer for DERP UDP) + Ingress at http://headscale.local
  • Helper scripts: scripts/create-user.sh, scripts/create-preauth.sh
  • README covering the registration flow for iOS / Android / laptop Tailscale clients, the subnet-router trick for reaching 172.20.0.0/24 from mobile, and the Cloudflare Tunnel path for cross-internet demos

Plus wiring in this repo:

  • gitops-repo/apps/headscale.yaml — the Application manifest
  • gitops-repo/manifests/argocd/values.yaml — new gitea-headscale repo credentials
  • scripts/setup-hosts.sh + scripts/04-create-k3d-cluster.shheadscale.local in the hosts + CoreDNS lists
  • Portal card under Your Applications

Added — scripts/resume.sh

Idempotent resume flow after a colima stop / ./teardown.sh cycle:

  1. Start Colima if not running.
  2. Merge dns: ["8.8.8.8", "1.1.1.1"] into /etc/docker/daemon.json (fills the v1.5.1 gap where already-bootstrapped clusters never got the pin).
  3. docker compose ... start the compose stack.
  4. k3d cluster start gitops-local, wait for nodes Ready.
  5. Re-patch each k3d node's /etc/resolv.conf (belt-and-braces — daemon.json catches new containers, node-level patch catches existing ones).
  6. Re-patch CoreDNS NodeHosts for gitea.local.
  7. Clear ghost Pending pods from the pre-stop state.

Using Headscale

After the app syncs:

# Create a user + pre-auth key (free unlimited)
bash scripts/create-user.sh alice
bash scripts/create-preauth.sh alice --reusable --expiry 168h

# On your phone: install the Tailscale app,
# → Settings → Change server → http://headscale.local
# → Sign in with auth key → paste the preauth key
# → Phone now has a 100.x.x.x Tailscale IP

To reach portal.local / gitea.local:3000 / etc. from the phone, register the laptop as a subnet router (see the app repo's README for the tailscale up --advertise-routes recipe).

For phones on cellular (outside your LAN), Headscale needs a public URL. Deploy Cloudflare Tunnel as a sibling Application — still 100% free for dev.

Upgrading an existing cluster

# If the cluster is stopped, use the new resume script:
./scripts/resume.sh

# Then pull + re-push gitops-infra to get Headscale wired in:
git pull
bash scripts/07-push-gitops-repo.sh

# Flush argocd-repo-server cache and let ArgoCD sync:
kubectl -n argocd rollout restart deploy argocd-repo-server

Full changelog

See CHANGELOG.md.