#10

Folio: Anime Image CDN

January 28, 2026

Google CloudTerraformCloud CDNCloud ArmorReact

Fast global anime image CDN + gallery with 10k+ assets. Deep focus on Google Cloud: global load balancer, CDN, Cloud Armor WAF, rate limiting, and Terraform IaC.

What is it?

This project looks like an anime image gallery on the surface, but the real reason I built it was to learn Google Cloud’s networking and edge stack properly. I wanted to serve images globally with low latency and make the whole deployment reproducible with Terraform.

So the gallery was almost the excuse. The actual project was the CDN, the load balancer, the WAF, the image transformation service, the SSL setup, and the cost controls around all of it.

The full infrastructure stack

I provisioned the whole stack with Terraform: storage bucket, image processing service, serverless network endpoint group, global load balancer, Cloud CDN, Cloud Armor, a static anycast IP, and managed certificates. The image processing layer uses Node.js with Sharp so requests can ask for different sizes and formats without me pre-generating every variant.

What I liked here was that I could go from nothing to a fully working global delivery stack with one infrastructure definition. It made the project feel much more like a real platform build than just a frontend app with some cloud hosting attached.

Cloud Armor: default-deny allowlist model

I wanted to be strict at the edge, so instead of a loose allow-by-default setup, I used a default-deny model and only allowed trusted origins and paths I actually wanted reaching the service. That means bad traffic gets blocked before it even hits the app layer.

I like this design because it keeps the backend simpler. Rather than hoping every request gets filtered later, I reject most unwanted traffic as early as possible. Combined with rate limiting and managed WAF rules, it makes the service much harder to abuse.

The billing circuit breaker

One thing I have learned from cloud projects is that security is not the only thing that needs a guardrail. Billing does too. So I added a circuit breaker path where budget alerts publish an event, a Cloud Function receives it, and the function changes Cloud Run ingress so public traffic gets cut off.

That gives me a hard emergency brake if spend starts going somewhere I do not like. It is a very practical feature for personal projects because it lets me experiment with public infrastructure without feeling like one traffic spike is going to become a disaster.

Cache key design

The CDN side gets interesting once images can be transformed dynamically. If width, height, and format can all change, the cache has to treat those variants as different objects. Otherwise one request can poison another.

So I designed the cache key to include the transformation parameters. A 400px WebP and an 800px PNG are separate cache entries. That sounds obvious, but it is exactly the kind of detail that decides whether a CDN setup feels correct or constantly weird when users hit different variants of the same asset.

Key takeaways

  • GCP Cloud CDN: anycast routing, PoPs, cache key design including query params
  • Cloud Armor allowlist model: default deny + explicit allow is more secure than default allow + blocklist
  • Billing circuit breaker: Pub/Sub to Cloud Function to Cloud Run ingress = INTERNAL_ONLY
  • Terraform IaC: full GCP networking stack reproducible from terraform apply
  • Node.js Sharp for on-the-fly image resizing: format conversion, quality settings
Try it live →Watch on YouTube →← all projects