TLS documentation is nonexistent and needs to clarify its for Headscale
Description
# /usr/local/bin/node --trace-warnings /var/lib/headplane/build/server/index.js
(node:1802294) ExperimentalWarning: SQLite is an experimental feature and might change at any time
at emitExperimentalWarning (node:internal/util:299:11)
at node:sqlite:8:1
at BuiltinModule.compileForInternalLoader (node:internal/bootstrap/realm:399:7)
at BuiltinModule.compileForPublicLoader (node:internal/bootstrap/realm:338:10)
at loadBuiltinModule (node:internal/modules/helpers:109:7)
at ModuleLoader.builtinStrategy (node:internal/modules/esm/translators:355:18)
at #translate (node:internal/modules/esm/loader:534:12)
at ModuleLoader.loadAndTranslate (node:internal/modules/esm/loader:581:27)
tough-cookie: can't load punycode; won't use punycode for domain normalization
2025-06-21T20:23:09.150Z [server] INFO: Running Node.js 22.16.0
2025-06-21T20:23:09.151Z [config] INFO: Found a valid configuration file at /etc/headplane/config.yaml
2025-06-21T20:23:09.164Z [config] INFO: Found a valid Headscale configuration file at /etc/headscale/config.yaml
2025-06-21T20:23:09.173Z [config] INFO: Using user database file at /var/lib/headplane/users.json
2025-06-21T20:23:09.174Z [config] INFO: Using certificate from /etc/headscale/certs/fullchain.pem
2025-06-21T20:23:09.235Z [config] INFO: Using https://accounts.google.com as the OIDC issuer
2025-06-21T20:23:09.237Z [server] INFO: Running on 0.0.0.0:3000
Looks like it uses the cert, now off to check it:
# openssl s_client -connect my-headplane-url:3000
CONNECTED(00000003)
40D79B462C7F0000:error:0A00010B:SSL routines:ssl3_get_record:wrong version number:../ssl/record/ssl3_record.c:354:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 5 bytes and written 316 bytes
Verification: OK
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
---
However it looks like it's not serving tls despite what I have in the config
server:
host: "0.0.0.0"
port: 3000
headscale:
tls_cert_path: "/etc/headscale/certs/fullchain.pem"
config_path: "/etc/headscale/config.yaml"
The same cert is used by headscale and works properly. I'm unsure how to approach it further
Headplane Version
v0.6.0
Headscale Version
v0.26.1
Managed to make it to work by omitting tls_cert_path, setting public_url that is accessible via rev_proxy. Headscale url is still on https
The TLS is for Headscale not Headplane. Headplane doesn't offer an option to serve via TLS and requires a reverse proxy. If this is something you are interested in, I can weigh in the options of adding it in.
The TLS is for Headscale not Headplane.
Didn't seem obvious to me especially since everything works perfectly without setting tls_cert_path if it's provided correctly in Headscale. Probably worth mentioning somewhere in the docs as it's a bit misleading imo
Yes you are right, the certificate is for if you are in an environment where the certificate you serve Headscale in isn't a default trusted certificate. For example, Headscale generates certificates, you could pass that in there.
I will improve the docs for this.