# Custom images

> Upload your own ISO or disk image, or make one from an instance, and build or rebuild instances from it.

Source: https://www.coritan.com/docs/cloud-compute/custom-images/

In the dashboard:

- /dashboard/compute/images: https://www.coritan.com/dashboard/compute/images
- /dashboard/compute/images/new: https://www.coritan.com/dashboard/compute/images/new

A *custom image* is an operating system you bring. It is one of two kinds:

- An **ISO** is an installer or a live system. An instance starts from it with an empty disk, and you install over the console.
- A **disk image** is a disk that is ready to start, in qcow2, raw or vmdk format. New instances start from a copy of it, and you can rebuild an instance onto it.

Your images are listed on the **Images** page, at `/dashboard/compute/images`. Search for Cloud Compute images to open it.

## Add an image

Open **Images** and choose **Add image**. Then do one of these:

- On this computer: choose the file. It goes straight to storage in parts, and a part that fails is sent again, so a dropped connection does not start the upload over.
- At a link: give a public address that starts with `https://`. We download the file. We do not follow redirects, so use the address the file is finally served from.

Give the image a name and say what it is: its kind, its operating system (Linux, BSD or other), and its firmware (UEFI, or legacy BIOS for an older system). For a disk image, also say whether it reads cloud-init. A cloud image does, and then each new instance gets its password, SSH keys and network settings from us.

After the file arrives we check it. The image says **Checking**, then **Ready** or **Failed** with the reason.

## What we accept

| | Largest file | Formats |
| --- | --- | --- |
| ISO | 10 GB | ISO 9660 or UDF |
| Disk image | 200 GB, also once written to a disk | qcow2, raw (with a partition table), vmdk in one file |

An account holds up to 25 images. We refuse these files, and the reason says what to do:

- A file that is compressed (gzip, xz, zstd, zip). Decompress it and upload the image inside.
- A qcow2 that depends on a backing file or keeps its data in a separate file. Convert it to one file with `qemu-img convert -O qcow2 in.qcow2 out.qcow2`.
- A qcow2 that is encrypted, or marked as damaged.
- A vmdk that names other files. Upload a single-file vmdk, or convert it to qcow2.

## Storage

Images and snapshots share your storage for snapshots and images. The Images page shows how much is in use. An upload that would not fit is refused before it starts. To get more room, delete an image or a snapshot, or add Snapshot Storage. An image that failed holds no storage.

## Make an image from an instance

Open the instance, go to its **Snapshots** tab and choose **Make image…**. The instance must be stopped, so its disk does not change while we copy it. The image keeps the operating system, firmware and cloud-init setting of the system the instance runs.

For an image that others can start from, prepare the instance before you stop it: run `cloud-init clean` and delete the SSH host keys (`/etc/ssh/ssh_host_*`). Each new instance then gets fresh ones.

## Use an image

- Rebuild an instance: on the instance's **Access** tab, under **Rebuild operating system**, choose one of **Your images**. A disk image needs a disk at least as large as the one it was made from, and the page says so when the instance's disk is smaller. Rebuilding erases the disk, as it does with any operating system.
- Start from your ISO: on the instance's **Rescue** tab, under **Start from your ISO**, choose the ISO and **Restart from ISO…**. The instance restarts from the ISO with its own disk attached. Choose **Leave rescue mode** when you are done to start from the disk again.
- Order an instance: the API takes `custom_image_uuid` in place of `template_id` in the order's `config`.

An instance built from an ISO starts in rescue mode with an empty disk. Install over the [console](/docs/cloud-compute/console/), then leave rescue mode. An image that does not read cloud-init gets no password or network settings from us: sign in with what the image holds, and set the network yourself from the addresses on the instance's **Network** tab.

Each instance gets its own copy of the image, so deleting an image never touches an instance made from it.

## With the API

Uploading takes three calls. `POST /api/v1/client/vps/images/uploads` with `name`, `kind` (`iso` or `disk`) and `size_bytes` answers the image and one URL per part. PUT each part of the file to its URL and keep the `ETag` each answers. Then send `{"parts": [{"part_number": 1, "etag": "..."}]}` to `POST /api/v1/client/vps/images/{image_uuid}/complete`.

```bash
curl -X POST https://api.coritan.com/api/v1/client/vps/images/imports \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"name": "Debian 12 netinst", "kind": "iso", "url": "https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-12.8.0-amd64-netinst.iso"}'
```

`GET /api/v1/client/vps/images` lists your images and your storage use. Rebuild with `POST /api/v1/client/vps/{uuid}/rebuild` and `{"custom_image_uuid": "..."}`, and start from an ISO with `POST /api/v1/client/vps/{uuid}/rescue/enter` and the same field.

## What is not included

- Windows images. We offer none.
- Sharing an image with another account, or making one public.
- Copying an image to another location in advance. An instance in any location can use it; the first start there takes longer while the image is fetched.

## API

- `GET /api/v1/client/vps/images`: The account's images, newest first, and the storage they and snapshots use (https://www.coritan.com/docs/api/reference/client/cloud-compute-images/#op-get-api-v1-client-vps-images)
- `POST /api/v1/client/vps/images/uploads`: Start upload (https://www.coritan.com/docs/api/reference/client/cloud-compute-images/#op-post-api-v1-client-vps-images-uploads)
- `POST /api/v1/client/vps/images/imports`: Queue a download of a public https file (https://www.coritan.com/docs/api/reference/client/cloud-compute-images/#op-post-api-v1-client-vps-images-imports)
- `POST /api/v1/client/vps/images/{image_uuid}/parts`: Sign the part URLs of an upload in progress again (https://www.coritan.com/docs/api/reference/client/cloud-compute-images/#op-post-api-v1-client-vps-images-image-uuid-parts)
- `POST /api/v1/client/vps/images/{image_uuid}/complete`: Join the uploaded parts (https://www.coritan.com/docs/api/reference/client/cloud-compute-images/#op-post-api-v1-client-vps-images-image-uuid-complete)
- `GET /api/v1/client/vps/images/{image_uuid}`: One of the account's images (https://www.coritan.com/docs/api/reference/client/cloud-compute-images/#op-get-api-v1-client-vps-images-image-uuid)
- `PATCH /api/v1/client/vps/images/{image_uuid}`: Rename an image, or correct its operating system, firmware or cloud-init flag (https://www.coritan.com/docs/api/reference/client/cloud-compute-images/#op-patch-api-v1-client-vps-images-image-uuid)
- `DELETE /api/v1/client/vps/images/{image_uuid}`: Delete an image (https://www.coritan.com/docs/api/reference/client/cloud-compute-images/#op-delete-api-v1-client-vps-images-image-uuid)
- `POST /api/v1/client/vps/{uuid}/images`: Turn this stopped instance into a disk image (app/modules/vps/customimages/capture.py) (https://www.coritan.com/docs/api/reference/client/cloud-compute/#op-post-api-v1-client-vps-uuid-images)
