PanelicaDocs
panelica.com
Docs / Developer / Command-Line Tool

Command-Line Tool

Panelica 1.0.375 Verified 2026-07-24 Developer

Everything the panel and the REST API can do, you can also do from the shell with the panelica command. It is the third face of Panelica's triple architecture (panel UI, REST API, CLI) and the fastest way to script provisioning, run one-off admin tasks over SSH, or recover a server. Under the hood it is a thin, authenticated client for the panel's own API, so it enforces exactly the same permissions and validation as the UI. This page documents every command group with real examples and the output you actually get back.

Binary/opt/panelica/bin/panelicapanelica <command> <subcommand> [flags]
 root@server ~
$ panelica users list
ID USERNAME EMAIL ROLE STATUS
------------------------------------------------------------
943feea0-19ab-43b7-b53e-6659befb9041 jane [email protected] RESELLER active
$ panelica domains create -n shop.example.com -u 943feea0-... --php=8.3
Domain 'shop.example.com' created

Signing in

The binary lives at /opt/panelica/bin/panelica (add it to your PATH, or call it by full path). It uses the standard cobra framework, so every command has --help, and panelica --version prints the build. Authentication works three ways:

  • Automatic (root): run as the Linux root user on the panel server and the CLI logs itself in as the panel's root account automatically (it reads the panel config), so panelica users list just works over SSH with no login step. This is the normal path for a server admin.
  • Explicit login: as any other user, sign in once; the token is cached in ~/.panelica/config.json (mode 0600):
    panelica login -u admin -p 'your-password'
    panelica whoami            # confirm who you are
    panelica logout
    
  • External API (HMAC): point the CLI at the signed External API with an API key/secret (useful from a remote machine). This switches the base path to /v1 and signs every request:
    panelica configure --api-key pk_live_xxx --api-secret sk_live_xxx --use-external
    
Permissions are enforced server-side. The CLI carries your identity to the API, which applies the same [role rules](/documentation/getting-started/roles-and-access) as the panel, a RESELLER's CLI sees only their own users, a USER only their own resources. Running as Linux root is what gives you full panel-root scope. A handful of recovery commands (below) talk to the database directly and so need Linux-root filesystem access instead.

Global flags, output and the response envelope

Every command accepts:

  • -o, --output table|json, table (default) for humans, json for scripts.
  • --api-url https://host:3001, target a different backend (defaults to localhost).
  • -v, --verbose and --config <path> (defaults to ~/.panelica/config.json).

The API wraps successful responses in an envelope, {"status":"success","success":true,"data": ... }, and -o json prints that verbatim. So a created object's ID is under .data.id, not .id, which matters when you pipe into jq:

panelica users list -o json | jq -r '.data[].username'
UID=$(panelica users create -u acme -e [email protected] -p 'S3cret!' --plan=<id> -o json | jq -r '.data.id')

Mutating commands (create/delete/suspend…) print a ✓ … line on success and ✗ … on failure, with a non-zero exit code so scripts with set -e stop correctly. Some read commands always print JSON regardless of -o (noted where relevant).

Names vs IDs. Only a few commands resolve a name to an ID for you, users get and domains get (read-only lookups), and the subdomains, ssl and backup commands (which accept a domain name). Everything else, including users update/delete/suspend, db create --domain and dns records create --zone, expects the actual UUID. Use the matching get/list to find it first.

Accounts, plans and quotas

panelica users list
panelica users create -u jane -e [email protected] -p 'S3cret!' --role=RESELLER --plan=<plan_id>
panelica users get jane                     # resolves username OR id (read-only)
panelica users update <user_id> --full-name "Jane Doe" --role=USER
panelica users suspend <user_id>
panelica users unsuspend <user_id>
panelica users change-password <user_id> -p 'NewPass!'
panelica users delete <user_id>

panelica plans list
panelica plans create --name "Basic" --disk=5120 --bandwidth=51200 --domains=5
panelica plans get <plan_id>
panelica plans delete <plan_id>

panelica quota get <user_id>
panelica quota set <user_id> --disk=10G --inodes=200000

users list (table): columns ID, USERNAME, EMAIL, ROLE, STATUS. users create flags: -u/--username, -e/--email, -p/--password (all needed), plus --full-name, --role (default USER), --plan (a plan UUID). Example JSON from a create:

{
  "status": "success", "success": true,
  "message": "User created successfully",
  "data": {
    "id": "943feea0-19ab-43b7-b53e-6659befb9041",
    "username": "jane", "email": "[email protected]",
    "full_name": "Jane Doe", "role": "RESELLER", "status": "active",
    "two_factor_enabled": false, "system_username": "jane",
    "home_directory": "/home/jane", "created_at": "2026-07-24T10:00:00Z"
  }
}

