ConduitDocs

CLI

cli/conduit is the command-line client for the panel — a thin layer over the same HTTP API the dashboard uses, plus the console proxy for live terminals. Zero dependencies, plain Node ≥ 20 (the live console wants ≥ 22 for the native WebSocket). Nothing here talks to the cluster directly; if the panel can't do it, the CLI can't either.

Setup#

alias conduit="node ~/Coding/conduit/cli/conduit"   # or symlink it into your PATH

conduit context add production --url http://<panel>:3001
conduit auth login          # shows a code → approve it in the panel at /approve
conduit status

Sign-in is browser-approved: auth login shows a short code, you approve it on the panel's /approve page while signed in there (passkey/TOTP protected), and the CLI receives a personal token — no password ever touches a terminal. Tokens land in ~/.config/conduit/config.json (mode 600), one per context — conduit context add staging --url … and --context staging (or context use) switch clusters, kubectl-style. A token minted in the panel UI works too: conduit auth token cu_….

Commands#

CommandWhat it does
statusnodes, containers, memory, players online
groups / tasks / instancesfleet state — list, inspect, scale, software updates (tasks update --rolling), motd, resync, lifecycle actions (instances restart-mc 204)
blueprintsdeployable templates, named by software (+ Purpur/Folia/CanvasMC flavor), category, and the default role; blueprints get <id>. A server's actual role is a separate, editable task property (proxy/lobby/smp/game/hub/web/db/generic).
deploy <blueprint>create a server from a blueprint (the /deploy wizard on the CLI): --group, --mode, --min/--desired/--max, --node-group|--node, --version, resource flags
nodescluster nodes — status, Conduit-container count, CPU/memory load
node-groupsnamed node sets for placement — list, create <label> --nodes a,b, delete <id>
playersroster, Player 360 lookup, ban/mute (+undo), kick
console <vmid>live terminal on any instance over the console proxy — input, colors, reconnect-free attach; --send "cmd" for one-shots
logsconsole scrollback (--follow tails over SSE), action log, player audit, operator audit
alertsalert feed, incidents, channel test fire
backupssnapshot list, on-demand backup, guarded restore
maintenancedowntime windows — list, schedule (--start +30m), cancel
plugins / packsmanaged plugin + resource pack inventory
doctorpath diagnostics from your machine: panel, auth, console proxy, every agent — with fixes
shellinteractive console — history, tab completion, same commands
completion bash|zshshell completion

conduit help <command> prints usage. Automation flags work everywhere: --json (raw API output), --yes (skip confirmations), --quiet, --context <name>. Mutations that can hurt (restarts, restores, bans, broadcasts) always confirm unless --yes.

Console#

conduit console 204                 # attach; Ctrl+C detaches
conduit console 204 --send "list"   # one-shot
conduit console 206 --sock redis    # per-kind consoles: mc, redis, postgres, mysql, web…

The CLI attaches through the same per-replica console proxy (:8801) the web terminal uses; the agent token never leaves the panel. When several nodes exist it probes which agent actually serves the vmid — pin with --agent <node-ip> to skip the probe.

Doctor#

conduit doctor checks the path from your machine: panel HTTP, token validity, console proxy, every agent's :8800. It knows the difference between a dead service and a dead path — a VIP that answers in-cluster but not from your workstation is reported as a route/VPN issue, with the replica-address workaround, instead of a false outage.

SSH gateway — the resident console#

The console also lives ON the panel CTs, behind a dedicated gateway sshd (default port 2202, network.sshGateway.port; expose it publicly with a router/firewall DNAT to the VIP). It is not remote shell access — every connection lands in the Conduit console and nowhere else:

ssh -p 2202 conduit@<panel-vip>
  • Registered key (added on /account, or trusted earlier): straight into the console as your panel user, on a 12-hour session token ("ssh session" under your API tokens). Key checks are live — revoking on /account takes effect on the next connection, no sync delay.
  • Any other key: the username sign-in — two factors. Enter your panel name and password (factor one, verified before anything else happens — a wrong password creates no request at all, and it's hard rate-limited). Then the second factor: either approve in the browser on /approve while signed into the panel, or type your authenticator code right in the terminal (TOTP accounts). After signing in, the gateway offers to trust the key so the next connection is direct.
  • No key at all (a phone, a locked-down client): the same username + password sign-in, reached over keyboard-interactive instead of a key — a key is only a shortcut past the password + second factor, never a way around them.
  • Approving is deliberate: the approval prompt (the /approve page and the live popup) shows you who is connecting — source IP, country, key fingerprint — but never the code. To approve you type the code from your own terminal, so a sign-in you didn't start can't be one-click-approved (denying it is one click). And never a system shell: however you arrive you land in the Conduit console and nowhere else — the gateway restricts the session (no forwarding, no sftp), runs its own host keys on its own port, and the account it uses is denied outright on the system sshd at :22.

SSH over 443 — for networks that reset the SSH port#

Some networks (hotel/corporate/mobile DPI) reset connections to a non-standard SSH port. Turn on SSH over 443 in the gateway card (Domains → SSH · CLI gateway; needs a hostname set) and the gateway also answers on :443, right beside the panel web. An nginx stream ssl_preread split reads the first bytes of each :443 connection and routes it: a TLS handshake with a panel hostname's SNI → the web; the gateway hostname's SNI → the sshd; and anything that isn't TLS at all → the sshd too. So :443 carries the panel, raw SSH, and TLS-wrapped SSH at once, and a port-based reset can't tell your SSH from HTTPS.

ssh -p 443 conduit@cli.example.com          # any SSH client, nothing to install

# if the port itself is inspected, wrap SSH in real TLS so it's indistinguishable from https:
ssh -o ProxyCommand='openssl s_client -quiet -verify_quiet -connect %h:443 -servername %h 2>/dev/null' conduit@cli.example.com
# socat works too: ProxyCommand='socat - OPENSSL:%h:443,verify=0,snihost=%h'

The wrap uses TLS purely as camouflage — verification is off because the origin serves a Cloudflare Origin cert (trusted by CF, not publicly), and SSH's own host key is what actually secures the session inside. The gateway hostname is a DNS-only record straight to the origin (SSH can't ride the orange-cloud proxy), so :443 there reaches the sshd, not CF.

Admins on a gateway session have one escape hatch inside the console: system shell, role-checked against the panel and confirmed before it opens. Everyone else operates through the console commands — that's the point.

The console#

conduit shell (what a gateway session lands in) is the CloudNet-school console. On a roomy terminal it's a split: a pinned header with your identity and live fleet counts, a LOG PANE up top that scrolls on its own (command output and alert events land there), and a fixed command line at the bottom with a live tab-completion menu — so typing never flickers the log and a streaming line never disturbs what you're typing. Short terminals fall back to a sticky inline prompt. screen <vmid> (alias of console) attaches a real server console and detaches back with Ctrl+C; top runs the full-screen live view and hands the prompt back; clear wipes the log; exit leaves (and releases the terminal so a gateway session actually closes).

Live view#

conduit top (also watch/monitor) is the k9s-style glance: nodes with cpu, fleet totals, players, and every instance with state/players/tps, refreshing on an interval. q leaves — back to the console prompt when you came from the shell.

Notes#

  • API tokens inherit your role and group scope; a read-only token turns every mutation command into a clean 403.
  • Credential-vault operations (reveal/rotate) need sudo re-auth, which is session-only — those stay in the panel by design.
  • The CLI's API surface is the panel's public HTTP API (docs/api.md); anything missing there is missing here too.
Edit on GitHubdocs/cli.md 5 min readUpdated