---
title: "CLI quickstart"
description: "From install to a running Ubuntu VM with SSH — entirely from the metalhost CLI."
url: "https://metalhost.net/docs/developers/quickstart"
---

# CLI quickstart

Install the CLI, authenticate, register an SSH key, create a VM, wait for provisioning, and SSH in. About five minutes end-to-end. New to Metalhost? Read [Concepts](https://metalhost.net/docs/developers/concepts.md) first for orgs, projects, wallets, and operations.

> **before you start**
>
> 1. Create an account at [app.metalhost.net](https://app.metalhost.net)
> 2. Fund the wallet (*Billing → Wallet → Top up*) — a few dollars is enough for testing
> 3. Mint an API key (*Developers → API keys → Create*)
> 4. Have an SSH keypair locally (`ssh-keygen -t ed25519` if needed)

## 1. Install

macOS and Linux:

```
curl -fsSL https://metalhost.net/install-cli.sh | bash
```

The installer prints `→ Installed …/metalhost` and a version string. That version is from the full path — if the path is `~/.local/bin` (typical on macOS), type this before anything else:

```
export PATH="$HOME/.local/bin:$PATH"
metalhost version
```

> **command not found**
>
> The binary is there; this terminal just isn’t looking in that folder. `curl | bash` cannot update PATH for you. Run the `export` above, then add the same line to `~/.zshrc` (macOS) or `~/.bashrc` so new windows keep it. Full walkthrough: [CLI — Install](https://metalhost.net/docs/developers/cli.md#install).

Windows zips, pinning a version, or `go install`: [CLI — Install](https://metalhost.net/docs/developers/cli.md#install-other).

## 2. Authenticate

### Interactive (first time)

The wizard writes your profile to `~/.config/metalhost/config.yaml`:

```
metalhost init
```

Press Enter on **profile name** and **API endpoint** to accept the defaults. The paste-an-API-key / log-in options appear after those two prompts — do not paste an `aes_…` key into the endpoint field. Choose **paste an API key** if you already minted one in the dashboard. The wizard also picks your default project and datacenter.

### Automation (CI / scripts)

Set env vars — they override the profile on every command:

```
export METALHOST_ENDPOINT=https://api.metalhost.net
export METALHOST_API_KEY=aes_...
export METALHOST_PROJECT=projects/my-project
export METALHOST_REGION=datacenters/us-dal-1

metalhost auth whoami
```

### Profile file

After `init`, your config looks like:

```
endpoint: https://api.metalhost.net
api_key: aes_...
organization: organizations/my-org
project: projects/my-project
region: datacenters/us-dal-1
format: table
```

Switch profiles with `metalhost profile use NAME`. Manage with `metalhost profile list`, `create`, `set`.

## 3. Discover your scope

Confirm identity and list projects before creating resources:

```
metalhost auth whoami -o json
metalhost project list
metalhost catalog datacenter list
metalhost catalog pricing quote --vcpus 2 --ram-gib 8 --cpu-class cascadelake --boot-disk-gib 80
```

## 4. Register an SSH key

Keys are project-scoped. Register once, reference on every VM:

```
metalhost vm ssh-key create \
  --id laptop \
  --display-name "My laptop" \
  --public-key "$(cat ~/.ssh/id_ed25519.pub)"

metalhost get ssh-key
```

## 5. Create a VM and wait

VM create kicks off a background provision and returns an `operations/…` resource. `--wait` polls until it finishes:

```
metalhost vm create \
  --hostname web-1 \
  --vcpus 2 \
  --ram-gib 8 \
  --cpu-class cascadelake \
  --image ubuntu-24-04 \
  --disk-size-gib 80 \
  --assign-public-ipv4 \
  --ssh-key-name projects/my-project/ssh-keys/laptop \
  --wait
```

Replace `projects/my-project` with your project from step 3. Required flags: `--vcpus`, `--ram-gib`, `--cpu-class`, and a boot source (`--image` or `--boot-url` with `--disk-size-gib`).

> **declarative manifests**
>
> For GPU VMs, multiple users, or custom cloud-init, write a YAML manifest and run `metalhost vm apply -f vm.yaml --wait`. See [CLI → VMs (YAML manifest)](https://metalhost.net/docs/developers/guides/cli-vms.md#yaml-manifest).

## 6. Read the VM and SSH in

```
metalhost vm get web-1 -o json | jq '.virtualMachine | {state, publicIpv4, linuxUsername}'

ssh ubuntu@$(metalhost vm get web-1 -o json | jq -r '.virtualMachine.publicIpv4')
```

Provisioning takes ~90 seconds. If state isn't `RUNNING` yet:

```
# if you saved the operation name from create output
metalhost ops wait operations/op_abc123
metalhost vm get web-1
```

## 7. Output formats

The CLI defaults to human-readable tables. For scripting:

```
metalhost vm list -o json
metalhost vm list -o yaml
metalhost vm list -q          # names only, one per line
```

## 8. Tear down

```
metalhost vm delete web-1 --yes --wait
```

## Troubleshooting

| Problem | What to check |
| --- | --- |
| `endpoint is required` | Run `metalhost init` or set `METALHOST_ENDPOINT` |
| `API key is required` | Set `METALHOST_API_KEY` or run `metalhost auth login --api-key` |
| Operation `FAILED` | `metalhost ops get operations/…` — read `errorMessage`. Often wallet balance or capacity. |
| Can't SSH | VM must be `RUNNING`; need `publicIpv4` or use `metalhost vm console` |
| `FailedPrecondition` on create | Top up the wallet in the dashboard |

## What's next

- [Concepts](https://metalhost.net/docs/developers/concepts.md) — platform mental model.
- [Examples cookbook](https://metalhost.net/docs/developers/examples.md) — CLI, Go, and curl for common tasks.
- [CLI reference](https://metalhost.net/docs/developers/cli.md) — every command and flag.
- [Go SDK](https://metalhost.net/docs/developers/sdk.md) — build programs against the API.
- [VM lifecycle](https://metalhost.net/docs/dashboard/guides/vms-lifecycle.md) — resize, snapshot, console, clone.
