Manage CAP's own TLS certificate
CertAutoPilot ships with a self-signed certificate so the web UI is reachable over HTTPS on first boot (browsers will warn — that is expected). Once the platform is running you can have CertAutoPilot manage its own TLS: issue a real certificate for the controller's hostname, distribute it to the node(s) that serve the UI, and let the normal renewal machinery keep it fresh. No extra software and no product feature to enable — this is the ordinary SSH distribution flow pointed at CertAutoPilot's own hosts.
This works identically on a single host and a multi-node cluster — you simply list every node as a target.
Where the served certificate lives
On a standalone install, nginx terminates TLS and reads its certificate and key from:
/etc/certautopilot/tls/server.crt (root:root, mode 0644) — leaf + chain (fullchain)
/etc/certautopilot/tls/server.key (root:root, mode 0600) — private key
The backend itself listens as plain HTTP on 127.0.0.1; nginx is the only TLS terminator. Replacing these two files and reloading nginx swaps the served certificate without restarting the backend.
- Kubernetes / Helm: the served certificate is not on disk — it is the
<release>-tlsKubernetes Secret (typekubernetes.io/tls), consumed by both the backend and the frontend pods. Usecert-manager(the idiomatic K8s option) or the Kubernetes distribution module to write that Secret instead of the SSH recipe below. - Docker Compose: the shipped compose runs plain HTTP (dev only) — there is no TLS to manage.
Recipe (SSH distribution)
Prerequisites:
- A certificate whose SAN covers the controller's public hostname (e.g.
cap.example.com), issued from any CA you have configured, with auto-renew ON. - Root SSH access to every node (or a user with password-less
sudo). Writing to/etc/certautopilot/tls, settingroot:rootownership, and runningsystemctl reload nginxall require privilege. Key-based SSH asrootis the simplest. - For the first certificate you need a working ACME challenge path — HTTP-01 (port 80 reachable to the controller) or DNS-01. Until that first certificate is issued and distributed, the self-signed one stays in place.
Steps (all in Settings → Distribution):
-
Targets — add one SSH target per node (the two cluster IPs, e.g.
cap-aandcap-b), or add both to a target group. A node distributing to itself over SSH is fine — no special handling needed. -
Path set — map the certificate artifacts to the exact paths nginx reads. This is a PathSet; the important columns are source, path, owner, and mode:
fullchain /etc/certautopilot/tls/server.crt root:root 0644private_key /etc/certautopilot/tls/server.key root:root 0600Use
fullchain(leaf + intermediates) forserver.crtso clients get the full chain, andprivate_keyforserver.keyat mode0600. These match exactly what the installer's self-signed generator produced, so nginx needs no config change. -
Action set — reload nginx after the files are written. This is an ActionSet:
sudo nginx -tsudo systemctl reload nginxnginx -tfails fast on a bad config before the reload. By default the action runs only when a written file actually changed, so a no-op redistribute won't reload. -
Module config + link — create an SSH module config referencing the target(s)/group, then link a distribution on the certificate to it.
That is all. On every renewal CertAutoPilot re-distributes automatically (the finalize step marks the distribution pending and enqueues it), so each node receives the new certificate and reloads nginx with zero manual steps.
Cluster notes
- The distribution job is picked up by whichever node's worker is free and it SSHes out to every listed target, so all nodes get the certificate regardless of which node ran the job — including the node CertAutoPilot itself runs on.
- Because the source of truth is the issued certificate (stored once in the shared database) and each node is an explicit SSH target, adding a third node is just adding a third target — nothing else changes.
- Prefer a target group over individual targets so a new node joins by group membership and inherits the same path set / action set automatically.
Verifying
After the first distribution:
# On each node
openssl x509 -in /etc/certautopilot/tls/server.crt -noout -subject -enddate
# From a client
echo | openssl s_client -connect cap.example.com:443 -servername cap.example.com 2>/dev/null \
| openssl x509 -noout -issuer -enddate
The distribution's status in the UI shows per-target success; a failed reload marks that target failed (and, if auto-rollback is enabled, a rollback re-deploys the previous retained certificate version through the same paths).
See also
- SSH distribution module — path sets, action sets, rollback
- Standalone install — the initial TLS options
- Multi-VM cluster — load-balancer and per-host TLS models