In one paragraph: the rarecloudio/rarecloud provider lets Terraform create and track RareCloud cloud servers, volumes, private networks, firewalls, load balancers, reserved IPs, reverse DNS, SSH keys, Object Storage buckets and keys, and domain registrations, all through the public API at https://api.rarecloud.io/v1. This page covers version 0.3.0, published on the Terraform Registry for macOS, Linux and Windows (amd64, and arm64 on macOS and Linux). The source is on GitHub.
Set up the provider
terraform {
required_providers {
rarecloud = {
source = "rarecloudio/rarecloud"
version = "~> 0.3"
}
}
}
provider "rarecloud" {
# token = "rc_pat_..." # better: export RARECLOUD_TOKEN
}
Run terraform init and Terraform downloads the provider from the registry.
Authenticate
Create a token in the console under Account, then API tokens. For the resources below it needs services:read and services:write (Object Storage included); add account:read and account:write for rarecloud_ssh_key and rarecloud_account, billing:read for the billing attributes of rarecloud_account, and domains:read / domains:write for domains. Scopes match exactly, so :write does not include :read.
Give it to the provider in one of two ways:
| Setting | Provider argument | Environment variable |
|---|---|---|
| API token | token (sensitive) | RARECLOUD_TOKEN |
| API base URL | api_endpoint | RARECLOUD_API |
The endpoint defaults to https://api.rarecloud.io and the provider adds /v1 itself. Keep the token out of your .tf files: the environment variable is enough.
Resources
rarecloud_server
A Cloud VM.
| Argument | Required | Notes |
|---|---|---|
name | yes | Display name and hostname. Set it once: the provider does not rename an existing server |
plan | yes | Catalog SKU, for example g-2vcpu-8gb. Changing it resizes the VM in place |
region | yes | Region slug, bucharest-ro for the cloud. Changing it recreates the VM |
image | yes | Image slug, for example ubuntu-24.04. Changing it recreates the VM |
ssh_public_key | no | The public key itself (ssh-ed25519 ...), injected at first boot. Changing it recreates the VM |
root_password | no | Initial root password, sensitive. Prefer ssh_public_key |
vpc_id | no | A rarecloud_network id to launch into. Changing it recreates the VM |
tags | no | Up to 50 tags, each 1 to 60 characters without , or / (tags starting with managed:, k8s: or rarecloud are reserved). Order does not matter. Changing them updates the VM in place. When unset, the VM's tags are read but not managed |
Exports id, ipv4, ipv6, private_ip, hostname, status and api_access. Create waits until the server is active (up to 10 minutes), so its addresses are in state when the apply ends. If it does not come up in time, the server stays in state marked tainted and the next apply replaces it. Destroy waits until the server is gone.
rarecloud_volume
A block storage volume, billed per GB while it exists.
| Argument | Required | Notes |
|---|---|---|
size_gb | yes | 1 to 2048. Changing it recreates the volume |
name | no | Changing it recreates the volume |
server_id | no | A rarecloud_server id. Set or clear it to attach or detach in place |
Exports id, status and api_access.
rarecloud_network
A private network (VPC). The CIDR is allocated for you.
| Argument | Required | Notes |
|---|---|---|
name | yes | Changing it recreates the network |
Exports id, cidr, is_default and api_access.
rarecloud_firewall
A stateful firewall (security group).
| Argument | Required | Notes |
|---|---|---|
name | yes | Changing it recreates the firewall |
inbound_rule | no | Set of rules: protocol (tcp, udp, icmp or all), port_range_min, port_range_max, remote_cidr, description |
outbound_rule | no | Same shape as inbound_rule |
attached_server_ids | no | Set of rarecloud_server ids to attach it to. When unset, attachments made elsewhere are read but never detached |
Exports id and is_default (the account's default firewall cannot be deleted).
A new firewall starts with default rules: inbound ICMP and TCP 22, 80 and 443, outbound everything. Leave inbound_rule or outbound_rule unset and Terraform keeps whatever that direction has. Set it and that direction's rules are made to match your list exactly, so a default you do not list is removed. Rules are matched by protocol, port range and CIDR, so their order does not matter.
rarecloud_load_balancer
An L4 TCP load balancer.
| Argument | Required | Notes |
|---|---|---|
name | yes | Changing it recreates the load balancer |
port | yes | Listener and member port, 1 to 65535. Changing it recreates it |
member_server_ids | yes | At least one rarecloud_server id. Changing the list recreates it |
health_check | no | Member health checks, on by default |
Exports id, status, ipv4 (its public address), members (each with id, address, port, status) and api_access. Create waits up to 15 minutes for the load balancer to finish building and become active; destroy waits until it is gone. It costs €9 a month with its public IP included, billed hourly.
rarecloud_reserved_ip
A static public IPv4. Destroying it releases the address, and that cannot be undone.
| Argument | Required | Notes |
|---|---|---|
server_id | no | A rarecloud_server id to attach it to; the VM needs a private (VPC) network interface. Set or clear it to attach or detach in place |
Exports id, ip, region and attached.
rarecloud_reverse_dns
The PTR record for a server's primary public IPv4. Destroying it removes only the record.
| Argument | Required | Notes |
|---|---|---|
service_id | yes | A rarecloud_server id |
hostname | yes | Fully qualified, for example mail.example.com |
rarecloud_ssh_key
An account-wide SSH key, offered when you deploy.
| Argument | Required | Notes |
|---|---|---|
name | yes | Display name |
public_key | yes | The public half only. Changing it recreates the key |
Exports id and fingerprint.
rarecloud_object_storage
Enables Object Storage for the account. There is nothing to configure, and it is optional: the first bucket enables the service too. Use it to make the account an explicit dependency or to read the price card and limits.
Destroying it disables Object Storage for good. The API refuses that while any bucket or active key exists, so give your buckets and keys depends_on = [rarecloud_object_storage.this]. Exports id, handle, status, plan, quota_tb, max_buckets, max_keys, regions, pricing and created_at.
rarecloud_object_storage_bucket
A bucket. Its real name, the one S3 clients use, is <handle>-<name>, exported as full_name.
| Argument | Required | Notes |
|---|---|---|
name | yes | Your part of the name: 3 to 40 lower-case letters, digits and hyphens, no dots. Changing it replaces the bucket |
region | yes | A region id from rarecloud_object_storage_regions, for example eu-central-1. Changing it replaces the bucket |
handle | first bucket | Your namespace, 3 to 16 characters. Required on the account's first bucket and permanent; leave it out or repeat it on later buckets |
versioning | no | Keep every version of every object. Changes in place |
public | no | Public delivery is not available yet: leave it unset or false, because the API refuses true today |
force_destroy | no | Destroying a bucket that still holds objects fails unless this is true, which deletes every object first |
Exports id, full_name, endpoint, bucket_url, public_url (empty until public delivery launches), status and created_at.
rarecloud_object_storage_key
An S3 access key. Keys cannot be edited, so any change replaces the key and its secret. Destroying it revokes the key.
| Argument | Required | Notes |
|---|---|---|
name | yes | A label, 1 to 80 characters |
buckets | yes | Bucket ids, or ["*"] for every bucket, future ones included |
access | yes | read or readwrite |
Exports id, access_key_id, secret_access_key (sensitive), secret_preview, status and created_at. The API returns the secret once, so Terraform keeps it in state in plain text, even though it is marked sensitive: protect your state file.
rarecloud_domain
A domain registration. Creating it places an order and an invoice; the domain is registered once the order is paid, so status starts as Pending and fills in on a later refresh. Destroying it only removes it from the Terraform state. It does not cancel the domain.
| Argument | Required | Notes |
|---|---|---|
domain | yes | For example example.com |
years | no | 1 to 10, default 1 |
nameservers | no | Up to 5, used for the first registration |
id_protection | no | WHOIS ID protection |
dns_management | no | DNS management |
Data sources
| Data source | Arguments | Returns |
|---|---|---|
rarecloud_account | none | email, first_name, last_name, country, preferred_currency, email_verified, and the cloud billing state: billing_state, billing_available_cents, billing_runway_hours, billing_power_off_at, open_invoice_id, open_invoice_amount_cents, open_invoice_currency, open_invoice_due_at |
rarecloud_catalog_plan | sku (the plan SKU) | product_sku, vcpu, ram_mb, disk_gb, bandwidth_gb, billing_tracks, monthly_price_cents_eur, hourly_price_cents_eur. In 0.3.0 it still cannot read Cloud VM plans (their hourly price has a fraction of a cent); check those with rarecloud catalog plans <sku> or GET /v1/catalog/products/<sku> |
rarecloud_regions | backend, line (optional filters) | regions, each with slug, display_name, country_code, city, region_group, available_backends, active |
rarecloud_image | slug | display_name, os_family, version, active, available_backends |
rarecloud_tld_pricing | tld | register, transfer, renew, currency (needs domains:read) |
rarecloud_object_storage | none | enabled (false, not an error, when Object Storage is off), handle, status, plan, quota_tb, current_month_accrued_cents, usage figures, max_buckets, max_keys, regions, pricing |
rarecloud_object_storage_regions | none | regions, each with id, label, endpoint (the S3 URL), country and eu. Works before Object Storage is enabled |
Managed Kubernetes clusters are not a Terraform resource in 0.3.0. Create them in the console or through the MCP server, and fetch kubeconfigs with the CLI.
Recipes
Deploy a VM with your SSH key
data "rarecloud_image" "ubuntu" {
slug = "ubuntu-24.04"
}
resource "rarecloud_ssh_key" "me" {
name = "laptop"
public_key = file("~/.ssh/id_ed25519.pub")
}
resource "rarecloud_network" "app" {
name = "app-vpc"
}
resource "rarecloud_server" "web" {
name = "web-01"
plan = "g-2vcpu-8gb"
region = "bucharest-ro"
image = data.rarecloud_image.ubuntu.slug
ssh_public_key = rarecloud_ssh_key.me.public_key
vpc_id = rarecloud_network.app.id
}
Add a volume and a fixed IP
resource "rarecloud_volume" "data" {
name = "web-01-data"
size_gb = 50
server_id = rarecloud_server.web.id
}
resource "rarecloud_reserved_ip" "web" {
server_id = rarecloud_server.web.id
}
output "web_ip" {
value = rarecloud_reserved_ip.web.ip
}
Open SSH and HTTPS only
resource "rarecloud_firewall" "web" {
name = "web"
inbound_rule = [
{ protocol = "tcp", port_range_min = 22, port_range_max = 22, remote_cidr = "203.0.113.10/32" }, # ssh from the office
{ protocol = "tcp", port_range_min = 443, port_range_max = 443, remote_cidr = "0.0.0.0/0" }, # https
]
attached_server_ids = [rarecloud_server.web.id]
}
Balance two servers
resource "rarecloud_load_balancer" "web" {
name = "web-lb"
port = 443
member_server_ids = [rarecloud_server.web.id, rarecloud_server.web2.id]
health_check = true
}
A bucket and a key for CI
resource "rarecloud_object_storage_bucket" "assets" {
name = "assets"
region = "eu-central-1"
handle = "acme" # first bucket only; the bucket becomes acme-assets
versioning = true
}
resource "rarecloud_object_storage_key" "ci" {
name = "ci"
buckets = [rarecloud_object_storage_bucket.assets.id]
access = "readwrite"
}
output "s3_endpoint" { value = rarecloud_object_storage_bucket.assets.endpoint }
output "ci_secret" {
value = rarecloud_object_storage_key.ci.secret_access_key
sensitive = true
}
The first bucket starts the monthly base fee. Point any S3 tool at the endpoint with the key's access_key_id and secret.
Check the bill before you apply
data "rarecloud_account" "me" {}
output "spendable_cents" { value = data.rarecloud_account.me.billing_available_cents }
output "open_invoice" { value = data.rarecloud_account.me.open_invoice_id }
The billing attributes need a token with billing:read; without it they stay empty and Terraform shows a warning.
Destroy
terraform destroy -target=rarecloud_volume.data # one resource
terraform destroy # everything in this configuration
Destroying a server, volume, bucket or reserved IP deletes it for good. A rarecloud_domain is the exception: destroy leaves the domain registered.
Safe retries
Every resource create sends an Idempotency-Key. If the API's answer is lost to a timeout or a dropped connection, the provider retries up to 3 times with the same key and the API runs the create once, so a server created while the answer was in flight lands in state instead of being left behind as an untracked duplicate.
Troubleshooting
| What you see | What it means |
|---|---|
Missing API token | Set RARECLOUD_TOKEN or the provider's token argument. |
| A permission error on apply | The token lacks the scope for that resource. :write does not include :read, and Terraform needs both to read state back. |
| A plan that wants to recreate a server | You changed region, image, ssh_public_key, root_password or vpc_id. Only plan changes in place. |
A resize made in the console does not show in terraform plan | The provider does not read the plan back from the API. Make plan changes in your .tf files. |
RESOURCE_PROTECTED on apply | API access is switched off for that resource in the console. Refresh still works; turn API access back on in the console to change or destroy it. |
Server created but did not become active | The VM exists but did not reach active within 10 minutes. It stays in state as tainted, and the next apply replaces it. |
| Destroying a bucket fails with "The bucket is not empty" | Set force_destroy = true, apply, then destroy. That deletes every object in it. |
rarecloud_reserved_ip will not attach | The server needs a private network interface: launch it with vpc_id. |
A new domain stays Pending | The order is waiting for payment. Pay the invoice, then terraform refresh. |
Links
- Registry: registry.terraform.io/providers/rarecloudio/rarecloud
- Source: github.com/RareCloudio/terraform-provider-rarecloud
- API reference: console.rarecloud.io/docs/api
- Step-by-step tutorial: Terraform on RareCloud
- The same API from a terminal or an agent: CLI docs and MCP docs