~/theoboursy.fr/portfolio

Infrastructure as Code · Google Cloud

Portfolio project

The infrastructure behind this whole domain. No buckets, no servers to babysit. Every site is a tiny Go binary shipped as its own Cloud Run service, wired up by Terraform. Cheap, cloud-native, and extended by editing a single JSON file.

no-load-balancer.tf the interesting bit

DNS points straight to Cloud Run

The usual way to expose Cloud Run on a custom domain is to put a Google Cloud external HTTPS Load Balancer in front of it. The catch: an HTTPS LB carries a fixed hourly cost just to exist, on the order of ~€18 / month, before it serves a single request. For a few small personal sites, that is way too much.

So there is no load balancer here. Cloud DNS maps each domain straight to its Cloud Run service: apex domains get Google-hosted A/AAAA records, subdomains get a CNAME to ghs.googlehosted.com, and Cloud Run domain mappings terminate TLS with a Google-managed certificate. Same HTTPS, custom domains, automatic certs, without the fixed monthly bill.

External HTTPS Load Balancer ~€18+/mo, always on
Cloud DNS to Cloud Run (this setup) ≈ €0, free tier
finops.tf

Almost free by design

Every service is tuned to sit inside the Cloud Run free tier, a generous monthly allowance that easily covers personal traffic. Combined with the no load balancer approach, the running cost rounds to zero.

  • min_instance_count = 0
  • cpu_idle = true
  • 128Mi
  • max_instance_count = 2
main.go

Cloud-native Go, from scratch

One shared Go server embeds each site with embed.FS and compiles to a static binary that runs on a scratch image, no OS and no libc. The image is tiny and the cold start is near zero, which is what makes scaling to zero painless.

config.json

Add a site in one entry

A single config.json drives which services exist and which domains map to them. Adding a project is one object.

{
  "name": "theoboursy-portfolio",
  "image_url": "IMAGE_URL",
  "subdomains": ["portfolio"]
}