plans list columns: ID, NAME, DISK, BANDWIDTH, DOMAINS (disk/bandwidth shown as MB). quota set sends --disk as a string (e.g. 10G) and --inodes as an integer; it is a PUT.

Domains, subdomains and redirects

panelica domains list
panelica domains create -n example.com -u <user_id> --php=8.3 --template=laravel
panelica domains get example.com            # resolves name OR id (read-only)
panelica domains suspend <domain_id>
panelica domains unsuspend <domain_id>
panelica domains delete <domain_id>

panelica subdomains list --domain=example.com      # accepts name or id
panelica subdomains create --name=blog --domain=example.com --path=/blog
panelica subdomains delete <subdomain_id> --domain=<domain_id>

panelica domain-config get <domain_id>
panelica domain-config update <domain_id> --document-root=/public --ssl-redirect=true --www-redirect=www

panelica redirect list <domain_id>
panelica redirect create --domain=<domain_id> --source=/old --target=https://example.com/new --type=301
panelica redirect delete <redirect_id>

domains list (table): ID, DOMAIN, USER, PHP, STATUS. domains create flags: -n/--name, -u/--user (a user UUID), --php (default 8.3), --template (default/laravel/wordpress). A created domain:

{
  "status": "success", "success": true,
  "data": {
    "id": "7479113a-c6ce-4e1d-9aff-6d7fde4b6226",
    "domain_name": "example.com", "user_id": "943feea0-...",
    "web_server": "nginx_apache", "php_version": "8.3", "php_handler": "fpm",
    "document_root": "public_html", "ip_address": "203.0.113.10",
    "ssl_enabled": false, "provisioning_status": "completed", "status": "active"
  }
}

subdomains is one of the few groups that resolves a domain name to its ID. domain-config update's --ssl-redirect is only sent when you pass the flag explicitly; --www-redirect takes none/www/non-www.

Databases and database users

panelica db list --domain=<domain_id>
panelica db create --name=wp_db --domain=<domain_id> --username=wp_user --password='S3cret!'
panelica db delete <database_id>
panelica db users list --domain=<domain_id>
panelica db users create --domain=<domain_id> --username=wp_user --password='S3cret!' --role=readWrite

panelica db-user list <domain_id>
panelica db-user create --domain=<domain_id> --username=app --password='S3cret!'
panelica db-user delete <db_user_id>

panelica mysql-user list
panelica mysql-user create --username=app --password='S3cret!' --host='%'
panelica mysql-user delete <username> --host='%'

panelica remote-mysql list
panelica remote-mysql add 203.0.113.50        # host is a positional argument
panelica remote-mysql remove <host_id>

db list (table): ID, NAME, TYPE, USER, SIZE. db create --domain takes the domain UUID (it does not resolve a name). Note remote-mysql add takes the host as a positional argument, not a flag.

ID                                    NAME          TYPE   USER      SIZE
------------------------------------------------------------
d5f8a1b2-...-c3d4                     wordpress_db  mysql  wp_user   12.44 MB

DNS and SSL

panelica dns zones list
panelica dns records list --zone=example.com          # zone name resolves to id here
panelica dns records create --zone=<zone_id> --type=A --name=www --value=1.2.3.4 --ttl=3600
panelica dns records create --zone=<zone_id> --type=MX --name=@ --value=mail.example.com --priority=10
panelica dns records delete <record_id> --zone=<zone_id>

panelica ssl list
panelica ssl info example.com                          # resolves name or id
panelica ssl install --domain=example.com --type=letsencrypt
panelica ssl install --domain=example.com --type=custom --cert=./fullchain.pem --key=./privkey.pem
panelica ssl renew example.com

dns records list (table): ID, TYPE, NAME, VALUE, TTL. One subtlety: dns records list --zone resolves a name to an ID, but dns records create --zone expects the zone UUID directly.

ssl list (table): DOMAIN, SSL, PROVIDER, EXPIRES, AUTO-RENEW (read from the domain record). ssl install has two paths: --type=letsencrypt issues/re-issues via Let's Encrypt (no cert files); --type=custom uploads the PEM files you give in --cert and --key. Example:

DOMAIN         SSL  PROVIDER     EXPIRES     AUTO-RENEW
------------------------------------------------------------
example.com    Yes  letsencrypt  2026-10-01  Yes

Email

panelica email accounts list --domain=<domain_id>
panelica email accounts create [email protected] --password='S3cret!' --quota=2048
panelica email accounts delete <email_id>
panelica email forwarders list
panelica email forwarders create [email protected] [email protected]
panelica email autoresponders list

