Source: https://crabglamp.com/docs/plain-vms/reference
Last updated: 2026-06-11
Type: reference

This is the catalog for the Plain VMs surface. For end-to-end walkthroughs, see the Tutorial.

## Tiers per region

Plain VM tiers share the conservative-floor numbers from the Agents cells. US
small reports 3 vCPU — the US region provisions one extra — and the rest match
the table below.

| Tier | Region | vCPU | RAM | Disk |
|---|---|---|---|---|
| small | US | 3 | 4 GB | 80 GB |
| small | EU | 2 | 4 GB | 80 GB |
| medium | US | 4 | 8 GB | 160 GB |
| medium | EU | 4 | 8 GB | 160 GB |
| large | US | 8 | 16 GB | 240 GB |
| large | EU | 8 | 16 GB | 320 GB |

## OS images

Default user is the cloud-image distro default — the create-success view
surfaces it so you do not have to guess.

| Image key | Display name | Default user |
|---|---|---|
| ubuntu-24.04 | Ubuntu 24.04 LTS | ubuntu |
| ubuntu-22.04 | Ubuntu 22.04 LTS | ubuntu |
| debian-13 | Debian 13 | debian |
| debian-12 | Debian 12 | debian |
| fedora-43 | Fedora 43 | root |
| rocky-10 | Rocky Linux 10 | root |
| alma-10 | AlmaLinux 10 | root |

## Firewall rule shape

Each VM has a Hetzner Cloud Firewall attached. Rules are customer-editable from the dashboard. Schema:

```json
{
  "direction": "in",
  "protocol": "tcp",
  "port": "22",
  "sourceIps": ["0.0.0.0/0"],
  "description": "SSH"
}
```

- `direction` — `in` only at v1.
- `protocol` — `tcp` or `udp`.
- `port` — a port number, or a port range like `8000-8100`.
- `sourceIps` — array of CIDR strings (IPv4 or IPv6).
- `description` — free-form label.

## Vault entry shape

The Vault stores OpenSSH public keys per account:

```json
{
  "id": "<uuid>",
  "label": "laptop-2026",
  "type": "ssh-ed25519",
  "fingerprintSha256": "SHA256:…",
  "createdAt": "2026-05-01T12:00:00Z"
}
```

The Vault accepts `ssh-rsa`, `ssh-ed25519`, `ecdsa-sha2-nistp256/384/521`, and the hardware-key types `sk-ssh-ed25519@openssh.com` and `sk-ecdsa-sha2-nistp256@openssh.com`. v1 stores public keys only.

## API endpoints

### POST /api/plain-vms

Provision a new Plain VM. Returns immediately with status `provisioning`; the VM is created in the background.

Request body (the VM's hostname is set from `name`):

```json
{
  "name": "box-1",
  "tier": "small",
  "region": "us",
  "osImageKey": "ubuntu-24.04",
  "billingType": "metered",
  "access": {
    "passwordEnabled": false,
    "vaultEntryIds": ["<uuid>"]
  }
}
```

### POST /api/plain-vms/[id]/start and /stop

Start or stop the VM. Returns 200.

### POST /api/plain-vms/[id]/restart

Power-cycle a running VM (stop, then start). The VM must be `running`; any other state returns 409. Returns 200; the dashboard polls for the VM to return to `running`. Dashboard path: the Restart button on the VM's page or its list card.

### PATCH /api/plain-vms/[id]/billing

Switch the VM between pay-as-you-go and subscribe-and-save. Body: `{ "billingType": "metered" }` or `{ "billingType": "subscription" }`. The VM must be `running` or `stopped`. Switching to pay-as-you-go frees the monthly slot it held, but keeps it on your subscription (remove it from the billing page — see [Account & billing](/docs/account-and-billing)). Dashboard path: the VM's settings page → Billing type.

### POST /api/plain-vms/[id]/transfer

Transfer the VM to another account you have membership on. Body: `{ "targetAccountId": "<uuid>" }`. The VM must be `running` or `stopped` (any other state returns 400); the target must be an organization with active billing. The VM lands on the destination as pay-as-you-go regardless of its source billing type. The server keeps running through the transfer.

The VM's SSH keys and root password are baked in at provision time and **do not rotate on transfer** — whoever holds the credentials keeps OS access. The response includes a `transferNote` saying so. Rebuild the VM if you need to cut off prior access. Dashboard path: the VM's settings page → Transfer (the confirm dialog repeats this caveat).

### DELETE /api/plain-vms/[id]

Destroy the VM. Returns 200; billing closes and the server is torn down in the background. A subscribe-and-save VM's monthly slot stays on your subscription for reuse (remove it from the billing page); a pay-as-you-go VM's charges stop at the destroy timestamp.

### PUT /api/plain-vms/[id]/firewall

Replace all firewall rules for the VM. Body is `{ "rules": [ … ] }` using the rule shape above (full-replace — pass the complete desired set). Returns the canonical post-mutation ruleset, re-fetched from Hetzner.

### POST /api/vault

Add a public key to the account's Vault. Body: `{ "type": "ssh_key", "label": "string", "value": "ssh-… …" }`.

### DELETE /api/vault/[id]

Delete a vault key. Returns 204.

## CLI

There is no CLI for Plain VMs at v1. SSH is the operating interface. Future versions may add `crabglamp vm …`.
