# One Cloudflare Pages project + custom domain + DNS record per language, # matching blog/hugo.toml's multihost [languages.*] baseURLs: each language # is a fully separate site (public// from the Hugo build) deployed to # its own subdomain, with English at the zone apex. # # The language codes themselves come from ../languages.txt, the same file # the Makefile reads for its deploy fan-out, so the two never drift apart. # blog/hugo.toml's [languages.*] blocks can't read that file too (Tofu has # no TOML parser to return the favor) - keep that one in sync by hand. locals { language_codes = split(" ", trimspace(file("${path.module}/../languages.txt"))) languages = { for code in local.language_codes : code => { hostname = code == "en" ? var.zone_name : "${code}.${var.zone_name}" project_name = "mykiwi-blog-${code}" } } } data "cloudflare_zone" "this" { name = var.zone_name } # Direct-upload projects (no `source` block, i.e. no git integration) - # deploys happen out-of-band, e.g. `wrangler pages deploy public/en # --project-name=mykiwi-blog-en` from CI, since this repo lives on # tangled.sh rather than GitHub. resource "cloudflare_pages_project" "site" { for_each = local.languages account_id = var.cloudflare_account_id name = each.value.project_name production_branch = "main" } resource "cloudflare_pages_domain" "site" { for_each = local.languages account_id = var.cloudflare_account_id project_name = cloudflare_pages_project.site[each.key].name domain = each.value.hostname } resource "cloudflare_record" "site" { for_each = local.languages zone_id = data.cloudflare_zone.this.id name = each.key == "en" ? "@" : each.key type = "CNAME" content = cloudflare_pages_project.site[each.key].subdomain proxied = true } # www.mykiwi.blog -> mykiwi.blog (English apex), not its own language - just # the one common typo/habit redirect, not a 5th site. resource "cloudflare_record" "www" { zone_id = data.cloudflare_zone.this.id name = "www" type = "CNAME" content = var.zone_name proxied = true } # Page Rules would also do this but its Edit permission only shows up in # the API token builder for account Super Administrators - Single Redirects # (this resource) works with a normal scoped token (Zone:Dynamic Redirect:Edit). resource "cloudflare_ruleset" "www_redirect" { zone_id = data.cloudflare_zone.this.id name = "www to apex redirect" description = "www.${var.zone_name} -> ${var.zone_name}, path preserved" kind = "zone" phase = "http_request_dynamic_redirect" rules { ref = "www_redirect" description = "Redirect www to apex" expression = "(http.host eq \"www.${var.zone_name}\")" action = "redirect" action_parameters { from_value { status_code = 301 target_url { expression = "concat(\"https://${var.zone_name}\", http.request.uri.path)" } preserve_query_string = true } } } }