# domain-scoped variants (separate command groups)
panelica email-forwarder list <domain_id>
panelica email-forwarder create --domain=<domain_id> --source=info [email protected],[email protected]
panelica email-autoresponder create --email=<email_account_id> --subject="Away" --body="Back Monday" \
  --start-date=2026-08-01 --end-date=2026-08-10

panelica mailing-list create --domain=<domain_id> --name=news [email protected]
panelica mailing-list add-member <list_id> [email protected]
panelica mail-queue list
panelica mail-queue flush
panelica smtp-relay set --host=smtp.provider.com --port=587 --username=u --password=p
panelica smtp-relay disable

email accounts list (table): ID, EMAIL, QUOTA, STATUS. email accounts create derives the domain from the address, so there is no --domain flag here; --quota is in MB (default 250). Note there are two forwarder commands: email forwarders create (--from/--to, a single destination) and the domain-scoped email-forwarder create (--source/--destinations, a comma-separated list).

FTP and SSH access

panelica ftp list
panelica ftp create -u deploy -p 'S3cret!' -d <domain_id> --path=/public_html
panelica ftp suspend <ftp_id>
panelica ftp delete <ftp_id>

panelica ssh-users list
panelica ssh-users create --username=dev --password='S3cret!' --user=<owner_id>
panelica ssh-users delete <ssh_user_id>
panelica ssh config
panelica ssh keys
panelica ssh add-key --name=laptop --key="ssh-ed25519 AAAA..."
panelica ssh remove-key <key_id>
panelica ssh-connection list            # live SSH sessions
panelica ssh-connection kill <connection_id>

ftp list (table): ID, FTP USER, OWNER, PATH, QUOTA, STATUS (quota in MB). Password hashes are never returned. ssh-connection list shows the live sessions you can terminate.

Backups

panelica backup list
panelica backup domains                       # domains you can back up
panelica backup create --name=nightly --domain=all --type=full --encryption=panel-key
panelica backup create --name=one --domain=example.com --encryption=password --password='Key!'
panelica backup details <filename>
panelica backup download <filename>           # prints a download URL, not the file
panelica backup restore <filename> --password=<key>
panelica backup delete <filename>

panelica backup-schedule list
panelica backup-schedule create --name=daily --cron="0 3 * * *" --retention=7 --type=full
panelica backup-activity list --limit=50

backup list (table): FILENAME, TYPE, SIZE, CREATED. backup create flags: --name (required), --domain (a domain name, comma-separated names, or the literal all) or --domain-ids (UUIDs), --type (full/incremental), --encryption (none/panel-key/password), --password (required when encryption is password), --note. --domain=all is expanded to every domain you own. backup download prints a tokenized URL to fetch with curl/wget rather than streaming the file itself.

PHP

panelica php list                       # installed versions
panelica php config <domain_id>
panelica php update <domain_id> --version=8.3 --memory-limit=256M --max-execution-time=120
panelica php restart                    # or: panelica php restart 8.3
panelica php system-status              # the CLI/system default PHP
panelica php system-set 8.3
panelica php system-remove

php update sends only the flags you set (--version, --memory-limit, --max-execution-time). php system-status renders a small report plus a COMMAND, TARGET, STATUS table of the wrapper symlinks:

Status:          Configured
Active Version:  PHP 8.3
Symlink:         /usr/local/bin/php -> /opt/panelica/services/php/8.3/bin/php

COMMAND  TARGET                                    STATUS
------------------------------------------------------------
php83    /opt/panelica/services/php/8.3/bin/php    OK

Security

panelica security firewall list
panelica security ip block 203.0.113.9 --reason="brute force" --duration=24h
panelica security ip unblock <block_id>
panelica security ip list
panelica security modsecurity status

panelica antivirus status <scan_id>
panelica antivirus list                 # scan history
panelica file-audit list --limit=50
panelica logs audit                     # panel audit trail

security ip list (table): ID, IP ADDRESS, REASON, BLOCKED AT. security ip block takes the IP as a positional argument with --reason and an optional --duration (e.g. 24h, 7d); omitting duration blocks permanently.

Server, services and monitoring

panelica server status                  # CPU/RAM/disk snapshot
panelica server info                    # full hardware inventory (JSON)
panelica server services list
panelica server services restart panelica-mysql
panelica services list
panelica monitoring status
panelica monitoring metrics
panelica processes list
panelica processes kill <pid>
panelica logs access --domain=<domain_id> --lines=100
panelica logs error  --domain=<domain_id> --lines=100

server status prints a formatted snapshot (and full JSON with -o json):

Server Status:
--------------
Uptime: up 5 days, 3 hours
CPU: 8 cores, 12.4% usage
Memory: 4096 MB / 16384 MB (25.0%)
Disk: 84 GB / 400 GB (21.0%)
Load Average: 0.34, 0.28, 0.19

