Administering the control plane
A handful of settings belong to the control plane rather than to any organization: how it is reached, how it sends mail, who may sign up, which providers can sign people in, and the encryption of what it stores. Those live in the Admin area (/admin/*), open to users with a control plane role. This chapter is the app side; the environment variables that back the same settings on a managed host are in Control plane configuration.
The model
Control plane roles
Every account carries a control plane role — user, admin or superadmin — that is separate from the organization grants in Organizations, teams and access:
| Role | What it means |
|---|---|
user | The default. Acts only through organization and team grants. |
admin | Opens the Admin area, and bypasses every organization check — an admin sees and may act on every organization on the control plane. |
superadmin | Everything admin can, plus the superadmin-only acts: Re-encrypt secrets and the tier catalogue. On self-hosted, the account created at install is the superadmin. |
Roles are not assigned from the app in this release; self-hosted has exactly the superadmin install created, and TurboPanel High Availability assigns roles operationally.
Where a setting comes from
Most Admin settings can be set in two places: the app, or an environment variable on the control plane. Environment wins. A key set by environment shows as Set by environment and is read-only in the app, so a host-managed value can never be changed from a browser. Secrets — SMTP password, provider client secrets, private keys — are write-only: the app reports that one is present and never shows it; leaving the field untouched keeps the stored value.
Before you begin
- An
adminorsuperadminaccount. Others are redirected to their dashboard. - Return to instance in the header takes you back to your preferred organization.
Access
Admin → Access. /admin opens here. /admin/networking redirects here. This is how people and machines reach this control plane. Organization TLS stays on the organization.
Hostnames
Admin → Access → Hostnames. Every address this control plane answers on, each with a certificate source:
| Source | What the name presents |
|---|---|
| Platform CA | The :8443 leaf. https://<host>:8443 stays bound even when no name uses this source. |
| Uploaded certificate | That hostname on :8443, with a pair from Certificates. |
| Let's Encrypt | That hostname on :8443, once the certificate is issued. Port 80 opens only while Let's Encrypt issues or renews — see Hostnames and TLS. |
Add a hostname. A scheme-less entry such as panel.lan (what TURBOPANEL_PUBLIC_URLS looks like) displays as https and is stored exactly as typed — it expands to port 8443 in an install command.
Pick the source. A new name starts on the Platform CA. A wildcard is an uploaded certificate. Let's Encrypt is refused for a loopback, private, or wildcard name.
Save stores the list. Save & Apply (self-hosted only) regenerates the Platform CA leaf for the Platform CA names and reloads the front proxy. The apply itself sends an empty body — the save already persisted the rows.
Apply drops the connection on purpose
Applying reloads the proxy your browser is talking through, so the request usually ends in a gateway error while the apply in fact succeeded. The app waits for the control plane to answer again and reports applied / reconnected; reload if in doubt — the list was saved before the apply was dispatched. On High Availability the button is absent (cert apply is not applicable on this runtime).
Per-hostname sources need a co-located daemon at 0.1.1 or newer. Older daemons keep the names visible and leave the sources disabled until that daemon is updated. The flat TURBOPANEL_PUBLIC_URLS list is the Platform CA names, kept in sync for certificate SANs, Git webhook callbacks, and the install command.
Certificates, trusted proxies, tunnel, Platform CA
| Page | What it sets |
|---|---|
| Certificates | Uploaded pairs (the private key is sent once and never shown again) and this control plane's Let's Encrypt settings: contact email, terms, directory URL, staging. These settings are for this control plane. An organization's Allow Let's Encrypt certificates is a different switch and applies only to that organization's hosting certificates. |
| Trusted proxies | The effective TURBOPANEL_TRUSTED_PROXY_CIDRS list, read-only. A custom list replaces the loopback default, so include loopback when Caddy is still on this host. |
| Tunnel | Write-only token for the co-located tunnel. An empty token tears the tunnel down. The stored token is never shown again. |
| Platform CA | Fingerprint, subject, validity, PEM download, and a trust reconcile for connected daemons. Self-hosted only. This is the Platform CA. |
Updates
Admin → Updates (/admin/updates). One platform upgrade for this control plane. The run installs a pinned build: the manifest and commit resolved when the run started, so a channel that moves mid-rollout does not change a later batch.
Order is fixed. Co-located daemon (this host), then Control plane (and the web app it serves, on that host), then every other server. The servers table stays waiting until both earlier steps are on the target build. A trunk channel has no control-plane package, so that step is skipped and only this host's daemon has to be on target first.
The status line is TurboPanel is up to date, Update available, Updating…, or Needs attention.
Update TurboPanel opens Ready to update TurboPanel?. Read the checks. The sheet says the control-plane database is backed up before the install. Copy the Recovery command (Copy command) before you continue.
Start update. Cancel leaves the run unstarted. A second start while one is pending or running is refused.
Watch Progress: Preparing → Downloading → Writing new files (still running the old version) → Restarting onto the new version → Checking the new version is running → Done, first for the Daemon step, then the Control plane step. The Web app step is the same step as the control plane's (the web app is installed together with it). The panel restarts on the control-plane step; the screen shows TurboPanel is updating until it answers again.
The servers list shows each other server. Retry on a row that failed or needs attention. A failed row does not hold the next batch.
Versions lists Control plane, Web app and Co-located daemon. Each shows Installed on disk and Running now separately, because until the restart the old version is still the one answering, and the newest build on the channel. An update that only changes the web app still lights Update available and the Update button. Under Progress, Server updates lists each other server (Server, Component, Status, Installed, Target, Step, Error); each server's daemon updates after the control plane is on target.
One update is one press of Update TurboPanel; the steps (daemon, control plane, then each server) are the parts of it. Only one update runs at a time: pressing it again while one is in progress is refused with Another update is already in progress (upgrade_run_active). The control-plane step is finished only when the daemon has checked the new version, not when the new version first answers, so a second update cannot start on top of one that could still be rolled back.
Automatic updates. Auto-update servers is off until you turn it on. Automatic runs start only when a newer build is published, no run is active, and — when Maintenance window is on — only inside that UTC window. Batch size is Percent (default 100) or Count, then Apply.
The first upgrade onto this release needs a co-located daemon that can take the backup. If pre-flight says it cannot, re-run the installer once, then come back here. See Upgrade and rollback.
The control plane is Managed by TurboPanel. There is no Update TurboPanel button and no Auto-update servers toggle. Connected daemons roll out in batches on their own.
Connected daemons filters All, Updating, Needs attention, and Up to date. Batch size is still Percent or Count, then Apply. Maintenance window limits when an automatic wave may start. Retry is on a row that needs it.
Per-server Update on a server's control panel stays hidden. The organization route answers updates_managed.
Admin → Email → Email settings. The control plane's outbound mail — sign-up verification, invitations, alerts.
| Field | Value |
|---|---|
| Provider | smtp or mailgun |
| From address | the sender every message carries |
| SMTP host / port / user / password | for smtp; the password is write-only |
| Mailgun API key / domain | for mailgun; the key is write-only |
Without a working provider, sign-up skips email verification and invitations are refused (email_unavailable) rather than created silently.
Sign-in providers
Admin → Sign-in providers. GitHub (an OAuth App's client ID and secret) and Google (an OAuth 2.0 client ID and secret). A configured provider appears on the sign-in screen and under each user's Linked accounts; an unconfigured one is absent. The redirect URI each provider needs is <public URL>/api/client/v1/auth/oauth/<provider>/callback. What the user sees is in Account security.
Git providers
Admin → Git providers. Instance-wide Git applications — GitHub Apps and GitLab OAuth applications every organization may use, shown read-only in their own Git sources beside the applications they register themselves. Several may coexist (github.com beside GitHub Enterprise, gitlab.com beside a self-managed GitLab). Create a GitHub App runs the manifest flow; Add manually takes existing credentials. The admin view hides Repository access, because an installation belongs to an organization. The rest of the surface is the same as an organization's, in Git sources and repositories.
Sign-up
Admin → Sign-up → Public sign-up. On, guests see Create account and /sign-up is open; off, only invited people and existing accounts get in (an invitation's sign-up still works — see Organizations, teams and access). When TURBOPANEL_IS_SIGNUP_ENABLED is set on the host, the toggle is locked: Sign-up is force-controlled by TURBOPANEL_IS_SIGNUP_ENABLED; clear that env var to use the app toggle (409).
Tiers
Admin → Tiers. High Availability only; superadmin only. The ladder (S1–S7, SX) is fixed in code; what a superadmin enters is which provider product each priced label sells through. Nothing seeds this.
Create one product per label, with a default monthly price, on the payment provider — see First-run tier catalogue for the exact shape.
For each row, Set up → pick the product from the dropdown (products whose metadata names the label are preselected; each shows an inline pass/fail) → save. The row's price is cached from the product; changing a price is done on the provider, never here.
Verify / Verify all re-run the checks: product and price active, a default price, monthly, per-unit, USD, and a resolvable tax behaviour (the price names it, or the provider account has a default). A failing product cannot be saved or sold.
Retire deactivates a row (rows are never deleted); Reactivate brings it back. SX has no product and is never purchasable; a negotiated deal binds that customer's product to it.
Secrets
Admin → Secrets → At-rest encryption. Superadmin only. Every secret the control plane stores — secret variables, TLS private keys, system user passwords, provider secrets — is sealed under the current data-encryption key. After rotating the root secret (TURBOPANEL_SECRETS, Security), Re-encrypt secrets re-seals everything onto the new key version in bounded batches; Resume sweep continues one that stopped. A second sweep while one runs is refused (reencrypt_in_progress). Only after a sweep completes may the old key be dropped from the keyring.
Server metrics
Admin → Server metrics → Live metrics sessions. How long one live metrics session on a server's Metrics tab may stream before it must be reopened: Max session length (minutes) — 0 turns live sessions off, otherwise 5–240. Save session length.
Also in the control plane API
Two settings have no screen yet and are set through /api/admin/v1:
- Control plane notification channels —
GET/POST/PATCH/DELETE /notification-channels[/:id]: the operator's own receivers, which hear every event on the control plane (same shapes as a person's channels; an email address must be an administrator's). The olderPUT /settings/alert-webhook{ url }(ornull) still works (Troubleshooting): it edits the control plane channel called Operator alert webhook, which a control plane configured before the notifications system existed is folded into automatically. It may point at a LAN address. See Notifications. - Daemon diagnostics —
GET /daemon/connections,/daemon/commands,/daemon/addresses: what every connected daemon reports, for support.
The interactive reference is at /api/admin/v1/reference.
Reference
| Item | Value |
|---|---|
| Roles | user · admin · superadmin |
| Admin-only areas | Access, Updates, Email, Sign-in providers, Git providers, Sign-up, Server metrics |
| Superadmin-only | Tiers, Secrets |
| Precedence | environment variable > panel setting |
| Public URL entry | scheme + host + optional port; scheme-less entries expand to port 8443 in install commands. Each hostname has a source: Platform CA, uploaded, or Let's Encrypt. |
| Live metrics session | 0 (off) or 5–240 minutes |
| Sign-up override | TURBOPANEL_IS_SIGNUP_ENABLED locks the toggle |
| Upgrade order (self-hosted) | co-located daemon → control plane → other servers; servers wait until the first two are on target |
| Upgrade batch | Percent 1–100 (default 100) or Count 1–10000 |
| Upgrade run statuses | pending · running · succeeded · partially_failed · failed · cancelled |
| Upgrade step statuses | pending · waiting · dispatched · preparing · downloading · installing · restarting · verifying · done · failed · rolled_back · needs_attention · skipped |
| Successful step retention | TURBOPANEL_UPGRADE_STEP_RETENTION_DAYS, default 14 days; failed steps 90 days; runs 365 days (newest 50 kept) |
Errors
| Message | Status | Meaning |
|---|---|---|
Forbidden | 403 | The account is not an admin or superadmin (or, on Tiers and Secrets, not a superadmin). |
One or more public URL entries are invalid | 400 | An entry is not a valid scheme + host + port. |
One or more hostnames are invalid | 422 | A hostname, its source, or its uploaded certificate failed validation. The body names the rows. |
Let's Encrypt cannot issue a certificate for a loopback or private hostname | 422 | That name stays on the Platform CA or an uploaded pair. |
Let's Encrypt cannot issue a certificate for a wildcard hostname | 422 | A wildcard is an uploaded certificate. The stock Caddy build speaks HTTP-01 only. |
no co-located daemon connected to apply public URLs | 503 | Apply needs the control plane's own daemon connected. |
cert apply is not applicable on this runtime | 422 | Apply is self-hosted only. |
Sign-up is force-controlled by TURBOPANEL_IS_SIGNUP_ENABLED… | 409 | Clear the variable to use the toggle. |
maxMinutes must be 0 or an integer between 5 and 240 | 400 | Live session length out of range. |
reencrypt_in_progress | 409 | A sweep is already running; wait or Resume sweep. |
Encryption unavailable — no encryption key configured | 503 | The control plane has no root secret, so nothing can be sealed. |
tier_invalid | 400 | The tier row or its product patch failed validation; message names the field. |
| Provider product verification failures | 400 | The product does not meet the checks listed under Tiers; the response lists them. |
control_plane_upgrade_required | 409 | Self-hosted POST /servers/:id/update and POST /servers/updates while the server-update gate is shut. The server badge reads Waiting for the control plane upgrade. Finish Admin → Updates first. |
upgrade_run_active | 409 | An update is already pending or running. Wait for it to finish or Cancel update. |
updates_managed | 409 | The same routes on TurboPanel High Availability. Per-server Update stays hidden; the rollout is Admin → Updates. |
preflight_disk | step error | Not enough free space, or the free-space check failed. Daemon: 512 MiB on the install root, 128 MiB on state, 256 MiB on temp. Control plane: 1 GiB on the install root and 1 GiB on the backup directory. |
preflight_manifest | step error | The pinned manifest could not be fetched or verified, or it does not match the target commit. |
preflight_trust | step error | Automatic-update TLS is not public trust and not the Platform CA. |
preflight_backup | step error | turbopanel-database is not running, so the control-plane dump was not taken. |
preflight_in_progress | step error | Another install is already running on that host. |
health_timeout · health_mismatch · restart_failed | step error | The new control plane did not pass GET /api/health. The previous generation was restored (rolled_back). |
recovery_required | step error | Automatic rollback did not restore the control plane. Use the Recovery command. |
step_timeout | step error | No progress for 15 minutes. After 3 dispatches the step is needs_attention. |
rolled_back | step error | The host restored its previous build. One automatic retry, then needs_attention. |
verify_timeout | step error | The control-plane step restarted, and the daemon did not confirm the new build within TURBOPANEL_UPGRADE_VERIFY_TIMEOUT_MINUTES (20 by default). The step is not retried, so a second install cannot land on a build still being checked; the run ends. Check the daemon log, then Retry or Cancel update. |
dispatch_failed | step error | The update command could not be delivered to the server, on every allowed attempt. The message carries the delivery error. |
server_offline | step error | The server stayed offline too long for its step to wait; the next batch still starts. |
managed_upgrade_required | step error | The control-plane step needs a daemon that advertises managed-upgrade-v1; the message holds the daemon-only update command to run first. |
downgrade_refused | step skipped | The server already runs a newer build than the target. Managed updates never downgrade a server. |
control-plane update is not applicable on this runtime | 422 | The legacy POST /instance/updates/instance on TurboPanel High Availability. The control plane is deploy-managed. |
This control plane follows <channel>, which has no control-plane package… | 422 | trunk (and edge) have no control-plane package. Use canary, rc, or release. |
no co-located daemon connected to update the control plane | 503 | The legacy control plane or daemon upgrade route needs this host's daemon connected. |
co-located daemon disconnected | 503 | The daemon dropped while that legacy route was dispatching. |
Related
- Control plane configuration — the environment variables behind these settings.
- First-run tier catalogue — the products to create before binding tiers.
- Security — secret rotation and the egress boundary.
- Organizations, teams and access — organization-level roles.
- Upgrade and rollback — backups, the recovery command, and the first installer re-run.
- Deployment troubleshooting —
needs_attentionand restoring a backup.
Last updated on
Billing and licenses
On TurboPanel High Availability — what a license is, buying the first ones, adding and releasing licenses at a tier, moving a license up or down the ladder, servers that are not covered, past-due payment, invoices and the customer portal, and every refusal
Error codes
Every stable error code the client API returns, by area — the HTTP status it comes with, what it means, and what to do