3.1 KiB
TLS & Certificates
Everything Headplane does with TLS lives on this page: terminating HTTPS in-process, trusting private certificate authorities for outbound connections, and the interactions with cookies and the bundled Docker healthcheck.
Custom Certificate Authorities
If you front any of the services Headplane talks to — your Headscale server,
your OIDC provider, an HTTPS Docker daemon, etc. — with a private or
self-signed certificate authority, Headplane needs to trust that CA. The
cleanest way to do that is the standard Node.js NODE_EXTRA_CA_CERTS
environment variable, which is honoured for every outbound TLS
connection in the process (OIDC discovery, Headscale API, Docker, anything
else that uses fetch or https).
Provide it as a path to a PEM-encoded bundle of one or more CA certificates:
NODE_EXTRA_CA_CERTS=/etc/headplane/extra-cas.pem
In Docker, bind-mount the bundle and pass the variable through:
services:
headplane:
image: ghcr.io/tale/headplane:latest
environment:
NODE_EXTRA_CA_CERTS: /etc/headplane/extra-cas.pem
volumes:
- "./internal-ca.pem:/etc/headplane/extra-cas.pem:ro"
- "./config.yaml:/etc/headplane/config.yaml"
- "./headplane-data:/var/lib/headplane"
The bundle is added on top of the system trust store, so public certificates (Let's Encrypt, ZeroSSL, etc.) keep working.
headscale.tls_cert_pathis a narrower knob that pins Headscale's API connection to exactly one certificate, bypassing the rest of the trust store. It still has its place if you want Headplane to refuse anything other than that specific cert for Headscale, butNODE_EXTRA_CA_CERTSis the right tool whenever you simply want to add a CA to the trusted set.
TLS Termination
Headplane can terminate TLS itself when both server.tls_cert_path and
server.tls_key_path are set in the configuration file. Both must point to
PEM-encoded files that Headplane can read.
server:
port: 443
tls_cert_path: "/var/lib/headplane/tls/fullchain.pem"
tls_key_path: "/var/lib/headplane/tls/privkey.pem"
When TLS is configured Headplane serves HTTPS/1.1 on server.port. HTTP/2
and HTTP/3 are intentionally not supported in-process — terminate those at a
reverse proxy (e.g. Caddy or Traefik) and forward to Headplane over HTTP/1.1
if you need them today.
server.cookie_secure is forced to true whenever TLS is enabled (browsers
refuse Secure-less cookies over HTTPS); a warning is logged if your config
had it set to false.
For most deployments we still recommend terminating TLS at a reverse proxy (see Reverse Proxying) so you can share certificates with Headscale and other services. Built-in TLS is meant for the simpler "Headplane on a single box" scenarios.
Healthcheck
The bundled Docker healthcheck picks up the right scheme and port
automatically — Headplane writes its loopback URL to /tmp/headplane-listen
when it starts, and the healthcheck reads it from there. So flipping TLS on
or off requires no healthcheck-specific configuration; everything just
works.