0

I have a NextJS application hosted on AWS. I have configured my domain to point to Cloufront and it points to the S3 origin bucket. I have added this policy to my S3 bucket:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicRead",
            "Effect": "Allow",
            "Principal": "*",
            "Action": [
                "s3:GetObject",
                "s3:GetObjectVersion"
            ],
            "Resource": "arn:aws:s3:::<mybucket>/*"
        }
    ]
}

I have made it public as well as Enabled the Static website hosting. I have also set the Default Object to be index.html in Cloudfront.

So what's happening is when I go to my domain, the homepage loads and as long as I click through the links I can reach the page. But as soon as I hit refresh, I get the S3 AccessDenied message. My folder structure is like this:

- /index.html

- /articles
-- index.html

-- /article1
---- /index.html

-- /article2
---- /index.html
.
.
.

Basically every path has its own index.html (common setup with NextJS). I read about a 404 issue also setup a 404 error page as mentioned in this question about 404. However it hasn't solved the problem.

I then tried access my site directly through the S3 origin URL and everything works as expected including the page refresh. So, I am thinking something between the mapping of my domain and S3 origin is not working but I am not sure what is it. Is it on Cloudfront or S3 policy or something else.

Please advice.

Blueboye
  • 1,217
  • 3
  • 22
  • 42
  • Did you ever figure this out? Facing the same issue. – a5af Oct 22 '21 at 12:36
  • Nope. I am just a bunch of things myself now. If I find a solution, will post here. – Blueboye Oct 22 '21 at 16:02
  • @Asaf I was able to get this working. Here's the comment that helped me https://stackoverflow.com/questions/69776999/how-to-setup-cloudfront-s3-to-point-to-index-html-for-every-route/69779378?noredirect=1#comment123365703_69779378. I also added my follow-up comment as well. – Blueboye Nov 01 '21 at 23:02

2 Answers2

0

There's a workaround using Cloudfront functions.

For example you have a Next.js blog housed inside ./pages/blog/[slug].tsx and you want to access it directly via https://example.com/blog so that it also works on refresh.

You have to redirect requests from /blog to /blog.html

Add this as a Viewer Request function in the distribution's default Behavior.

function handler(event) {
    var request = event.request;
    var uri = request.uri;
    if (uri !== '' && uri !== '/' && uri.indexOf('.') === -1) {
        request.uri = uri + '.html';
    }
    return request;
}
a5af
  • 2,222
  • 2
  • 13
  • 11
  • I tried this and it didn't help. Just to remind - if I browse the site with on page links then I am able to access all the pages. But if I refresh on a page, I just get issue. – Blueboye Oct 22 '21 at 19:21
  • Ok I read your post again. This is assuming you are building + exporting the static files to an s3 folder. My directory structure looks different than yours. My export has a folder /blog and a file blog.html. Make sure you have that structure and that your config is right. I verified with multiple routes. You can see it in action at https://asophe.com – a5af Oct 22 '21 at 19:48
0

I figured it out. Since nobody was able to answer it I thought of putting what helped me. I have my website hosted on S3 with Static hosting enabled. I copied the origin url from there (without the http:// part). I then went to cloudfront and while setting up the origin, I pasted the S3 static URL (without the http:// part). DO NO PICK THE ORIGIN FROM THE DROPDOWN if you are hosting a static site. The dropdown list points to the REST API endpoints of S3 and that doesn't work in this case. More info here: https://aws.amazon.com/premiumsupport/knowledge-center/cloudfront-serve-static-website/

Blueboye
  • 1,217
  • 3
  • 22
  • 42
  • You copy the bucket website endpoint from S3 bucket properties and use it as the Cloudfront origin's domain? https://prnt.sc/1y7uzsq They are identical for me and makes no diff. there's even a simpler function that so far has performed well. function handler(event) { var request = event.request; var uri = request.uri; if (uri !== '' && uri !== '/' && uri.indexOf('.') === -1) { request.uri = uri + '.html'; } return request; } – a5af Nov 03 '21 at 00:09