Daemon trust model
The TurboPanel daemon (turbopaneld) is a high-privilege service on every managed server. This page describes what it can do, what it sends upstream, and how to revoke access.
Enrollment
- Operator creates a one-shot license in the app.
- Installer runs
curl -fsSL turbopanel.sh | TURBOPANEL_LICENSE=… sh. - Daemon proves possession of a generated Ed25519 key via challenge/response (
turbopanel-daemon-enroll-v1). - Control plane attaches daemon identity to a
serverrow; license is consumed.
Re-enrollment requires the persisted serverId or a fresh license.
Connectivity
| Path | Detail |
|---|---|
| Transport | TLS + WebSocket /ws/daemon/v1 |
| Session | 15-minute daemon JWT (EdDSA), refreshed via auth challenge |
| Trust | Platform CA bundle on self-hosted (GET /api/daemon/v1/instance/ca → /etc/turbopanel/instance-ca.pem) or system roots (public TLS) — no skip-verify mode. Control-plane identity is the JWKS/Ed25519 JWT; the CA is a transport anchor only. |
| Presence | Heartbeats project timeSync, addresses, and online state to Postgres |
Co-located dev may dial a Unix socket when configured; servers always use WSS to the public URL.
Commands the daemon can run
Approved command types include deploy/stop, ping, hostname/reboot, timezone/NTP, TurboFabric reconcile, platform CA trust reconcile (server.tls.trust.reconcile), managed engine lifecycle, and orchestration playbooks invoked through Ansible.
Commands are queued in Postgres, dispatched over the cell, and correlated by commandId. The daemon executes only handlers registered in its command pipeline.
Files and privileges
| Area | Path / privilege |
|---|---|
| State | /var/lib/turbopanel (keys, license, wireguard material mode 0600) |
| Config | /etc/turbopanel/daemon.env, /etc/turbopanel/instance-ca.pem (platform CA bundle) |
| Logs | /var/log/turbopanel/daemon.log |
| Production user | tp:tp with passwordless sudo for Ansible |
| Orchestration | /opt/turbopanel/share/orchestration playbooks and roles |
WireGuard PSK files are deleted after apply; they never appear in Ansible extra-vars. The daemon owns TurboFabric apply directly (no Ansible round-trip).
Secrets
- License token on disk until enrollment completes
- WireGuard private keys under
/var/lib/turbopanel/network/wireguard/(mode0600) - No workload application secrets are stored in daemon state by default — compose injection comes from control plane at deploy time
Updates
Channel manifest from CDN or GitHub Releases → run.sh reconciles /opt/turbopanel and restarts turbopaneld.service. Install and update downloads use HTTPS; the channel manifest lists each artifact URL with a SHA-256 checksum, and the installer verifies the downloaded bytes against that hash before extraction. Every production manifest also carries an Ed25519 signature made with the release signing key. The installer, the daemon, and the control plane each verify it against one pinned public key and refuse a missing, malformed, or foreign signature; the daemon and the control plane also refuse a validly signed manifest that is older than the build they already know about. The key is a single trusted key today: see Signing key rotation for what changing it involves.
Data sent to the control plane
| Data | Purpose |
|---|---|
| Hostname, OS, addresses, time sync | Servers UI and automation |
| Host metrics samples | Charts and alerting (see server metrics) |
| Command results / logs (on demand) | Operator actions |
| Public daemon key fingerprint | Authentication |
Daemons do not upload arbitrary filesystem contents unless a specific command requests it (e.g. managed logs tail).
Revocation
- Delete or revoke the server in the org console.
- Remove
turbopaneldand state on the host (purge). - Rotate org secrets if you suspect key compromise.
Managed vs self-hosted
The daemon trust model is identical — only the control plane URL and TLS trust root differ: hosted edge TLS, or self-hosted Platform CA on :8443 with an uploaded or Let's Encrypt hostname using the system trust store instead. See Control plane listeners.
Platform CA rotation (self-hosted)
The control-plane-wide platform CA lives under /var/lib/turbopanel/tls/ (ca.crt, ca.key, ca-bundle.pem). It is not the per-organization TLS library (/api/client/v1/tls). Public-URL apply regenerates only the leaf; rotating the root requires an explicit TURBOPANEL_TLS_CA_ROTATE=1 on the generator.
Rotation procedure:
- Rotate — mint the new root while keeping the outgoing CA in
ca-bundle.pem(current first). The control plane still presents a leaf signed by a CA that existing daemons already trust. - Overlap — fan
server.tls.trust.reconcileto every connected server over the existing WSS session. Each daemon atomically writes/etc/turbopanel/instance-ca.pemand rebuilds its HTTP client from the bundle. - Confirm all daemons acked — wait until every connected server reports
{ applied, fingerprint }matching the new first-cert fingerprint. - Retire — drop the old CA from the bundle only after those acks. Do not retire first: a daemon still on the stale pin cannot fetch a replacement CA over the killed WSS session.
A daemon left on a stale anchor parks with a greppable tls-trust log (dialed host, CA path, local fingerprint). Recovery: re-run the installer with --instance-ca or --insecure-tls so run.sh can fetch the new bundle (pinned --cacert first; one guarded unpinned retry when the old pin is dead). See troubleshooting.
Organization CA rotation (managed-database / ProxySQL / replication leaves — not daemon → control-plane trust) follows the same order via the org TLS library. This is not the Platform CA above — see Organization CA for the full model. Mint a new active generation while the outgoing CA stays in the overlap trust bundle (POST /api/client/v1/tls/ca/rotate), distribute by fanning managed.apply and managed.ingress.reconcile, confirm those commands succeeded (GET /api/client/v1/tls/ca/rotation), then retire (POST /api/client/v1/tls/ca/retire) so the old generation leaves the bundle. Do not retire first.
Hosting is separate: tenant hosting leaves (Caddy-fronted web services) are operator-pinned library certificates, Caddy tls internal, or a Let's Encrypt row Caddy issues on the serving host (tlsMode: acme). They are never issued by the Organization CA. See Hostnames and TLS.
Related
-
Trust boundaries — what each part reaches if it is compromised
Last updated on