The tempting approach is just to use a publicly accessible bucket in “website mode” for a website (since the website itself will also be public), and then use Cloudfront with the bucket’s website URL as the origin, but this feels lazy. Instead, use a private bucket and Cloudfront with OAC to securely access and serve content from the private bucket.
Set up a bucket policy
First, set up a bucket policy for the bucket, referencing the AWS account ID and preferred Cloudfront distribution ID (the below comes directly from the link above):
{
"Version": "2012-10-17",
"Statement": {
"Sid": "AllowCloudFrontServicePrincipalReadOnly",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::<S3 bucket name>/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::<AWS account ID>:distribution/<CloudFront distribution ID>"
}
}
}
}
(Be sure to replace <S3 bucket name>
, <AWS account ID>
, and <CloudFront distribution ID>
with the appropriate values.)
Configure the Cloudfront distribution
In the Cloudfront distribution, make sure your origin references the bucket itself, and NOT the website URL (e.g. it’ll be of the form BUCKET_NAME.s3.REGION.amazonaws.com
).
In the “Origin Access” section select “Origin access control settings” and then click the “Create new OAC” button. Accept the defaults (i.e. “Sign requests”) and then create it.
Default/error pages for SPA
If you’re hosting an SPA (and want to route all requests through to your /index.html
), also do the following.
In the Cloudfront distribution, go to the “Error pages” tab and add a new error page with the following settings:
- HTTP error code: 403 (Forbidden)
- Customize error response: Yes
- Response page path: /index.html
- HTTP response code: 200