Back to templates
Headscale icon

Deploy Headscale on Sealos

An open source, self-hosted implementation of the Tailscale control server with the Headplane web UI.

Tools
Deploy Headscale in a few clicks from the Sealos App Store.Run a self-hosted open-source service on Kubernetes-backed infrastructure.Get automatic HTTPS, routing, and resource management from Sealos.Avoid manual YAML while keeping control of the deployed workload.

Why deploy on Sealos

Sealos makes deploying any app effortless, secure, and production-ready. From one-click launch to ongoing operations, we handle the heavy lifting so you can focus on what matters.

One-Click Deploy
Sealos logo
Compute
Networking
Storage
Security
Observability
Your Application is Live

One-Click Deployment

Deploy any app template in seconds. No compose setup, manual configure, and go live.

Managed Kubernetes Reliability

Built on Sealos Managed Kubernetes for high availability, auto-scaling, and self-healing by default.

Automatic HTTPS & Security

Every deployment includes a secure domain with automatic SSL. We handle certificates and text protection for you.

Persistent Storage

Attach persistent volumes with ease. Your data stays safe, durable, and always accessible.

Scale when needed

Adjust resources as your app grows, no downtime required.

You Get the Whole Stack

Sealos provisions and connects every resource your application needs. Everything is ready to use.

One-click, fully provisionedSecure by defaultProduction ready

App Service

Your application is running and ready to serve requests.

Public HTTPS URL

Secure, global endpoint to access your application.

Database

Managed database instance for your application.

Persistent Volume

Durable storage for uploads and application data.

Environment Variables

Configuration and secrets injected securely into your app.

Logs & Metrics

Centralized logs and basic metrics are enabled.

README

README.md

Deploy and Host Headscale on Sealos

Headscale is an open source, self-hosted implementation of the Tailscale control server. This template deploys Headscale 0.29.2 with the Headplane 0.7.0 web UI, persistent storage, TLS-enabled public endpoints, and an optional KubeBlocks PostgreSQL database.

Headscale website

About Headscale

Headscale coordinates a private Tailscale-compatible network. It manages users, machines, routes, DNS, ACL policies, and device enrollment while compatible clients establish their data paths.

The template runs Headscale and Headplane together in one StatefulSet so Headplane can safely reload Headscale configuration through its Kubernetes integration. SQLite is the default database and matches the upstream recommendation for new deployments. The use_postgresql option provisions a dedicated PostgreSQL 16.4.0 cluster when your operating model requires an external database.

Common Use Cases

  • Run a private control plane for Tailscale-compatible clients.
  • Connect homelab, edge, and team devices across networks.
  • Manage users, routes, DNS, ACLs, and pre-auth keys from Headplane.
  • Keep control-plane state on persistent Sealos storage.
  • Use a managed PostgreSQL database for database-specific operational requirements.

Dependencies

The template includes the complete server-side runtime: Headscale, Headplane, persistent volumes, Service and Ingress resources, scoped Kubernetes RBAC, and the conditional PostgreSQL resources.

  • Headscale 0.29.2 provides the control server and APIs.
  • Headplane 0.7.0 provides the administration UI.
  • KubeBlocks provides PostgreSQL 16.4.0 when use_postgresql is enabled.
  • A compatible Tailscale client is required on each device joining the network.

Architecture

ComponentVersionPurposeMinimum tested limit
Headscale0.29.2-debugControl server, REST API, gRPC API, and metrics100m CPU / 128Mi memory
Headplane0.7.0Web administration UI100m CPU / 256Mi memory
SQLiteEmbeddedDefault Headscale database on persistent storageIncluded with Headscale
PostgreSQL16.4.0Optional KubeBlocks-managed database500m CPU / 512Mi memory
PostgreSQL initpostgres:16-alpineCreates and verifies the headscale database100m CPU / 128Mi memory

The application uses three 512Mi persistent volumes:

PathContents
/var/lib/headscaleSQLite database, keys, and Headscale runtime state
/etc/headscaleValidated, non-sensitive Headscale configuration
/var/lib/headplaneHeadplane state

The main public domain serves the Headscale HTTP API and Headplane at /admin/. A dedicated public domain exposes the Headscale gRPC endpoint. Metrics remain available only inside the cluster on port 9090.

