How to make CloudFront never cache index.html on S3 bucket

Amazon Web-ServicesAmazon S3Amazon Cloudfront

Amazon Web-Services Problem Overview


I have a React app hosted on an S3 bucket. The code is minified using yarn build (it's a create-react-app based app). The build folder looks something like:

build
├── asset-manifest.json
├── favicon.ico
├── images
│   ├── map-background.png
│   └── robot-icon.svg
├── index.html
├── js
│   ├── fontawesome.js
│   ├── packs
│   │   ├── brands.js
│   │   ├── light.js
│   │   ├── regular.js
│   │   └── solid.js
│   └── README.md
├── service-worker.js
└── static
    ├── css
    │   ├── main.bf27c1d9.css
    │   └── main.bf27c1d9.css.map
    └── js
        ├── main.8d11d7ab.js
        └── main.8d11d7ab.js.map

I never want index.html to be cached, because if I update the code (causing the hex suffix in main.*.js to update), I need the user's next visit to pick up on the <script src> change in index.html to point to the updated code.

In CloudFront, I can only seem to exclude paths, and excluding "/" doesn't seem to work properly. I'm getting strange behavior where I change the code, and if I hit refresh, I see it, but if I quit Chrome and go back, I see very outdated code for some reason.

I don't want to have to trigger an invalidation on every code release (via CodeBuild). Is there some other way? I think one of the challenges is that since this is an app using React Router, I'm having to do some trickery by setting the error document to index.html and forcing an HTTP status 200 instead of 403.

Amazon Web-Services Solutions


Solution 1 - Amazon Web-Services

A solution based on CloudFront configuration:

Go to your CloudFront distribution, under the "Behavior" tab and create a new behavior. Specify the following values:

  • Path Pattern: index.html
  • Object Caching: customize
  • Maximum TTL: 0 (or another very small value)
  • Default TTL: 0 (or another very small value)

Save this configuration.

CloudFront will not cache index.html anymore.

Solution 2 - Amazon Web-Services

If you never want index.html to be cached, set the Cache-Control: max-age=0 header on that file only. CloudFront will make a request back to your origin S3 bucket on every request, but it sounds like this is desired behavior.

If you're wanting to set longer expiry times and invalidate the CloudFront cache manually, you can use a * or /* as your invalidation path (not / as you have mentioned). This can take up to 15 minutes for all CloudFront edge nodes around the world to reflect the changes in your origin however.

Solution 3 - Amazon Web-Services

Here is the command I ran to set cache-control on my index.html file after uploading new files to s3 and invalidating Cloudfront:

aws s3 cp s3://bucket/index.html s3://bucket/index.html --metadata-directive REPLACE --cache-control max-age=0 --content-type "text/html"

Solution 4 - Amazon Web-Services

It's much better to run an invalidation for index.html on every release than to defeat Cloudfront's purpose and serve it (what is basically an entrypoint for your app) from S3 every single time.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionffxsamView Question on Stackoverflow
Solution 1 - Amazon Web-Servicesfoobar443View Answer on Stackoverflow
Solution 2 - Amazon Web-ServicesLuke PetersonView Answer on Stackoverflow
Solution 3 - Amazon Web-ServiceschadhamreView Answer on Stackoverflow
Solution 4 - Amazon Web-ServicesasliwinskiView Answer on Stackoverflow