TurboPanel Docs
Deployment

Refresh a stuck daemon

Sometimes a managed server looks offline in the UI even though the daemon is still running, or the Update button fails because the node is on an old build. Re-run the same run.sh installer used for first-time setup — it reads license state from disk and reconciles the FHS tree in place.

When to use this

Use a manual run.sh refresh when:

  • The server badge shows Offline but the daemon service is running (systemctl status turbopaneld)
  • The Update button in the UI errors or does nothing
  • You changed update channel in /etc/turbopanel/daemon.env and want to pull from the new channel immediately
  • You want to reconcile after a bad upgrade (daemon disabled, wrong version, etc.)

Co-located dev hosts

This page covers managed servers (FHS tree). If your control-plane host was provisioned with the dev console, update it from the console (Sync Dev Build / Upgrade System) instead — that host runs the daemon from a source checkout, not /opt/turbopanel/bin.

UI vs cell panel

The server list reads a Postgres projection for online/offline. The Cell panel reads live WebSocket state. If those disagree, the daemon is usually fine — run an update to refresh both the installed binary and presence.

On the managed server, as root:

Terminal
LICENSE_B64=$(python3 -c "
import base64
id = open('/var/lib/turbopanel/license.id').read().strip()
tok = open('/var/lib/turbopanel/license.token').read().strip()
print(base64.urlsafe_b64encode(f'{id}:{tok}'.encode()).decode().rstrip('='))
")

curl -fsSL turbopanel.sh | \
  TURBOPANEL_LICENSE="$LICENSE_B64" \
  TURBOPANEL_UPDATE_CHANNEL=trunk \
  sh

The installer:

  1. Uses your license from TURBOPANEL_LICENSE (built from /var/lib/turbopanel/license.id + license.token above)
  2. Reads your update channel from TURBOPANEL_UPDATE_CHANNEL / --channel or /etc/turbopanel/daemon.env (default trunk)
  3. Reads your control plane URL and CA from daemon.env when self-hosted (TURBOPANEL_INSTANCE_URL, TURBOPANEL_INSTANCE_CA, else /etc/turbopanel/instance-ca.pem)
  4. Reinstalls the host-arch native binary + orchestration tree (and turbopaneld.js + vendored Deno only when the native binary cannot execute on that host)
  5. Re-runs Ansible and restarts turbopaneld.service

Run as root

Pipe the installer to sh as root (su - or sudo sh). A non-root pipe will hang or fail when provisioning needs elevated privileges.

Self-hosted control plane

Add TURBOPANEL_HOST when the instance is not production Cloudflare. Use :8443 by default; omit the port (or use :443) when turbopanel_tls_mode=lets_encrypt. Public TLS omits --insecure-tls / TURBOPANEL_INSECURE_TLS.

Terminal
curl -fsSL turbopanel.sh | \
  TURBOPANEL_LICENSE="$LICENSE_B64" \
  TURBOPANEL_HOST=https://<instance-host>:8443 \
  sh

Change update channel

Set TURBOPANEL_UPDATE_CHANNEL on the same command. Channel names (trunk, canary, rc, release, …) are technical identifiers — not product branding. The example below stays on trunk (the default):

Terminal
curl -fsSL turbopanel.sh | \
  TURBOPANEL_LICENSE="$LICENSE_B64" \
  TURBOPANEL_UPDATE_CHANNEL=trunk \
  sh

If the license file is missing

The refresh command reads:

FilePurpose
/var/lib/turbopanel/license.idOrganization license UUID
/var/lib/turbopanel/license.tokenSecret token (shown once at license creation)

Check on the server:

Terminal
sudo ls -la /var/lib/turbopanel/

If those files are missing, create a new license in the TurboPanel UI (Servers → Licenses), copy the install command immediately, and run it on the server.

Verify after update

Terminal
sudo systemctl status turbopaneld
curl -sS https://turbopanel.app/api/daemon/v1/version   # or your instance URL

In the UI, refresh the servers page — the node should show Online with a current commit on the update row.

Edit on GitHub

Last updated on

On this page