Skip to content
SHC Docs

Terraform / OpenTofu

Infrastructure-as-code for provisioning and driving a Self-Hosted Cloud (SHC) cluster. SHC ships a vendored Terraform surface (under terraform/ in the repo) with three parts:

PartWhat it is
The shc providerA custom Terraform provider (selfhosted-cloud/shc) with ~12 resources and 4 data sources that talk to the SHC daemon — bootstrap nodes, install apps, wire DNS, manage tenants/users/connections.
The module libraryTwo reusable modules: core (platform-agnostic — turns a node list into a running cluster) and shc/<cloud> (13 per-substrate front doors that build the cloud infra and call core).
The examples~18 ready-to-copy root configurations, one per substrate/scenario (AWS, Azure, GCP, Hetzner, Proxmox, DigitalOcean, Linode, Scaleway, Vultr, Exoscale, Alibaba, CloudStack, OpenStack, plus LAN / WAN-mesh / LB / mixed variants).

Everything targets OpenTofu (tofu) but works identically with HashiCorp Terraform (terraform) — the commands below use tofu; swap in terraform if you prefer.

  • Getting started — install the provider from the network mirror, pick an example, set credentials, tofu init/plan/apply, and how the provisioned nodes relate to shc init / shc node join.
  • The shc provider — declaring the provider, pointing it at the network mirror, provider configuration arguments, and a reference section for every resource and data source.
  • The module library — the core module and the per-substrate shc/<cloud> front doors: inputs, outputs, and usage.
  • Examples — a table of every example and an end-to-end walkthrough of a representative root.

A typical estate uses a single substrate front door, which folds three layers into one tofu apply:

  1. Infra — plain cloud provider resources (instances, VPC/network, firewalls, SSH keys). No SHC auth needed.
  2. Bootstrap — the shc provider installs the .deb and runs shc init (node 1) / shc node join (the rest), producing a running cluster.
  3. Topology / platform — DNS, ACME/Let’s Encrypt, the load-balancer attach, mesh overlay, and app deployments.
module "shc" {
source = "https://<PAGES-URL>/modules/shc-hetzner-<version>.tgz"
cluster_name = "cloud"
ssh = { user = "admin", private_key_path = "~/.ssh/id_ed25519" }
node_groups = { control = { count = 3, server_type = "cx33", runtime = "compose" } }
bootstrap = { package = { deb_url = var.deb_url }, vault_password = var.vault_pw, host = "cloud.example.com" }
topology = { kind = "lb", dns = { name = "hetzner", type = "hetzner", zones = ["example.com"], credentials = { token = var.hcloud_token } } }
}

SHC’s Terraform artifacts are not on the public Terraform / OpenTofu registries. They are published GitLab-natively, on the SAME v* product tags (so the Terraform artifacts version in lockstep with the product):

  • The provider is published as goreleaser zips + SHA256SUMS into a GitLab generic package registry, and re-served through a provider network mirror (the Terraform provider-network-mirror protocol — static JSON + zips over HTTPS) on GitLab Pages. GitLab has no native provider-registry protocol, so the mirror is how consumers install it.
  • The modules are published as .tgz tarballs into the generic package registry, and re-served as plain archive-over-HTTPS downloads at https://<PAGES-URL>/modules/<name>-<system>-<version>.tgz. Consumers set source to that URL (the version lives IN the URL — go-getter archive fetch, no version argument).

A consumer therefore does two things (both covered in Getting started and The provider):

  1. Point the CLI at the provider mirror via a provider_installation block in ~/.terraformrc / ~/.tofurc (or a repo-local registry.tfrc via TF_CLI_CONFIG_FILE).
  2. Reference modules by their Pages tarball URL (or use a local ../../modules/... path when developing in-tree).

Both mirrors live under one Pages site. <PAGES-URL> is the project’s GitLab Pages root — for example a deployed estate might use https://<your-group>-<project>.gitlab.io/. Confirm the exact value under Deploy → Pages; the mirror must be publicly readable (Terraform sends no auth to a network mirror).

  • shc init / shc node — the CLI verbs the provider drives on each node.
  • shc config — the scoped-config surface behind shc_config.
  • Cloud guides — prose, per-cloud provisioning walkthroughs and account prerequisites.
  • Error code reference — the X<HTTP><SEQ><MNEMONIC> codes the provider surfaces verbatim in diagnostics.