DEV Community

Cover image for I Spent Three Hours Fighting CloudFront. Here's What I Actually Learned.
Jas
Jas

Posted on

I Spent Three Hours Fighting CloudFront. Here's What I Actually Learned.

Today was supposed to be simple.

I'm working through the Cloud Resume Challenge, a project that has you build a resume site on AWS using S3, CloudFront, Lambda, DynamoDB, and a handful of other services, wired together by hand. The point isn't the resume. The point is proving you can actually use the infrastructure, not just talk about it.

Stage one: static site on S3. Done. Stage two: CloudFront with HTTPS.

Three hours later, I was staring at the same error message for the sixth time.

What Went Wrong

The error was this:

404 Not Found
Code: NoSuchBucket
BucketName: d2aoai2y8wmb9h.cloudfront.net
Enter fullscreen mode Exit fullscreen mode

S3 was receiving requests and trying to find a bucket named after my CloudFront domain. Which doesn't exist. Which will never exist. That's not how any of this works.

Here's what was actually happening: CloudFront was forwarding the wrong Host header to S3. Instead of telling S3 "hey, I'm looking for content from resume.jasmineallen.dev.s3-website.us-east-2.amazonaws.com," it was sending its own domain name as the host. S3 saw that, tried to find a matching bucket, couldn't, and threw a 404.

The root cause was the AWS console's new simplified CloudFront UI. When I selected "Amazon S3" as my origin type during setup, it locked in S3-specific origin behavior under the hood. Behavior I couldn't fully override by just editing the origin domain afterward. The UI was abstracting away the exact setting I needed to change.

What I needed was a custom origin configured with CustomOriginConfig, which tells CloudFront to treat S3 as a plain HTTP server rather than an S3 bucket. That distinction matters because S3 static website hosting works differently from the S3 REST API, and CloudFront handles them differently.

The console wouldn't let me set it. Every path I tried hit a wall: blocked Host header overrides, stale cached errors, a distribution I couldn't delete because of a billing plan lock. I tried:

  • Editing the origin domain
  • Creating a second origin and swapping the behavior
  • Invalidating the cache
  • Disabling and re-enabling the distribution

None of it worked.

What finally worked was bypassing the UI entirely and using the AWS CLI to create a new distribution with the exact config I needed:

bashaws cloudfront create-distribution --distribution-config '{
  "Origins": {
    "Items": [{
      "DomainName": "resume.jasmineallen.dev.s3-website.us-east-2.amazonaws.com",
      "CustomOriginConfig": {
        "HTTPPort": 80,
        "OriginProtocolPolicy": "http-only"
      }
    }]
  }
  ...
}'
Enter fullscreen mode Exit fullscreen mode

First try. Site loaded. HTTPS working.

What I Actually Learned

The console UI hides things that matter.

Simplified UIs are useful until they're not. The new CloudFront setup wizard made the wrong choice for my use case, S3 REST origin instead of custom HTTP origin, and then made it very hard to correct that choice after the fact. If I hadn't known to look for CustomOriginConfig as a concept, I would have been completely stuck.

This is true of a lot of AWS tooling. The console is great for exploration. For production configuration, the CLI or IaC gives you precision the UI sometimes can't.

Error messages are clues, not just complaints.

The BucketName: d2aoai2y8wmb9h.cloudfront.net in the error response was telling me exactly what was wrong. CloudFront was sending the wrong host. I just had to slow down and read it instead of treating it as noise.

Cache invalidation is not a magic fix.

I created two invalidations today trying to clear errors that weren't caused by caching. Invalidation tells CloudFront to stop serving stale content. It doesn't fix a misconfigured origin. Reaching for invalidation before diagnosing the actual problem just adds waiting time.

Sometimes you have to go lower in the stack.

The UI abstracted away the problem. The CLI solved it in one command. Knowing that the CLI exists and how to use it isn't optional knowledge. It's the fallback when the pretty interface runs out of options.

Why This Matters Beyond the Challenge

This exact class of problem shows up in real projects all the time.

A team sets up a CDN for a client-facing application using the console's default settings. Everything looks fine in the UI. Then traffic starts behaving strangely. Some requests are slow, some are returning stale content, some are failing entirely. Nobody can figure out why because nobody looked at the actual origin configuration. The UI said it was set up correctly.

Or a startup moves their static marketing site to CloudFront to improve global performance. The engineer who set it up used the wizard. Six months later a different engineer needs to debug a caching issue and finds the origin type is wrong, with the distribution locked into a billing plan that makes it hard to recreate cleanly.

Understanding what's actually happening underneath the UI isn't just useful for passing certifications. It's the difference between being able to debug your own infrastructure and being stuck with whatever the wizard decided for you.

A few concrete takeaways for anyone building on AWS:

For S3 static website hosting + CloudFront: always use the S3 website endpoint (bucket-name.s3-website.region.amazonaws.com) as a custom HTTP origin, not the S3 REST endpoint. The website endpoint handles index documents and error routing correctly. The REST endpoint doesn't.

Before reaching for cache invalidation: confirm the origin is actually returning what you expect by hitting the origin URL directly. If the origin is broken, no amount of invalidation will fix it.

Learn the CLI early. Not everything, just the services you're actively using. aws cloudfront create-distribution, aws s3 sync, aws lambda update-function-code. These give you a level of control and repeatability the console can't match.

Where I Am Now

S3 static site: done
CloudFront with HTTPS: done (via CLI, not the wizard)
DNS: pointing resume.jasmineallen.dev at CloudFront
Visitor counter: JavaScript to API Gateway to Lambda to DynamoDB
IaC
CI/CD
This post

The debugging was frustrating in the moment. Looking back, it was the most useful part of the day, more useful than if everything had worked on the first try.

That's the thing about infrastructure work. The happy path teaches you the steps. The broken path teaches you how it actually works.

Next up: DNS and the visitor counter.

Provisioning Jas is a series about building real things on AWS, written in real time, mistakes included.

Top comments (0)