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:
| Part | What it is |
|---|---|
The shc provider | A 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 library | Two 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.
Contents
Section titled “Contents”- Getting started — install the provider from the
network mirror, pick an example, set credentials,
tofu init/plan/apply, and how the provisioned nodes relate toshc init/shc node join. - The
shcprovider — 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
coremodule and the per-substrateshc/<cloud>front doors: inputs, outputs, and usage. - Examples — a table of every example and an end-to-end walkthrough of a representative root.
How it fits together
Section titled “How it fits together”A typical estate uses a single substrate front door, which folds three
layers into one tofu apply:
- Infra — plain cloud provider resources (instances, VPC/network, firewalls, SSH keys). No SHC auth needed.
- Bootstrap — the
shcprovider installs the.deband runsshc init(node 1) /shc node join(the rest), producing a running cluster. - 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 } } }}The publish / mirror model
Section titled “The publish / mirror model”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 +
SHA256SUMSinto 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
.tgztarballs into the generic package registry, and re-served as plain archive-over-HTTPS downloads athttps://<PAGES-URL>/modules/<name>-<system>-<version>.tgz. Consumers setsourceto that URL (the version lives IN the URL — go-getter archive fetch, noversionargument).
A consumer therefore does two things (both covered in Getting started and The provider):
- Point the CLI at the provider mirror via a
provider_installationblock in~/.terraformrc/~/.tofurc(or a repo-localregistry.tfrcviaTF_CLI_CONFIG_FILE). - 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).
Related docs
Section titled “Related docs”shc init/shc node— the CLI verbs the provider drives on each node.shc config— the scoped-config surface behindshc_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.