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

22,300

Solution 1

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 2

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 3

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

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.

Share:
22,300
ffxsam
Author by

ffxsam

Updated on July 08, 2022

Comments

  • ffxsam
    ffxsam almost 2 years

    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.