Search code examples
amazon-web-servicesvue.jsamazon-s3amazon-cloudfrontamazon-route53

"The specified key does not exist" for VueJS app deployed on deployed on S3 with CloudFront


I have deployed a VueJS app with S3 and CloudFront using Route53. It seemed like everything was working fine. I'm able to visit the site at https://my-domain.com, and I can navigate to different routes that I have set up with Vue router. However, when I try to access https://my-domain.com/about directly, I see the following error:

This XML file does not appear to have any style information associated with it. The document tree is shown below.
<Error>
<link type="text/css" id="dark-mode" rel="stylesheet" href=""/>
<style type="text/css" id="dark-mode-custom-style"/>
<Code>NoSuchKey</Code>
<Message>The specified key does not exist.</Message>
<Key>about</Key>
<RequestId>8371CJFJ48JM68239</RequestId>
<HostId>
/fQp7V6SuN0eDPgZpTroQrrxmfVQJTjXtroij56OIJONB56048OIaZDa4snkjc/Ygr/oZu0=
</HostId>
</Error>

Here are the settings for my AWS resources:

S3 Bucket

Properties

All properties are disabled (I don't have static website hosting set since I'm using https)

Permissions (Public)

Public Access Settings

All four options are set to false

Access Control List

Public Access: everyone can read and list objects

Bucket Policy

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadForGetBucketObjects",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::mybucketname.com/*"
        }
    ]
}

CORS configuration

Nothing is set here

Route53

I have a domain that has a hosted zone with 5 records:

  • mydomain.com: A Record; Points to CloudFront distribution

  • Default NS and SOA records that I have not changed

  • *.mydomain.com: A record; Also point to CloudFront distribution for frontend subdomains

  • api.mydomain.com: A record; Points to an ALB for backend API service

CloudFront

Here are the General settings for my CloudFront distribution:

Distribution ID: 12356OIJSGSU9I
ARN: arn:aws:cloudfront::123456789012:distribution/ABCD1234
Log Prefix: -
Delivery Method: Web
Cookie Logging: Off
Distribution Status: Deployed
Comment: -
Price Class: Use All Edge Locations (Best Performance)
AWS WAF Web ACL: -
State: Enabled
Alternate Domain Names (CNAMEs):
*.mydomain.com
mydomain.com
SSL Certificate: mydomain.com (abc1234-1234-1234-1234-abcd1234)
Domain Name: abcd1234.cloudfront.net
Custom SSL Client Support: Only Clients that Support Server Name Indication (SNI)
Security Policy: TLSv1.1_2016
Supported HTTP Versions: HTTP/2, HTTP/1.1, HTTP/1.0
IPv6: Enabled
Default Root Object: index.html
Last Modified: 2019-02-19 11:45 UTC-5
Log Bucket: -

I don't have any origin groups set up. I'm not sure if I need this but it sounds like it could help solve this issue.

I have also heard of AWS Amplify (https://console.aws.amazon.com/amplify/).

What settings can I change so that I can have non-root requests to my domain be routed to the VueJS app?


Solution

  • This is a typical issue with SPAs, because those routes like /dashboard are not real physical routes on the server. To fix this, just open your CloudFront distribution, go to the "Error Pages" tab, and create a Custom Error Response with the following settings:

    enter image description here

    This is essentially telling CloudFront to ignore a 404 error and just return an HTTP 200 response, and point to /index.html. Your SPA will handle any "page not found" errors internally via Vue Router. This might help with that.