Resources·Docs

RareCloud Terraform provider: setup, resources and data sources

Reference for the rarecloud Terraform provider 0.3.0: configure the token, every resource and data source with its arguments, and configs for a VM, a volume, a firewall, a load balancer and a bucket.

By RareCloud Team · 12 min read · 7 Oct 2026 · Updated 9 Oct 2026

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:

SettingProvider argumentEnvironment variable
API tokentoken (sensitive)RARECLOUD_TOKEN
API base URLapi_endpointRARECLOUD_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.

ArgumentRequiredNotes
nameyesDisplay name and hostname. Set it once: the provider does not rename an existing server
planyesCatalog SKU, for example g-2vcpu-8gb. Changing it resizes the VM in place
regionyesRegion slug, bucharest-ro for the cloud. Changing it recreates the VM
imageyesImage slug, for example ubuntu-24.04. Changing it recreates the VM
ssh_public_keynoThe public key itself (ssh-ed25519 ...), injected at first boot. Changing it recreates the VM
root_passwordnoInitial root password, sensitive. Prefer ssh_public_key
vpc_idnoA rarecloud_network id to launch into. Changing it recreates the VM
tagsnoUp 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.

ArgumentRequiredNotes
size_gbyes1 to 2048. Changing it recreates the volume
namenoChanging it recreates the volume
server_idnoA 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.

ArgumentRequiredNotes
nameyesChanging it recreates the network

Exports id, cidr, is_default and api_access.

rarecloud_firewall

A stateful firewall (security group).

ArgumentRequiredNotes
nameyesChanging it recreates the firewall
inbound_rulenoSet of rules: protocol (tcp, udp, icmp or all), port_range_min, port_range_max, remote_cidr, description
outbound_rulenoSame shape as inbound_rule
attached_server_idsnoSet 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.

ArgumentRequiredNotes
nameyesChanging it recreates the load balancer
portyesListener and member port, 1 to 65535. Changing it recreates it
member_server_idsyesAt least one rarecloud_server id. Changing the list recreates it
health_checknoMember 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.

ArgumentRequiredNotes
server_idnoA 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.

ArgumentRequiredNotes
service_idyesA rarecloud_server id
hostnameyesFully qualified, for example mail.example.com

rarecloud_ssh_key

An account-wide SSH key, offered when you deploy.

ArgumentRequiredNotes
nameyesDisplay name
public_keyyesThe 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.

ArgumentRequiredNotes
nameyesYour part of the name: 3 to 40 lower-case letters, digits and hyphens, no dots. Changing it replaces the bucket
regionyesA region id from rarecloud_object_storage_regions, for example eu-central-1. Changing it replaces the bucket
handlefirst bucketYour namespace, 3 to 16 characters. Required on the account's first bucket and permanent; leave it out or repeat it on later buckets
versioningnoKeep every version of every object. Changes in place
publicnoPublic delivery is not available yet: leave it unset or false, because the API refuses true today
force_destroynoDestroying 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.

ArgumentRequiredNotes
nameyesA label, 1 to 80 characters
bucketsyesBucket ids, or ["*"] for every bucket, future ones included
accessyesread 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.

ArgumentRequiredNotes
domainyesFor example example.com
yearsno1 to 10, default 1
nameserversnoUp to 5, used for the first registration
id_protectionnoWHOIS ID protection
dns_managementnoDNS management

Data sources

Data sourceArgumentsReturns
rarecloud_accountnoneemail, 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_plansku (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_regionsbackend, line (optional filters)regions, each with slug, display_name, country_code, city, region_group, available_backends, active
rarecloud_imageslugdisplay_name, os_family, version, active, available_backends
rarecloud_tld_pricingtldregister, transfer, renew, currency (needs domains:read)
rarecloud_object_storagenoneenabled (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_regionsnoneregions, 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 seeWhat it means
Missing API tokenSet RARECLOUD_TOKEN or the provider's token argument.
A permission error on applyThe 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 serverYou 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 planThe provider does not read the plan back from the API. Make plan changes in your .tf files.
RESOURCE_PROTECTED on applyAPI 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 activeThe 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 attachThe server needs a private network interface: launch it with vpc_id.
A new domain stays PendingThe order is waiting for payment. Pay the invoice, then terraform refresh.

Related