One procedure covers two cases: a smaller root disk, since a root only grows in place, and replacing a machine whose guest you can no longer reach. Both machines exist during the switch, so you can verify the new one before anything points at it. Moving a volume needs the old VM stopped, so a service whose data is on volumes is down from step 2 until DNS points at the new VM.
It works if you keep a setup manifest and your data is on volumes, which detach from one VM and attach to another intact. The root disk does not carry over: anything on it you have not scripted is lost.
It does not work for a VM whose hypervisor is unreachable
(power: "unknown"): that VM cannot be stopped, so its volumes cannot be
detached. Open a ticket (POST /v1/support/tickets) naming the VM.
# 1. create the replacement (smaller root, if that is why you are here).
# It comes up stopped, so step 2 can happen before its first boot.
POST /v1/vms {"name":"web2","ram_mb":4096,"disk_gb":40,
"image":"ubuntu-lts","ssh_keys":[...]} + Idempotency-Key
# 2. move the data — detach needs the VM stopped, so unmount in-guest first,
# and refuses a volume the old VM's snapshots include: delete those first
# (409 volume_in_snapshots names them)
POST /v1/vms/{vm_OLD}/actions {"type":"stop"}
POST /v1/volumes/{id}/actions {"type":"detach"}
POST /v1/volumes/{id}/actions {"type":"attach","vm_id":"vm_NEW"}
# 3. start the replacement, then re-run your setup script
POST /v1/vms/{vm_NEW}/actions {"type":"start"}
# 4. point DNS at the new VM's address (GET /v1/vms/{id} carries it)
# 5. verify, then delete the old VM. Its volumes were moved in step 2;
# delete any snapshots it still has first, newest first,
# or this answers 409 vm_has_snapshots and names them.
DELETE /v1/vms/{vm_OLD}
The IP is bound to its VM for that VM's life and no endpoint reassigns one (why). So **put a DNS name in front of every VM** before you need this procedure, at a low TTL — 60s is plenty. With a DNS name, the switch is one record change. Without one, you have to find everything that hard-coded the address.
If a specific address has to move, open a ticket (POST /v1/support/tickets);
no API call moves one.
volume_in_snapshots (409) — the old VM has a snapshot that includes the
volume you are detaching, and a snapshot restores a volume only on the VM
that took it. The error's snapshots field names them; delete those first.
Deleting a snapshot leaves the volume's current data alone.vm_not_stopped (409) — detach needs the VM stopped. Unmount in-guest,
stop, detach.vm_has_snapshots / vm_has_volumes (409) — the delete in step 5 refuses
while the old VM still has either, and lists what is left. The order
matters: snapshots first (newest first), then detach volumes, then delete.quota_exceeded (403) — both machines exist at once, so the project needs
quota for both during the switch.
Quotas.no_capacity_available (409) — no room right now: at step 1 nothing was
created, and at step 3 the replacement stays stopped. Retry later; raising
your quota will not help.Both VMs bill while both exist — RAM only while each runs, root disk, address and snapshots regardless. Delete the old machine once the new one is verified; stopping it saves only the RAM charge.