Why Deploy Headscale on Sealos?

  • Deploy the complete Headscale and Headplane stack from one App Store template.
  • Receive HTTPS application and gRPC domains with managed TLS certificates.
  • Keep configuration, keys, and database state on persistent volumes.
  • Select embedded SQLite or a KubeBlocks-managed PostgreSQL database during deployment.
  • Inspect resources, logs, events, and container terminals from the Sealos Canvas.
  • Start with the tested minimum resources and adjust capacity as the tailnet grows.

Deploy on Sealos

  1. Open the Headscale template and click Deploy Now.
  2. Keep use_postgresql disabled for the default SQLite deployment. Enable it to provision the dedicated PostgreSQL cluster.
  3. Wait for all resources to become ready. SQLite usually starts in a few minutes. A new PostgreSQL cluster may take several minutes during its first initialization.
  4. Open the application URL. The root path redirects to the Headplane sign-in page at /admin/.

Sign In to Headplane

Headplane authenticates with a Headscale API key. Generate one from the Headscale container in the Sealos terminal:

headscale apikeys create

The command displays the key once. Store it securely and paste it into the API Key field on the Headplane sign-in page. Headscale gives a new key a 90-day lifetime by default. Set an explicit lifetime when needed:

headscale apikeys create --expiration 365d

After signing in:

  1. Open Users, select Add user, and create the first Headscale user.
  2. Open Settings > Auth Keys, select Create pre-auth key, choose the user, and set the desired lifetime and key options.

Connect a Device

Install a compatible Tailscale client, then use the main Sealos application URL and the pre-auth key created in Headplane:

tailscale up \
  --login-server=https://your-headscale-domain.example.com \
  --authkey=<pre-auth-key>

The device appears under Machines in Headplane after enrollment.

Remote Headscale CLI

The template exposes gRPC on a dedicated TLS domain. Use a headscale CLI binary matching server version 0.29.2, then configure the endpoint and API key:

export HEADSCALE_CLI_ADDRESS=your-headscale-grpc-domain.example.com:443
export HEADSCALE_CLI_API_KEY=<api-key>
headscale users list

The Headplane UI covers the common administration workflow, so remote gRPC access is optional.

Database Options

SQLite

SQLite is enabled by default and stores its database at /var/lib/headscale/db.sqlite. Write-ahead logging is enabled, and the persistent volume keeps state across Pod replacement.

PostgreSQL

Enable use_postgresql during deployment to create a KubeBlocks PostgreSQL cluster. The template creates the headscale database and waits for it to accept authenticated queries. Headscale receives the host, port, username, and password directly from the KubeBlocks Secret through its official HEADSCALE_DATABASE_POSTGRES_* environment variables.

The Kubernetes Secret remains the credential source, while /etc/headscale/config.yaml contains static, non-sensitive database settings. PostgreSQL adds a database Pod and a 1Gi data volume. The initialization Job allows up to six minutes for a cold database start.

Configuration

  • Use Headplane to manage users, machines, routes, DNS, ACL policies, and pre-auth keys.
  • Headscale reads /etc/headscale/config.yaml from persistent storage. The init container validates mode, placeholders, and the complete Headscale configuration before replacing an incomplete file with an atomic same-directory move.
  • Headplane reads /etc/headplane/config.yaml from the template ConfigMap.
  • Headplane receives its generated cookie secret through HEADPLANE_SERVER__COOKIE_SECRET, keeping the value out of the ConfigMap.
  • PostgreSQL credentials are injected directly into the Headscale container from the KubeBlocks connection Secret and stay out of persistent volumes.
  • shareProcessNamespace and scoped Pod-read RBAC let Headplane signal Headscale after supported configuration changes.
  • The Pod runs as UID/GID 1000 with RuntimeDefault seccomp and all Linux capabilities dropped.

Troubleshooting

Headplane rejects the API key

Create a fresh API key in the Headscale container and paste the complete value into the sign-in form. API keys are displayed once and expire according to their configured lifetime.

A client does not enroll

Confirm that --login-server uses the main HTTPS application URL and that the pre-auth key belongs to an existing user. Check the Machines and Auth Keys pages in Headplane.

PostgreSQL deployment is still initializing

Open the Sealos Canvas and inspect the PostgreSQL Cluster, the *-pg-init Job, and the Headscale StatefulSet. The application starts after the database accepts an authenticated query and the headscale database exists.

Health checks

Use these endpoints to verify the two application containers:

https://your-headscale-domain.example.com/health
https://your-headscale-domain.example.com/admin/healthz

Resources

License

Headscale is available under the BSD-3-Clause license. Headplane is available under the MIT license. This template follows the repository license for Sealos templates.

Related templates

Explore more production-ready templates.

More