# n8n-nodes-krova

[![npm version](https://img.shields.io/npm/v/n8n-nodes-krova)](https://www.npmjs.com/package/n8n-nodes-krova)
[![npm downloads](https://img.shields.io/npm/dm/n8n-nodes-krova)](https://www.npmjs.com/package/n8n-nodes-krova)
[![license](https://img.shields.io/npm/l/n8n-nodes-krova)](./LICENSE)

Provision and manage **Krova Cloud** Cubes — and read the platform catalog — straight from your [n8n](https://n8n.io) workflows.

[Krova Cloud](https://krova.cloud) is a self-service cloud platform for running lightweight **Cubes** (Firecracker microVMs). This community node wraps the Krova Cloud REST API so you can create, power off, start, list, and delete Cubes and query regions, images, and pricing — no glue code, no HTTP Request nodes.

[Installation](#installation) · [Credential setup](#credential-setup) · [Operations](#operations) · [Example workflow](#example-workflow) · [Compatibility](#compatibility) · [Related packages](#related-packages) · [Resources](#resources)

## Installation

Install this node from within n8n — no CLI, no server restart:

1. Open **Settings → Community Nodes**.
2. Select **Install**.
3. Enter the package name **`n8n-nodes-krova`**.
4. Acknowledge the community-node risk prompt and select **Install**.

The **Krova Cloud** node appears in the node panel immediately after install. For self-hosted / manual setups, see the official [community-nodes installation guide](https://docs.n8n.io/integrations/community-nodes/installation/).

## Credential setup

Every operation authenticates with a **Krova Cloud API** credential.

1. Get an API key: sign in at **[krova.cloud](https://krova.cloud)**, open your Space, and create an API key. Keys are scoped per Space and inherit the permissions of the membership that created them. They look like `kro_...`.
2. In n8n, add a new **Krova Cloud API** credential.
3. Paste the key into **API Key** — it is sent to the API in the `X-API-KEY` header and stored encrypted by n8n.
4. Leave **Base URL** at its default `https://krova.cloud/api/v1` (override only for self-hosted or test endpoints).
5. Click **Test**. n8n calls `GET /space` (an authenticated endpoint) to confirm the key is valid and the endpoint is reachable — an invalid or revoked key fails here.

| Field | Required | Default | Notes |
| --- | --- | --- | --- |
| **API Key** | Yes | — | A `kro_...` key from your Space. Sent as the `X-API-KEY` header. |
| **Base URL** | No | `https://krova.cloud/api/v1` | Change only for self-hosted or test endpoints. |

## Operations

### Cube

Cubes are scoped to a **Space**, so every Cube operation takes a **Space ID**.

| Operation | Fields | Description | Endpoint |
| --- | --- | --- | --- |
| **List** | Space ID | List all Cubes in a Space | `GET /spaces/{spaceId}/cubes` |
| **Get** | Space ID, Cube ID | Retrieve a single Cube by ID | `GET /spaces/{spaceId}/cubes/{cubeId}` |
| **Create** | Space ID, Name, Image, SSH Public Key, vCPU, RAM (GB), Disk (GB); optional Region, User Data | Create a new Cube in a Space | `POST /spaces/{spaceId}/cubes` |
| **Power Off** | Space ID, Cube ID | Power off a running Cube — preserves data, stops compute billing, frees host RAM | `POST /spaces/{spaceId}/cubes/{cubeId}/power-off` |
| **Restart** | Space ID, Cube ID | Cold-restart a **running** Cube — boots against the host's current kernel, preserving the disk. The only way to pick up a refreshed guest kernel: a `reboot` issued inside the Cube cannot change it, and reports no error | `POST /spaces/{spaceId}/cubes/{cubeId}/restart` |
| **Start** | Space ID, Cube ID | Start a stopped Cube | `POST /spaces/{spaceId}/cubes/{cubeId}/wake` |
| **Delete** | Space ID, Cube ID | Delete a Cube (asynchronous) | `DELETE /spaces/{spaceId}/cubes/{cubeId}` |

#### Create field notes

- **Image** — an OS image slug or ID. Fetch valid values from **Catalog → Get Images**.
- **SSH Public Key** — written to the Cube login user's `~/.ssh/authorized_keys` at boot. That user is `ubuntu` on Ubuntu images and `debian` on Debian images (both with passwordless `sudo`); Cubes created before August 2026 log in as `root`. Must start with `ssh-ed25519`, `ssh-rsa`, `ecdsa-sha2-*`, `ssh-dss`, or `sk-*@openssh.com`.
- **vCPU / RAM (GB) / Disk (GB)** — sent as nested `resources.{vcpu,ramGb,diskGb}`. Every Space gets the same per-Cube ceiling (16 vCPU / 32 GB RAM / 100 GB disk) — **size is not tiered**. Ceilings depend on a per-Space override and on host capacity, not on which tier you are on.
- **Region** (optional) — a region slug from **Catalog → Get Regions**. Leave empty to auto-select.
- **User Data** (optional) — a cloud-init script run at first boot (max 16 KB).

### Catalog

Public read endpoints. The API key is still sent but is not required for these.

| Operation | Fields | Description | Endpoint |
| --- | --- | --- | --- |
| **Get Regions** | — | List regions with available capacity | `GET /regions` |
| **Get Images** | — | List available OS images | `GET /images` |
| **Get Pricing** | — | Per-resource hourly rates and volume pricing tiers | `GET /pricing` |

### Domain

Custom domains attached to a Cube. Every operation takes a **Space ID** and **Cube ID**.

| Operation | Fields | Description | Endpoint |
| --- | --- | --- | --- |
| **List** | Space ID, Cube ID | List the custom domains attached to a Cube | `GET /spaces/{spaceId}/cubes/{cubeId}/domains` |
| **Create** | Space ID, Cube ID, Domain, Port; optional Origin Scheme; Additional Fields: PROXY Protocol, Confirm Mixed PROXY Protocol | Attach a custom domain | `POST /spaces/{spaceId}/cubes/{cubeId}/domains` |
| **Update** | Space ID, Cube ID, Domain Mapping ID, Origin Scheme; Additional Fields: PROXY Protocol, Confirm Mixed PROXY Protocol | Change a domain's proxy settings | `PATCH /spaces/{spaceId}/cubes/{cubeId}/domains/{mappingId}` |
| **Delete** | Space ID, Cube ID, Domain Mapping ID | Detach a custom domain | `DELETE /spaces/{spaceId}/cubes/{cubeId}/domains/{mappingId}` |

**Origin Scheme** (Create and Update) — the transport the edge uses to reach the
Cube. Leave as **HTTP** unless the Cube terminates TLS itself: a control panel
holding its own certificate, or an app listening on HTTPS, answers plain HTTP
with a redirect and cannot be served over cleartext at all. Visitors are on
HTTPS either way. The dial port is derived — `https` on the default port 80
connects on 443. The setting applies as saved, with no check: if nothing in the
Cube answers HTTPS for the domain, visitors get an error page until you set it
back to **HTTP**. On **Update**, choose **Leave Unchanged** to change only the
PROXY protocol; the default, **HTTP**, sets the domain back to cleartext.

**PROXY Protocol** (Additional Fields, Create and Update) — send a PROXY protocol
header (**V1**, a line of text, or **V2**, binary) naming the visitor at the start
of every connection to the Cube, for an app that reads the visitor's address from
the connection. **Off** turns it off. The app must accept the PROXY protocol on
that port first, or every request to the domain fails. Every domain on the same
Cube port needs the same setting: a save that would mix them fails with `409`,
naming the other domains, unless **Confirm Mixed PROXY Protocol** is on.


### Snapshot

Snapshot and restore a Cube's disk.

| Operation | Fields | Description | Endpoint |
| --- | --- | --- | --- |
| **List** | Space ID, Cube ID | List a Cube's disk snapshots | `GET /spaces/{spaceId}/cubes/{cubeId}/snapshots` |
| **Create** | Space ID, Cube ID, Name (optional) | Snapshot a Cube's disk | `POST /spaces/{spaceId}/cubes/{cubeId}/snapshots` |
| **Delete** | Space ID, Cube ID, Snapshot ID | Delete a snapshot | `DELETE /spaces/{spaceId}/cubes/{cubeId}/snapshots/{snapshotId}` |
| **Restore** | Space ID, Cube ID, Snapshot ID | Restore the Cube's disk from a snapshot (replaces the disk) | `POST /spaces/{spaceId}/cubes/{cubeId}/restore` |

### Backup

A Cube's disk and configuration, kept after the Cube is gone. The API key's member needs **View Backups** to read and **Manage Backups** for Get Download Link and Share.

| Operation | Fields | Description | Endpoint |
| --- | --- | --- | --- |
| **List** | Space ID | List the space's backups, newest first (shared copies included) | `GET /spaces/{spaceId}/backups` |
| **Get** | Space ID, Backup ID | Retrieve a single backup | `GET /spaces/{spaceId}/backups/{backupId}` |
| **Get Download Link** | Space ID, Backup ID | A presigned URL for the backup's `.cube` archive, valid for 15 minutes. Anyone holding it can download the disk, so keep it out of logs and messages | `GET /spaces/{spaceId}/backups/{backupId}/download` |
| **Share** | Space ID, Backup ID, Destination Space ID; optional Idempotency Key | Offer another space its own copy. It has 48 hours to accept and pays for its copy from then; your backup is unchanged | `POST /spaces/{spaceId}/backups/{backupId}/shares` |

### Backup Share

Answer or withdraw a backup offered between spaces. Accept and Decline need the destination space's owner, or a member there with **Manage Backups**.

| Operation | Fields | Description | Endpoint |
| --- | --- | --- | --- |
| **List** | Space ID | Pending shares into (`incoming`) and out of (`outgoing`) the space | `GET /spaces/{spaceId}/backup-shares` |
| **Accept** | Space ID, Share ID | Create this space's own copy, billed for storage from now | `POST /spaces/{spaceId}/backup-shares/{shareId}/accept` |
| **Decline** | Space ID, Share ID | Decline a share offered to this space | `POST /spaces/{spaceId}/backup-shares/{shareId}/decline` |
| **Cancel** | Space ID, Share ID | Withdraw a pending share this space offered | `POST /spaces/{spaceId}/backup-shares/{shareId}/cancel` |

### TCP Mapping

Expose a Cube TCP port on the host.

| Operation | Fields | Description | Endpoint |
| --- | --- | --- | --- |
| **List** | Space ID, Cube ID | List a Cube's TCP port mappings | `GET /spaces/{spaceId}/cubes/{cubeId}/tcp-mappings` |
| **Create** | Space ID, Cube ID, Cube Port | Expose a Cube TCP port on the host | `POST /spaces/{spaceId}/cubes/{cubeId}/tcp-mappings` |
| **Delete** | Space ID, Cube ID, Mapping ID | Remove a TCP port mapping | `DELETE /spaces/{spaceId}/cubes/{cubeId}/tcp-mappings/{mappingId}` |

Each operation returns the raw Krova Cloud API response, ready to reference downstream with n8n expressions.

## Example workflow

**Provision a Cube every morning, power it off every night — pay only for the hours you use.**

1. **Schedule Trigger** (`0 8 * * *`) → **Krova Cloud** — Resource *Catalog*, Operation *Get Images* — to resolve the image slug you want to boot.
2. **Krova Cloud** — Resource *Cube*, Operation *Create*. Set the Space ID, a Name, the Image slug from step 1, your SSH Public Key, and `vCPU` / `RAM (GB)` / `Disk (GB)`. The response contains the new Cube's ID.
3. A second **Schedule Trigger** (`0 20 * * *`) → **Krova Cloud** — Resource *Cube*, Operation *List* → **Filter** for the Cubes you want idle → **Krova Cloud** — Operation *Power Off* on each Cube ID.

Because a stopped Cube keeps its disk but stops compute billing, this pattern gives you an ephemeral-by-day, zero-compute-by-night box driven entirely from n8n. Swap *Power Off* for *Delete* if you want it torn down instead of parked.

## Compatibility

- Requires an n8n instance with the community-nodes feature enabled.
- Built and tested against `n8n-workflow` 2.x and Node.js **20.15+**.

## Related packages

Krova Cloud ships first-party tooling across the ecosystem:

- **[@krovacloud/sdk](https://www.npmjs.com/package/@krovacloud/sdk)** — official TypeScript/JavaScript SDK.
- **[@krovacloud/mcp](https://www.npmjs.com/package/@krovacloud/mcp)** — Model Context Protocol server for AI agents.
- **[@krovacloud/webhook](https://www.npmjs.com/package/@krovacloud/webhook)** — HMAC signature verification for Krova webhooks.

## Resources

- [Krova Cloud](https://krova.cloud)
- [n8n community nodes documentation](https://docs.n8n.io/integrations/community-nodes/)
- [Report an issue](https://github.com/krovacloud/krova-node/issues)
- [Changelog](./CHANGELOG.md)

## License

[MIT](./LICENSE) © Krova Inc.
