CLI — VMs
metalhost vm (aliases vms, compute)
provisions and manages virtual machines — from quick flags or a declarative
YAML manifest.
Commands
| Command | What it does |
|---|---|
vm list | List VMs in the active project. |
vm get NAME | Get a VM by resource name. |
vm create | Provision from flags (see below). |
vm apply -f FILE | Provision from YAML/JSON manifest. |
vm start|stop|restart NAME | Power actions. |
vm delete NAME | Tear down the VM. |
vm resize NAME --vcpus N --ram-gib N | Change shape (stop → patch → start). |
vm reimage NAME | Wipe OS disk and reinstall. |
vm clone --source NAME --display-name NEW | Disk-level copy. |
vm console NAME --type serial|vnc | Short-lived console URL. |
vm metrics NAME | CPU / memory / network samples. |
vm autorenew NAME --enable|--disable | Toggle monthly auto-renew. |
vm renew NAME | Renew a monthly VM immediately. |
vm create flags
Use flags for simple single-user VMs. For GPU, multiple users, billing modes, or cloud-init, use a YAML manifest instead.
| Flag | What it does |
|---|---|
--vcpus N | vCPU count (required). |
--ram-gib N | RAM in GiB (required). |
--cpu-class NAME | e.g. cascadelake (required). |
--image ID | Catalog image, e.g. ubuntu-24-04. |
--boot-url URL | Raw image URL (alternative to --image). |
--boot-disk-name NAME | Existing disk as boot volume. |
--disk-size-gib N | Boot disk size (required with image/boot-url). |
--gpu-model NAME / --gpu-count N | GPU passthrough, e.g. rtx4090. |
--hostname NAME | DNS hostname; defaults to a UUID slug. |
--user NAME / --password / --sudo | Single login user (use manifest for multiple). |
--ssh-key PUBKEY | Inline public key (repeatable). |
--ssh-key-name NAME | Registered key resource name (repeatable). |
--user-data YAML | cloud-init user-data — owns user creation. |
--network NAME | Tenant network (default: project's default). |
--assign-public-ipv4 | Attach a public IPv4. |
--billing-mode MODE | HOURLY, monthly-1 … monthly-12. |
--autorenew | Auto-renew for monthly modes. |
--wait | Block until the create operation finishes. |
metalhost vm create \
--vcpus 2 --ram-gib 8 --cpu-class cascadelake \
--image ubuntu-24-04 --disk-size-gib 80 \
--hostname my-vm \
--ssh-key-name projects/main/ssh-keys/laptop \
--assign-public-ipv4 \
--wait YAML manifest
Use metalhost vm apply -f vm.yaml when flags aren't enough —
multiple users, GPU shapes, prepaid billing, labels, or full cloud-init.
Same schema as the dashboard and Go SDK.
Apply a manifest
metalhost vm apply -f vm.yaml --wait
# Omit project/region in the file — fill from profile or flags:
metalhost vm apply -f vm.yaml --project projects/my-app --region datacenters/us-dal-1 --wait
# Pipe from stdin:
cat vm.yaml | metalhost vm apply -f - --wait metadata.project and spec.region fall back to
your active CLI profile (or --project /
--region) when omitted. Returns an operation — use
--wait to block until provisioning finishes.
Schema
| Top-level | Required | Description |
|---|---|---|
apiVersion | No | compute.metalhost.io/v1 |
kind | No | VirtualMachine |
metadata | Yes | name, project, labels, annotations |
spec | Yes | Region, compute, boot, network, users, billing, cloud-init |
spec.compute
| Field | Description |
|---|---|
cpuClass | cascadelake, milan, etc. |
vcpus / ramGib | Shape — max 4 GiB RAM per vCPU on CPU VMs |
gpu.model / gpu.count | Whole-GPU passthrough, e.g. rtx4090 |
spec.boot
Exactly one of image, imageUrl, or diskName.
spec.network
publicIpv4 defaults to false. IPv6 is always on.
spec.users[]
name, sshKeys, sshPubkey, password, sudo.
spec.billing
mode: BILLING_MODE_HOURLY (default) or
BILLING_MODE_MONTHLY_1 through BILLING_MODE_MONTHLY_12.
autorenew for monthly modes.
Basic CPU VM
apiVersion: compute.metalhost.io/v1
kind: VirtualMachine
metadata:
name: web-1
project: projects/my-app
spec:
region: datacenters/us-dal-1
compute:
cpuClass: cascadelake
vcpus: 2
ramGib: 8
boot:
image: ubuntu-24-04
diskGib: 80
network:
publicIpv4: true
users:
- name: ubuntu
sshKeys:
- projects/my-app/ssh-keys/laptop GPU VM with monthly billing
apiVersion: compute.metalhost.io/v1
kind: VirtualMachine
metadata:
name: gpu-train-1
project: projects/my-app
labels:
env: prod
spec:
region: datacenters/us-dal-1
compute:
cpuClass: cascadelake
vcpus: 8
ramGib: 32
gpu:
model: rtx4090
count: 1
boot:
image: ubuntu-24-04
diskGib: 200
network:
publicIpv4: true
users:
- name: ubuntu
sshKeys:
- projects/my-app/ssh-keys/laptop
billing:
mode: BILLING_MODE_MONTHLY_1
autorenew: true Multiple login users
apiVersion: compute.metalhost.io/v1
kind: VirtualMachine
metadata:
name: shared-dev
project: projects/my-app
spec:
region: datacenters/us-dal-1
compute:
cpuClass: cascadelake
vcpus: 4
ramGib: 16
boot:
image: ubuntu-24-04
diskGib: 80
network:
publicIpv4: false
users:
- name: alice
sshKeys:
- projects/my-app/ssh-keys/alice-laptop
sudo: true
- name: deploy
password: "change-me-on-first-login"
sudo: false Full cloud-init
apiVersion: compute.metalhost.io/v1
kind: VirtualMachine
metadata:
name: custom-init
project: projects/my-app
spec:
region: datacenters/us-dal-1
compute:
cpuClass: cascadelake
vcpus: 2
ramGib: 8
boot:
image: ubuntu-24-04
diskGib: 80
network:
publicIpv4: true
cloudInit: |
#cloud-config
package_update: true
packages:
- nginx
runcmd:
- systemctl enable --now nginx
users:
- name: ubuntu
sudo: ALL=(ALL) NOPASSWD:ALL
ssh_authorized_keys:
- ssh-ed25519 AAAA... you@host Round-trip from a running VM
metalhost vm get web-1 -o yaml > vm.yaml
metalhost vm apply -f vm.yaml --wait vm apply also accepts JSON with the same camelCase field
names as the HTTP API.
Snapshots
| Command | What it does |
|---|---|
vm snapshot create --vm NAME --display-name S | Take a snapshot. |
vm snapshot list --vm NAME | List snapshots. |
vm snapshot get NAME | Get a snapshot. |
vm snapshot delete NAME | Delete a snapshot. |
vm from-backup --snapshot NAME ... | Provision from a snapshot. |
SSH keys
| Command | What it does |
|---|---|
vm ssh-key list | List registered keys. |
vm ssh-key create --id ID --public-key "ssh-ed25519 ..." | Register a key. |
vm ssh-key delete NAME | Unregister a key. |
What's next
- Go SDK — VM manifest
- Dashboard → VM lifecycle
- CLI → Operations — poll
--wait