Ditch the Dashboard: Mastering VergeOS with `verge-cli`
What if your entire private cloud was just a curl away?
For most VergeOS administrators, the dashboard is home. It's intuitive, powerful, and visual. But what happens when you need to:
- Power cycle an entire test lab of 20 VMs with a single command string?
- Find out which VM is consuming the most resources across your environment?
- Script a snapshot-before-deploy workflow that even an intern can run safely?
That's where verge-cli becomes your new best friend. It's a single, statically-linked binary that gives you raw, unadulterated access to the entire VergeOS API. No browser, no clicking, just pure command-line power.
π‘ Why Ditch the Dashboard?
While the VergeOS UI is fantastic, the CLI wins in three key scenarios:
- Bulk Operations: Updating settings on 20 VMs takes 30 seconds with a one-liner vs. 15 minutes of manual clicking.
- Automation Pipelines: Triggering snapshots before a deployment can be baked directly into your CI/CD jobs.
- Speed & Stability: On a spotty cellular connection or when tunneling through SSH, a 50KB JSON response is inherently more reliable than a heavy web interface.
π Getting Started: Connect to Your System
Before you do anything, you need to authenticate. The most robust way to work is by generating a session token and storing it in a shell variable for reuse.
Step 1: Generate a Session Token
Generate a session token using the /sys/tokens endpoint. Unlike the UI, the API requires a specific JSON payload:
export VG_HOST="192.168.1.138" # Your VergeOS IP/Hostname
# Note: The JSON body keys are 'login' and 'password'
export YB_TOKEN=$(verge-cli --server=$VG_HOST --tls-skip-verify \
--post='{"login": "admin", "password": "YourSecurePassword"}' \
/sys/tokens | jq -r '."$key"')
echo "Token: $YB_TOKEN"
Step 2: Use the Token
Now pass the token and server explicitly to every command:
# This lists your active VMs (ignoring recipe templates)
verge-cli --server=$VG_HOST --tls-skip-verify -T $YB_TOKEN \
--filter="is_snapshot eq false" /v4/vms
β οΈ Important: Most lab and tenant environments use self-signed certificates. Always include
--tls-skip-verifyunless you've configured custom CA certificates with--tls-ca-cert.
π Reading Data: The GET World
The default action for verge-cli is a GET request. This is your window into the system's state.
List Active VMs
verge-cli --server=$VG_HOST --tls-skip-verify -T $YB_TOKEN \
--filter="is_snapshot eq false" /v4/vms
VMs vs. Recipes (Templates)
VergeOS stores "Recipes" (templates) in the same endpoint as active VMs. You can filter them using the is_snapshot field:
# List ONLY active VMs
verge-cli --server=$VG_HOST --tls-skip-verify -T $YB_TOKEN --filter="is_snapshot eq false" /v4/vms
# List ONLY Recipes/Templates
verge-cli --server=$VG_HOST --tls-skip-verify -T $YB_TOKEN --filter="is_snapshot eq true" /v4/vms
Filter by Name
Use the --filter flag with OData-style syntax:
verge-cli --server=$VG_HOST --tls-skip-verify -T $YB_TOKEN --filter="name eq 'web-server-prod'" /v4/vms
Get Specific Fields
Don't need the whole object? Use --fields:
verge-cli --server=$VG_HOST --tls-skip-verify -T $YB_TOKEN --fields='name,$key,ram,cpu_cores' /v4/vms
Output:
[
{"name": "web-server-1", "$key": 12, "ram": 4096, "cpu_cores": 2},
{"name": "db-server-1", "$key": 15, "ram": 8192, "cpu_cores": 4}
]
The Magic most Field
Too lazy to list every field? VergeOS has you covered. By adding a filter, we can also ensure we only see active VMs and not recipes:
verge-cli --server=$VG_HOST --tls-skip-verify -T $YB_TOKEN \
--filter="is_snapshot eq false" --fields='most' /v4/vms
This returns all commonly useful fields without the internal metadata.
Checking VM Power Status
Here's a gotcha: the /v4/vms endpoint doesn't directly show if a VM is running or stopped. For live power state, you need the /v4/machine_status endpoint.
Step 1: Get the machine IDs
verge-cli --server=$VG_HOST --tls-skip-verify -T $YB_TOKEN \
--filter="is_snapshot eq false" --fields='name,machine' /v4/vms
Step 2: Query machine_status
verge-cli --server=$VG_HOST --tls-skip-verify -T $YB_TOKEN \
--fields='machine,running,status,state' /v4/machine_status
The status field contains human-readable values: running, stopped, hibernating, starting, stopping, etc.
The Power Status One-Liner:
# Join VM names with their power status
VMS=$(verge-cli --server=$VG_HOST --tls-skip-verify -T $YB_TOKEN \
--filter="is_snapshot eq false" --fields='name,machine' /v4/vms)
STATUS=$(verge-cli --server=$VG_HOST --tls-skip-verify -T $YB_TOKEN \
--fields='machine,status' /v4/machine_status)
echo "$VMS" | jq -r '.[] | "\(.machine)|\(.name)"' | while IFS='|' read m n; do
s=$(echo "$STATUS" | jq -r ".[] | select(.machine == $m) | .status")
echo "$n: $s"
done
Which Node Is My VM On?
In a multi-node cluster, you often need to know which physical host is running each VM. The /v4/machine_status endpoint includes a node field for this:
# Get running VMs and their host nodes
VMS=$(verge-cli --server=$VG_HOST --tls-skip-verify -T $YB_TOKEN \
--filter="is_snapshot eq false" --fields='name,machine' /v4/vms)
STATUS=$(verge-cli --server=$VG_HOST --tls-skip-verify -T $YB_TOKEN \
--fields='machine,status,node' /v4/machine_status)
NODES=$(verge-cli --server=$VG_HOST --tls-skip-verify -T $YB_TOKEN \
--fields='$key,name' /v4/nodes)
echo "$VMS" | jq -r '.[] | "\(.machine)|\(.name)"' | while IFS='|' read m n; do
m_status=$(echo "$STATUS" | jq -r ".[] | select(.machine == $m)")
if [ "$(echo "$m_status" | jq -r '.status')" == "running" ]; then
node_id=$(echo "$m_status" | jq -r '.node')
node_name=$(echo "$NODES" | jq -r ".[] | select(.\"\$key\" == $node_id) | .name")
echo "VM: $n β Node: $node_name"
fi
done
βοΈ Creating and Modifying: POST and PUT
Here's where the scripting power shines.
Create a New Tag Category
verge-cli --server=$VG_HOST --tls-skip-verify -T $YB_TOKEN \
--post='{"name":"Environment","description":"Classify resources","taggable_vms":true}' \
/v4/tag_categories
Response:
{"$key": "1", "location": "/v4/tag_categories/1"}
Create a Tag
verge-cli --server=$VG_HOST --tls-skip-verify -T $YB_TOKEN --post='{"name":"production","category":1}' /v4/tags
Update a VM's RAM
verge-cli --server=$VG_HOST --tls-skip-verify -T $YB_TOKEN --put='{"ram":8192}' /v4/vms/12
This updates VM with $key=12 to 8GB of RAM.
ποΈ Deleting Resources
Careful now. This is the --delete flag.
Delete a Snapshot
verge-cli --server=$VG_HOST --tls-skip-verify -T $YB_TOKEN --delete /v4/machine_snapshots/5
Delete a Tag
verge-cli --server=$VG_HOST --tls-skip-verify -T $YB_TOKEN --delete /v4/tags/2
β‘ Performing Actions
Some endpoints aren't just dataβthey're commands. VergeOS uses a /v4/<resource>/<id>/<action> pattern.
β οΈ Important: Action endpoints use
POST, notPUT!
Power On a VM
verge-cli --server=$VG_HOST --tls-skip-verify -T $YB_TOKEN --post='{}' /v4/vms/36/poweron
Graceful Shutdown (Guest OS Shutdown)
verge-cli --server=$VG_HOST --tls-skip-verify -T $YB_TOKEN --post='{}' /v4/vms/36/poweroff
This sends an ACPI shutdown signal to the guest OS, allowing it to shut down gracefully.
Force Power Off (Hard Stop)
verge-cli --server=$VG_HOST --tls-skip-verify -T $YB_TOKEN --post='{}' /v4/vms/36/kill
Use this when the guest OS is unresponsive. It's equivalent to pulling the power cord.
Guest Reboot
verge-cli --server=$VG_HOST --tls-skip-verify -T $YB_TOKEN --post='{}' /v4/vms/36/guestreset
Reset (Hard Reboot)
verge-cli --server=$VG_HOST --tls-skip-verify -T $YB_TOKEN --post='{}' /v4/vms/36/reset
Take a Snapshot
# Note: You need the VM's 'machine' ID, not its '$key'!
verge-cli --server=$VG_HOST --tls-skip-verify -T $YB_TOKEN \
--post='{"machine":35,"name":"pre-upgrade-snap"}' \
/v4/machine_snapshots
π€ Uploading Files: The Secret Weapon
One of the most powerful (and least documented) features of verge-cli is its ability to upload large files directly to the VergeOS file store.
Upload a QCOW2 Image
verge-cli --server=$VG_HOST --tls-skip-verify -T $YB_TOKEN \
--upload=/path/to/debian-13-generic-amd64.qcow2 \
--upload-name="debian-13.qcow2" \
--threads=16 \
/v4/files
This uses parallel chunked uploads (16 threads!) to stream the file directly into VergeOS. A 400MB image uploads in under 20 seconds.
β οΈ Gotchas & Tips
1. The $key vs machine Distinction
VMs have two important IDs:
$key: The VM's database ID (what you see in URLs like/v4/vms/12)machine: The hypervisor's internal machine ID
When creating snapshots, you need the machine ID, not $key:
# First, get the machine ID
VM_INFO=$(verge-cli --server=$VG_HOST --tls-skip-verify -T $YB_TOKEN --fields='$key,name,machine' /v4/vms/12)
MACHINE_ID=$(echo $VM_INFO | jq -r '.machine')
# Then create the snapshot
verge-cli --server=$VG_HOST --tls-skip-verify -T $YB_TOKEN \
--post="{\"machine\":$MACHINE_ID,\"name\":\"my-snapshot\"}" \
/v4/machine_snapshots
2. Escaping $key in jq
The $key field requires quoting in jq:
# β Wrong
echo $JSON | jq '.[0].$key'
# β
Correct
echo $JSON | jq '.[0]."$key"'
3. Recipe VMs Can't Be Snapshotted
If you're bulk-snapshotting VMs and some fail, they're probably recipe templates (read-only base images). These are immutable by design.
4. Write Idempotent Scripts
Always check if a resource exists before creating:
EXISTING=$(verge-cli --server=$VG_HOST --tls-skip-verify -T $YB_TOKEN \
--filter="name eq 'my-tag'" /v4/tags)
if [ "$(echo "$EXISTING" | jq 'length')" -eq 0 ]; then
# Create the tag
fi
π§© Real-World Scripting Examples
Script 1: Bulk Create VMs from a CSV
#!/bin/bash
while IFS=, read -r name cores ram; do
verge-cli --server=$VG_HOST --tls-skip-verify -T $YB_TOKEN \
--post="{\"name\":\"$name\",\"cpu_cores\":$cores,\"ram\":$ram}" \
/v4/vms
echo "Created VM: $name"
done < vms.csv
Script 2: Nightly Snapshot of All Production VMs
#!/bin/bash
DATE=$(date +%Y-%m-%d)
verge-cli --server=$VG_HOST --tls-skip-verify -T $YB_TOKEN \
--filter="is_snapshot eq false" --fields='$key,name,machine' /v4/vms \
| jq -c '.[]' | while read vm; do
MACHINE=$(echo $vm | jq -r '.machine')
NAME=$(echo $vm | jq -r '.name')
# Skip if machine ID is null (recipe templates)
if [ "$MACHINE" = "null" ]; then
echo "Skipping $NAME (no machine ID)"
continue
fi
verge-cli --server=$VG_HOST --tls-skip-verify -T $YB_TOKEN \
--post="{\"machine\":$MACHINE,\"name\":\"nightly-$NAME-$DATE\"}" \
/v4/machine_snapshots
echo "Snapshotted: $NAME"
done
Script 3: Complete Infrastructure Workflow
Here's a production-ready script that discovers VMs, creates tags, takes snapshots, and generates an inventory report:
#!/bin/bash
set -e
CLI="verge-cli --server=$VG_HOST --tls-skip-verify -T $YB_TOKEN"
DATE=$(date +%Y-%m-%d_%H%M)
echo "π‘ Discovering VMs..."
VMS=$($CLI --filter="is_snapshot eq false" --fields='$key,name,machine' /v4/vms)
echo " Found $(echo $VMS | jq 'length') VMs"
echo "π·οΈ Setting up tags..."
$CLI --post='{"name":"CLI-Managed","taggable_vms":true}' /v4/tag_categories 2>/dev/null || true
echo "πΈ Taking snapshots..."
echo "$VMS" | jq -c '.[]' | while read vm; do
MACHINE=$(echo $vm | jq -r '.machine')
NAME=$(echo $vm | jq -r '.name')
[ "$MACHINE" != "null" ] && \
$CLI --post="{\"machine\":$MACHINE,\"name\":\"backup-$NAME-$DATE\"}" \
/v4/machine_snapshots 2>/dev/null && echo " β $NAME"
done
echo "π Generating report..."
echo "{\"vms\":$($CLI --filter=\"is_snapshot eq false\" /v4/vms),\"snapshots\":$($CLI /v4/machine_snapshots)}" \
> inventory-$DATE.json
echo "β
Complete! Report: inventory-$DATE.json"
π Security Best Practices
- Never hardcode tokens in scripts. Use environment variables and pass them as flags:
verge-cli -T $YB_TOKEN ... - Use custom CA certs for production:
verge-cli --tls-ca-cert=/path/to/ca.pem ... - Rotate tokens regularly. Session tokens expire. For long-running automation, consider using the Terraform provider which handles authentication gracefully.
π― When to Use verge-cli vs. Terraform
| Use Case | verge-cli |
Terraform |
|---|---|---|
| Quick one-off queries | β | β |
| CI/CD pipeline deploys | β (scripted) | β (preferred) |
| DR runbooks | β | β οΈ (state file complexity) |
| Drift detection | β | β |
| Complex dependency graphs | β | β |
| Bulk operations | β | β οΈ |
The Golden Rule: Use verge-cli for imperative tasks (do this now). Use Terraform for declarative state (this is what should exist).
π Conclusion
verge-cli is the Swiss Army knife you didn't know you needed. Whether you're automating nightly backups, scripting disaster recovery, or just prototyping API calls before writing Terraform, it puts the full power of VergeOS at your fingertips.
So next time you find yourself clicking through the dashboard for the hundredth time, ask yourself: Could this be a one-liner?
The answer is probably yes.
π₯ Download & Installation
GitHub Repository: https://github.com/verge-io/verge-cli
verge-cli is a single, statically-linked Go binary. Download the appropriate release for your platform:
# Example: Download and install on Linux
curl -L https://github.com/verge-io/verge-cli/releases/latest/download/verge-cli-linux-amd64 -o verge-cli
chmod +x verge-cli
sudo mv verge-cli /usr/local/bin/
Built with β€οΈ for the VergeOS Community.