Skip to content

Terraform Infrastructure Encoding

On 2 March 2026, all existing UCCA Cloudflare infrastructure was audited, declared in Terraform, and imported into state. The ucca-infra repo is now the single source of truth for infrastructure configuration.

Why Terraform

UCCA's Cloudflare infrastructure was managed manually via the dashboard and wrangler CLI. This worked during early development but created three problems:

  1. No audit trail — no record of what changed, when, or why
  2. No drift detection — no way to verify actual state matches intended state
  3. No review process — changes went live without review or approval

Terraform solves all three. Every change is a code diff, reviewed in a PR, and applied deliberately.

What's Under Management

116 resources imported with zero drift. The full breakdown:

Resource Type Count Details
Zones 10 ucca.online, rtopacks.com.au, ucca.asia, ucca.college, ucca.com.au, ucca.live, rignold.com, dlongglobal.com/net/org
DNS records 83 A, AAAA, CNAME, MX, TXT, CAA across all active zones
Zone settings 16 SSL, TLS, HTTPS, security level, brotli, browser check (2 zones)
Pages projects 2 ucca-docs, ucca-knowledge (GitHub-connected)
Pages domains 2 docs.ucca.online, knowledge.ucca.online
D1 database 1 rtopacks-db
R2 bucket 1 rtopacks-media
KV namespace 1 LEADS

Scope Decision: Infra Only

Terraform manages infrastructure — zones, DNS, storage, zone settings, and Pages projects. Worker script deployment stays in ucca-surfaces via wrangler.

This is a deliberate boundary:

  • Terraform owns the resources Workers run on (DNS routing, storage bindings, zone config)
  • Wrangler owns the application code deployed to those resources (Worker scripts, routes, environment variables, secrets)

There is no overlap. Wrangler's wrangler.jsonc files define Worker bindings and routes. Terraform defines the zones, DNS records, and storage those bindings reference. Neither tool touches the other's domain.

Repository Structure

infra/ucca-infra/                  (git: uccaonline/ucca-infra)
├── main.tf                        # Provider config (Cloudflare v5)
├── variables.tf                   # Account ID, zone IDs, API token
├── zones.tf                       # All 10 Cloudflare zones
├── dns_ucca_online.tf             # DNS records for ucca.online
├── dns_rtopacks.tf                # DNS records for rtopacks.com.au
├── dns_secondary.tf               # DNS records for other active zones
├── storage.tf                     # D1, R2, KV
├── pages.tf                       # Pages projects and custom domains
├── security.tf                    # Zone-level security settings
├── imports.tf                     # Import blocks (can be removed after apply)
├── outputs.tf                     # Key resource IDs and endpoints
├── Makefile                       # init, validate, plan, apply, fmt
└── terraform.tfstate              # Local state (gitignored)

Key Technical Details

  • Terraform version: 1.5.7 (last open-source release)
  • Cloudflare provider: v5.18.0 (significant schema differences from v4 — uses account = { id = ... } instead of account_id for zones, individual cloudflare_zone_setting instead of cloudflare_zone_settings_override)
  • State: Local for now. Migrate to remote backend when team access is needed.
  • Import IDs: Provider v5 uses simplified format (zone_id/record_id) not the v4 API path format

Version History

Version Date Change Author
1.0 2026-03-02 Initial creation Claude Code
1.1 2026-03-02 Pages resources imported, 112 → 116 Claude Code