In this post, I will be guiding you how to setup an Amazon S3 bucket as a static website, then configure CloudFront CDN to serve in front of Amazon S3. Outline is as following:
- Create a S3 Bucket
- Configure Amazon S3 to serve as a static website
- Create Cloudfront distribution.
- Set Route53 records
- Restrict S3 access to Cloudfront
Amazon S3 π
Create an S3 bucket and then follow Amazon S3 bucket properties -> Permissions -> Edit bucket policy and paste the following text.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::www.mysite.com/*"
}
]
}
Amazon S3 bucket properties -> Static Web Hosting, choose Enable website hosting and provide Index Document as index.html. You will see the site url there: www.mysite.com.s3-website-eu-west-1.amazonaws.com. Now upload some file and check if your site is working.
Cloudfront π
Navigate to CloudFront. Click on Create Distribution button. Choose Get Started below Web.
Origin Domain Name: www.mysite.com.s3-website-eu-west-1.amazonaws.com (write the path you see in Amazon S3 bucket properties -> Static Web Hosting -> Endpoint: www.mysite.com.s3-website-eu-west-1.amazonaws.com). You could choose your S3 Bucket here but if you do so, you won’t be able to display subdirectories: http://www.mysite.com/blog/ which contains a index.html. You will have to call index.html explicitly (http://www.mysite.com/blog/index.html).
Origin Path: Empty or /
Origin ID: Enter a descriptive ID for this origin: S3-mysite.com
Compress Objects Automatically: Yes
Price Class: US and Europe
Alternate Domain Names (CNAMEs): Enter the domain names you would like to redirect to Cloudfront, one at each line. If you don’t specify your domains here, you will get an Access Denied error.
cloudfront.mysite.com www.mysite.com mysite.com
Default Root Object: index.html (If you don’t put this, you will get access denied unless you provide full path to the html file.)
Then press Create Distribution. In the distributon list, you will see Domain Name column. We will use the domain name written here (abcdefghi.cloudfront.net) on Route53. It may take some time to see the system has been fully deployed.
Route53 π
Add A record for your Hosted Zone.
- Name: cloudfront.mysite.com.
- Type: A - IPv4 Address
- Alias: Yes.
- Alias Target: abcdefghi.cloudfront.net.
Then press Create. It may take some time until cloudfront.mysite.com is propagated to DNS servers. When Cloudfront is deployed and enabled, Route 53 A records are active, you will see your website on cloudfront.mysite.com
Check if your site is served through CloudFront:
curl -svo /dev/null http://www.mysite.com
Check if you can access subdirectories like http://cloudfront.mysite.com/blog/ after placing an index.html in it.
If it works, create a similar A Record for www.mysite.com and mysite.com
Going Back to S3 π
If you wish to stop using Cloudfront and go back to S3 serving, update www.mysite.com A record alias. Delete the URL written there, then a list will appear. Choose your S3 bucket (www.mysite.com) and Save Record Set.
Restricting S3 access to Cloudfront π
You may want to allow only CloudFront to access your S3 Bucket so that DDoS attackers can’t attack on your S3 bucket’s web endpoint, causing you thousands of dollars.
Cloudfront π
Click on your distribution, navigate to Origins tab, choose origin in the list and press Edit. Add a new header on Origin Custom Headers.
- Header Name: User-Agent
- Value: abcdefghi123 (replace this with something random, this will be the password)
Now Amazon Cloudfront will add User-Agent: abcdefghi123 on each request it is forwarding to Amazon S3.
Amazon S3 π
On S3 permissions, click Bucket Policy Editor and fill is as the following. This will limit the resources to AWS network and allow only requests from User Agent “abcdefghi123”. Only the ones who provide this password through User-Agent will be able to access the bucket.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::www.mysite.com/*",
"Condition": {
"StringEqualsIgnoreCase": {
"aws:UserAgent": "abcdefghi123"
}
}
}
]
}