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.envand 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.
One-command update (recommended)
On the managed server, as root:
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 \
shThe installer:
- Uses your license from
TURBOPANEL_LICENSE(built from/var/lib/turbopanel/license.id+license.tokenabove) - Reads your update channel from
TURBOPANEL_UPDATE_CHANNEL/--channelor/etc/turbopanel/daemon.env(defaulttrunk) - Reads your control plane URL and CA from
daemon.envwhen self-hosted (TURBOPANEL_INSTANCE_URL,TURBOPANEL_INSTANCE_CA, else/etc/turbopanel/instance-ca.pem) - Reinstalls the host-arch native binary + orchestration tree (and
turbopaneld.js+ vendored Deno only when the native binary cannot execute on that host) - 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.
curl -fsSL turbopanel.sh | \
TURBOPANEL_LICENSE="$LICENSE_B64" \
TURBOPANEL_HOST=https://<instance-host>:8443 \
shChange 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):
curl -fsSL turbopanel.sh | \
TURBOPANEL_LICENSE="$LICENSE_B64" \
TURBOPANEL_UPDATE_CHANNEL=trunk \
shIf the license file is missing
The refresh command reads:
| File | Purpose |
|---|---|
/var/lib/turbopanel/license.id | Organization license UUID |
/var/lib/turbopanel/license.token | Secret token (shown once at license creation) |
Check on the server:
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
sudo systemctl status turbopaneld
curl -sS https://turbopanel.app/api/daemon/v1/version # or your instance URLIn the UI, refresh the servers page — the node should show Online with a current commit on the update row.
Related
- Daemon setup — First-time install (
turbopanel.sh) - Deployment troubleshooting — TLS, Postgres, connectivity
Last updated on