server services list (table): NAME, TYPE, STATUS, PORT, VERSION. To control a service, use server services restart <name> (which drives the panel's service-control path); monitoring metrics returns the same live CPU/memory/disk/load figures as the dashboard as JSON.

Sessions, 2FA and your own account

panelica session list
panelica session kill <session_id>
panelica session kill-all               # end every other session
panelica 2fa status
panelica 2fa enable                     # returns secret + QR URL
panelica 2fa verify 123456
panelica 2fa disable --password='your-password'
panelica password change --current='old' --new='new'
panelica password generate --length=24  # local, no API call

password generate runs entirely locally (crypto-strong, clamped to 8–128 chars) and prints just the password, handy for scripting new credentials.

Updates and packages

panelica package check                  # look for updates
panelica package list                   # same, alias
panelica package apply panelica-server
panelica package rollback panelica-server --slot=23
panelica package reinstall nginx
panelica package history panelica-server

package history (table): SLOT, VERSION, PREVIOUS, INSTALLED AT. package rollback without --slot does a smart rollback (the newest slot whose version differs from the current one); pass --slot=N to target a specific backup slot. package apply on panelica-server triggers a self-update; see System Updates for how the panel reconnects.

SLOT   VERSION    PREVIOUS   INSTALLED AT
------------------------------------------------------------
23     1.0.372    1.0.371    2026-07-20T14:03:11Z
22     1.0.371    1.0.370    2026-07-18T09:11:02Z

Utilities

panelica validate domain example.com    # always JSON
panelica validate email [email protected]
panelica validate password 'S3cret!'
panelica api generate-openapi > openapi.json   # in-process, emits OpenAPI 3.0
panelica config-locks list
panelica panel-app list
panelica panel-app restart <app_name>
panelica panel-settings get
panelica panel-settings set <key> <value>
panelica phpmyadmin sso <database_id>          # returns a one-time login URL
panelica system-cron list
panelica system-cron run <job_id>
panelica bandwidth user <user_id>
panelica bandwidth domain <domain_id>
panelica files list /home/jane/public_html
panelica files read /home/jane/public_html/index.php
panelica ip-addresses list             # alias: panelica ip list
panelica ip-addresses add --ip=203.0.113.60 --interface=eth0

validate prints a JSON verdict ({"valid":true,"score":4,...}). api generate-openapi builds the spec in-process (no server call) and writes OpenAPI 3.0 JSON to stdout, a quick way to feed the API into other tooling.

Operator recovery commands

A few commands work without logging in, because they exist to rescue a server; they read the panel's database directly, so in practice only Linux root can run them:

panelica root 'NewRootPassword!'   # reset the panel root password (min 6 chars)
panelica panel                     # print a one-time browser login URL (root)
panelica login --url --user=jane   # one-time login URL for a specific user
panelica migration export-metadata --quick   # export account/domain metadata (JSON)

panelica panel is handy over SSH, it prints a link that logs you into the web panel once (valid five minutes) with no password. migration export-metadata dumps account and domain data as JSON for the migration tooling; its --quick mode lists domains, the default deep mode includes databases, email and (decrypted) Cloudflare credentials.

These bypass the normal login. The recovery commands talk straight to the database and are gated only by filesystem access (you must be root on the box). Use them for recovery, not routine automation, day-to-day scripting should go through panelica login or an API key so it stays audited and role-scoped like everything else. And keep passwords off the command line where you can (they show up in shell history and ps), prefer prompting or a tightly-permissioned config file.

A worked example: provision a customer end-to-end

#!/usr/bin/env bash
set -e

# 1. create the account on a plan (the ID is under .data.id)
UID=$(panelica users create -u acme -e [email protected] -p 'S3cret!' \
      --role=USER --plan=<plan_id> -o json | jq -r '.data.id')

# 2. add the domain with PHP 8.3, capturing its ID
DID=$(panelica domains create -n acme.com -u "$UID" --php=8.3 -o json | jq -r '.data.id')

# 3. database + user (db create takes the domain ID)
panelica db create --name=acme_db --domain="$DID" --username=acme_db --password='Db!pass'

# 4. a mailbox
panelica email accounts create [email protected] --password='Mail!pass' --quota=2048

# 5. issue a certificate (ssl install accepts the domain name)
panelica ssl install --domain=acme.com --type=letsencrypt

echo "acme.com provisioned"

Access

The CLI enforces the panel's roles and permissions through the API, so what a given login can do from the shell matches exactly what it can do in the UI. Running as Linux root gives full panel-root scope; anything else is scoped to that account.

Panelica Documentation · Written and verified against the live panel. · Last verified 2026-07-24 on Panelica 1.0.375