The pluspanel CLI
pluspanel is a single static binary for Linux, macOS and Windows (amd64 and arm64). Every operation
of the public API is a command, with the same permissions as the panel. It sends no
telemetry, no analytics and no update checks: it talks only to the panel address you configure.
Install
Section titled “Install”Linux and macOS:
curl -fsSL https://get.pluspanel.net/cli.sh | shWindows (PowerShell):
irm https://get.pluspanel.net/cli.ps1 | iexThe installers download the latest release from GitHub
(112tech/pluspanel-cli), always check its
SHA-256 checksum, and also check the cosign signature of the checksums when
cosign is installed. They never call sudo: cli.sh installs into
~/.local/bin (as root: /usr/local/bin), cli.ps1 into %LOCALAPPDATA%\Programs\pluspanel and adds
it to your user PATH. A directory or a version can be chosen:
curl -fsSL https://get.pluspanel.net/cli.sh | sh -s -- --prefix /opt/bin --version 0.1.0Prefer to read a script before running it? Download it first:
curl -fsSLO https://get.pluspanel.net/cli.shless cli.shsh cli.shVerify a download yourself
Section titled “Verify a download yourself”Each release carries the archives pluspanel_<version>_<os>_<arch>.tar.gz (Windows: .zip), a
SHA256SUMS file and its cosign signature SHA256SUMS.sig, made with the PlusPanel release key:
cosign.pub.
curl -fsSLO https://pluspanel.net/docs/cli/cosign.pubcosign verify-blob --key cosign.pub --signature SHA256SUMS.sig --insecure-ignore-tlog=true SHA256SUMSsha256sum --ignore-missing -c SHA256SUMS # macOS: shasum -a 256 --ignore-missing -c SHA256SUMSBoth commands must succeed before you use the binary. The signature is made offline with the release
key and is not uploaded to a public transparency log, hence --insecure-ignore-tlog=true: the trust
comes from the key.
Sign in
Section titled “Sign in”pluspanel login --api-url https://panel.example.comThe CLI shows a short code and opens the panel’s /device page in your browser. Sign in there as
usual (password and second factor, or a passkey), check that the code and the request (device name,
IP address, time) are yours, and approve. Approving asks you to confirm your identity again (password
or authenticator code) if you have not done so in the last 5 minutes. The CLI then receives a personal
API key, valid 90 days and revocable in Settings → API, and keeps it in a file only you can read
(0600) in its configuration directory. On the approval page you can make the key read-only.
Without a browser on this machine, add --no-browser and open the printed address anywhere.
--client-name changes the name shown on the approval page (default: pluspanel CLI on <hostname>).
pluspanel whoami shows the user, organization and key in use. pluspanel logout forgets the stored
key; pluspanel logout --revoke also revokes it on the control plane.
In CI and scripts
Section titled “In CI and scripts”Use an API key created for the job, with the scopes it needs, from your CI’s secret store:
export PLUSPANEL_API_URL=https://panel.example.comexport PLUSPANEL_API_KEY="$PLUSPANEL_CI_KEY"pluspanel servers list -o jsonOr store a key in a profile: --api-key reads it from standard input and --api-key-file from a file,
so it does not end up in your shell history:
printf '%s' "$PLUSPANEL_CI_KEY" | pluspanel login --api-url https://panel.example.com --api-keypluspanel login --api-url https://panel.example.com --api-key-file ~/.pluspanel-keyThe CLI checks that what it reads looks like a PlusPanel key (ppk_…) before sending it anywhere.
Profiles
Section titled “Profiles”Profiles keep several control planes apart, for example staging and production:
pluspanel login --profile staging --api-url https://staging.example.compluspanel login --profile prod --api-url https://panel.example.compluspanel profiles listpluspanel profiles use prodpluspanel profiles set prod --default-output jsonpluspanel --profile staging servers listPLUSPANEL_PROFILE=prod pluspanel accounts listpluspanel profiles delete stagingWithout --profile the current profile is used (the first one you signed in to, or the one chosen
with profiles use). The files live in the user configuration directory: ~/.config/pluspanel/
(or $XDG_CONFIG_HOME/pluspanel) on Linux, ~/Library/Application Support/pluspanel on macOS,
%AppData%\pluspanel on Windows; PLUSPANEL_CONFIG_DIR overrides it. config.yaml holds the
profiles (no secrets), credentials.yaml the keys, mode 0600: the CLI refuses to read it when other
users can.
| Variable | Effect |
|---|---|
PLUSPANEL_PROFILE |
profile to use |
PLUSPANEL_API_URL |
API URL (overrides the profile’s) |
PLUSPANEL_API_KEY |
API key (overrides the stored credential) |
PLUSPANEL_CONFIG_DIR |
configuration directory |
NO_COLOR |
no bold table headers (also --no-color) |
Output
Section titled “Output”-o table (default, for people), -o json and -o yaml (for programs). JSON output is the API’s
answer, unchanged, so it pipes into jq:
# Every server's name and statuspluspanel servers list --all -o json | jq -r '.items[] | "\(.name)\t\(.status)"'
# Accounts as CSVpluspanel accounts list --all -o json | jq -r '.items[] | [.id, .name] | @csv'--all follows next_cursor through every page; without it a list prints one page and the next cursor
(--cursor fetches it). --verbose prints each request, its status, request id and remaining rate
limit to standard error (never the key). Errors read Error: <detail> (code <code>, request <id>).
Exit codes: 0 success, 1 usage or API error,
2 authentication (401/403, not signed in), 3 not found, 4 conflict, precondition failed or rate
limited (409/412/429), 5 the API could not be reached.
Examples
Section titled “Examples”# Servers and accountspluspanel servers listpluspanel servers get 6f1c2d3e-…pluspanel accounts list
# Launch a WordPress site in an account (retries are safe with --idempotency-key)pluspanel sites launch 5a5a5a5a-… \ --primary-domain shop.example.com --title Shop --admin-email owner@example.com \ --idempotency-key "$(uuidgen)"
# Full request bodies from a file or standard input (- = stdin); flags override its memberspluspanel sites launch 5a5a5a5a-… --data-file site.jsonpluspanel dns create-record 7c7c7c7c-… --data '{"name":"www","type":"CNAME","content":"example.com."}'
# Optimistic concurrency: send back the ETag of the GET you read (412 if the object changed# meanwhile; see Conventions → ETags for reading it with curl)pluspanel security put-site 6b6b6b6b-… --data-file security.json --if-match "$etag"
# API keys and webhookspluspanel api-keys create --name ci --scopes 'servers:read,sites:write' -o jsonpluspanel api-keys listpluspanel webhooks create --url https://hooks.example.com/pluspanel --events 'site.*,backup.failed'pluspanel webhooks list-deliveries 9d9d9d9d-… --state dead
# Any operation by path, like curl with your credentialspluspanel api GET /php-versionspluspanel api GET '/audit?limit=5'Commands are grouped by resource (pluspanel --help lists the groups, pluspanel <group> --help their
commands). Path parameters are positional arguments in the order of the route; query parameters and
top-level body members are flags (lists comma-separated); every POST takes --idempotency-key and
every PUT (and every PATCH whose path has a GET) --if-match. Every command’s --help shows its description, flags and HTTP route,
generated from the API reference.
Shell completion
Section titled “Shell completion”pluspanel completion bash > ~/.local/share/bash-completion/completions/pluspanelpluspanel completion zsh > "${fpath[1]}/_pluspanel"pluspanel completion fish > ~/.config/fish/completions/pluspanel.fishpluspanel completion powershell | Out-String | Invoke-Expression