Terraform
The Excloud Terraform provider lets you describe your infrastructure in HCL and apply it through Terraform’s normal plan/apply flow. It uses the same APIs the
exc CLI does and reads the same credentials, so you can mix-and-match — bootstrap with the CLI, manage steady state with Terraform.
| Source address | excloud-dev/excloud |
| Registry | registry.terraform.io/excloud-dev/excloud |
| Public repo | github.com/excloud-dev/terraform-provider-excloud |
In this section
| Page | Covers |
|---|---|
| Quickstart | Install, authenticate, apply a VM with a public IP, destroy |
Resources
| Resource | Purpose |
|---|---|
excloud_ssh_key | Register a public key for use with VMs |
excloud_compute_instance | Virtual machine |
excloud_volume | Block volume |
excloud_volume_attachment | Attach a volume to a VM |
excloud_snapshot | Point-in-time copy of a volume |
excloud_public_ipv4 | Reserved public IPv4 |
excloud_security_group | Security group |
excloud_security_group_rule | Ingress/egress rule |
excloud_security_group_binding | Bind a security group to a VM interface |
excloud_bucket | S3-compatible object storage bucket |
excloud_bucket_access_key | S3 access key (secret returned once) |
excloud_dns_zone | DNS zone |
excloud_dns_record | DNS record (any supported type) |
Data sources
| Data source | Purpose |
|---|---|
excloud_compute_images | Look up image IDs by name (avoid hard-coding) |
excloud_instance_types | Look up instance types by name |
excloud_subnets | Find the DEFAULT subnet in a zone |
excloud_snapshots | List existing snapshots |
excloud_buckets | List existing buckets |
excloud_bucket_usage | Per-bucket usage figures |
excloud_dns_zones | List DNS zones |
Provider configuration
terraform {
required_providers {
excloud = {
source = "excloud-dev/excloud"
version = "~> 0.2"
}
}
}
provider "excloud" {
# Optional. Everything below resolves from environment variables or
# ~/.exc/config from `exc login` if not set explicitly.
# api_key = var.excloud_api_key
# org_id = var.excloud_org_id
# account_id = var.excloud_account_id
}Authentication resolution order
The provider tries, in this order:
- Explicit provider attributes (
api_key,id_token,account_id,org_id). - Environment variables —
EXCLOUD_API_KEY/API_KEY/ACCESS_TOKEN,EXCLOUD_ORG_ID,EXCLOUD_ACCOUNT_ID, etc. ~/.exc/config, as written byexc login. The provider readsdefault_acc,default_org, that account’sid_token, and that org’saccess_token.
For CI, set env vars (EXCLOUD_API_KEY, EXCLOUD_ORG_ID) from a service-account API key. For local development, exc login once and the provider just works.
Per-service base URLs
The provider points at production by default. Override per service if you need to:
provider "excloud" {
compute_base_url = "https://compute.excloud.in"
buckets_base_url = "https://buckets.excloud.in"
dns_base_url = "https://dns.excloud.in"
}Or via env: EXCLOUD_COMPUTE_BASE_URL, EXCLOUD_BUCKETS_BASE_URL, EXCLOUD_DNS_BASE_URL.
A minimal real-world stack
data "excloud_compute_images" "all" {}
data "excloud_instance_types" "all" {}
data "excloud_subnets" "zone_1" { zone_id = 1 }
locals {
ubuntu = one([for i in data.excloud_compute_images.all.images : i if i.name == "ubuntu-24.04-latest"])
size = one([for t in data.excloud_instance_types.all.instance_types : t if t.name == "m1a.large"])
subnet = one([for s in data.excloud_subnets.zone_1.subnets : s if s.name == "DEFAULT"])
}
resource "excloud_ssh_key" "main" {
name = "main"
public_key = file("~/.ssh/id_ed25519.pub")
}
resource "excloud_security_group" "web" {
name = "web"
description = "HTTP/HTTPS in, all out"
}
resource "excloud_security_group_rule" "http" {
security_group_id = excloud_security_group.web.id
direction = "ingress"
protocol = "TCPv4"
cidr = "0.0.0.0/0"
port_range = "80,443"
}
resource "excloud_public_ipv4" "web" {
name = "web-prod"
}
resource "excloud_compute_instance" "web" {
name = "web-1"
zone_id = local.subnet.zone_id
subnet_id = local.subnet.id
image_id = local.ubuntu.id
instance_type = local.size.name
ssh_pubkey = excloud_ssh_key.main.public_key
security_group_ids = [tonumber(excloud_security_group.web.id)]
public_ipv4_reservation_id = tonumber(excloud_public_ipv4.web.id)
root_volume = {
name = "web-1-root"
size_gib = 40
}
}
output "web_ip" {
value = excloud_public_ipv4.web.address
}terraform apply creates everything; terraform destroy tears it down. The plan is idempotent — re-running it without changes is a no-op.
Versioning
The provider follows Terraform’s normal semver convention. Pin to a major in your required_providers block (~> 0.2) so minor releases pick up bug fixes without surprises.
Provider source vs. CLI source
The provider talks to the same APIs as exc. If you can do something with exc compute create, the matching excloud_compute_instance exists. If a flag is missing from the provider but present in the CLI,
open an issue — most of the provider is auto-generated from the API specs, so additions are quick.