Table of contents
Introduction
In this easy-to-follow guide, I will show you how to put your static website on the internet using Amazon's S3 and CloudFront. We'll keep things secure, sticking to a blend of best practices and AWS recommendations. We'll cover the basics and also get into some of the details, making it simple for you to host your website. Let's dive in!
How to host a static website in a secure way
In order to finish this tutorial, we need to create an S3 bucket and a CloudFront distribution. We will also explore the bucket policies and Origin Access Control (OAC). Once you're done with the tutorial, deleting these resources is a good idea to avoid unnecessary AWS charges.
Step 1: Create static website
To host a static website, we need to do a few things before we can get started. We must create it first. Don't worry. Creating a static site can be complicated, but we'll keep things simple.
To begin, we'll start with some basic HTML. We don't want to go into too much detail at this point. Let's focus on just a few files that are essential for now.
index.html
<!DOCTYPE html>
<html lang=en>
<head>
<meta charset=utf-8>
<title>index</title>
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>
403.html
<!DOCTYPE html>
<html lang=en>
<head>
<meta charset=utf-8>
<title>403</title>
</head>
<body>
<h1>403</h1>
</body>
</html>
404.html
<!DOCTYPE html>
<html lang=en>
<head>
<meta charset=utf-8>
<title>404</title>
</head>
<body>
<h1>404</h1>
</body>
</html>
Step 2: Create S3 bucket
Let's begin by navigating to the AWS Management Console. Take advantage of the search box positioned at the top of the screen for a faster route. By typing in "S3", you can quickly locate the S3 service amidst the numerous services AWS offers.
Before we delve into creating a new S3 bucket, it's essential to remember a couple of crucial points:
- Each S3 bucket must be created in a specific geographical region. This region can be chosen based on factors such as data governance requirements, proximity to the majority of your users, or cost.
- Each bucket name must be globally unique across all existing bucket names in Amazon S3. This is because the bucket namespace is shared by all AWS accounts worldwide. Therefore, it's a good idea to devise a unique name that relates to its purpose.
In this walkthrough, I've opted for the name "one-more-secure-website". This name encapsulates the purpose of our bucket - to hold assets for a secure website - and also adheres to the requirement of global uniqueness. Now, we're ready to create our S3 bucket using this name.
You can now adjust various settings, including versioning, server-side encryption, and access permissions. However, you can leave these settings at their default values for this tutorial. Remember, these configurations can be modified later if required.
Once you're satisfied with the settings, finalize the process by clicking on the "Create bucket" button at the bottom of the page. Your new bucket should now be successfully created in your designated AWS region.
Step 3: Upload our website to S3
We need to move some files to a place called an S3 bucket. You can do this two ways: using the AWS Management Console or running commands from your computer using CLI or Command-Line Interface.
If you're okay with typing commands, it's pretty easy. Keep in mind that you need to install the AWS CLI in order to use it. For example, if you have a file called "index.html" and you want to put it in your bucket, you'd type something like this:
aws s3 cp index.html s3://{bucket}/index.html
Step 4: Create CloudFront Distribution
This is the most exciting part. You might have noticed that we haven't made any changes to the S3 settings, yet we still want to host a static website. The reason is that CloudFront has all the necessary features to accomplish that.
Open up the AWS console, the control panel for all Amazon's tools. Type "CloudFront" in the search box on top. It'll take you right to the CloudFront tool.
There's a button that says "Create a CloudFront distribution". Click it. This will start the process of setting up how your website data gets sent out.
You'll be asked to select your "origin domain". That's where your website data is coming from - in our case, it's our S3 bucket, the storage space we mentioned earlier.
Look for the "Origin access control settings" area. Go for the "Origin access control settings (recommended)" option and click "Create control setting". It's okay to stick with what's already there, no need to change anything. Then click "Create".
Next, we have to sort out the "Default cache behavior". This is how CloudFront stores and sends your website data. Make sure you change "Viewer protocol policy" to "Redirect HTTP to HTTPS". That's just a fancy way of saying it makes sure anyone visiting your site has a secure connection. Leave everything else as it is.
You'll see a "Web Application Firewall (WAF)" section. We're going to skip it, so select "Do not enable security protections".
Almost there! In the "Settings" part at the bottom, make sure the "Default root object" says "index.html". That's just telling CloudFront what to show when someone visits your website.
To finish off, scroll down and click "Create distribution". And there you go! You've set up how your website gets sent to viewers with CloudFront.
Step 5: Update bucket policy
After setting things up, you'll get two messages from AWS. The first one basically says, "Good job! You've created the distribution successfully!" The second one suggests you update your S3 bucket policy, which is like a set of rules for your S3 bucket. This update is needed so CloudFront can read what's in your S3 bucket.
Here's how to do that:
- Look for and click on the "Copy Policy" button, then click on the "Go to S3 bucket permissions to update policy" button. When you click this, it'll take you directly to your S3 bucket's permissions tab.
- Find the "Bucket Policy" section and click "Edit". You'll see a field where you can paste the policy you got earlier.
- After inserting the policy, hit "Save changes" to lock in these new rules.
Once that's done, you'll have to wait a bit. The CloudFront distribution is getting ready, which is like preparing your content for delivery. You've created a strong base for hosting a safe, static site.
Step 6: Let’s check our site
To check out the site we've set up, copy the distribution domain we've given and put it into browser's address bar. Upon opening it, you should see our index page.
You can also try typing in the address without the "https://" part at the beginning, just using "http://" instead. If you do this, don't worry, CloudFront will automatically guide you to the secure version of the site (the one starting with "https://"). You might notice a message saying "301 Moved Permanently", that just means CloudFront moved you to the secure page, which is a good thing!
Step 7: Create custom error documents
Imagine you've got a bucket and it only contains three files: an index, a "403" item, and a "404" item. Now, pretend you're looking for something that isn't there, like a document called "another.html". You'd probably expect to be told, "Sorry, can't find that" – or in internet language, you'd expect a '404 error'. Let's check if that's what actually happens.
Oops! Instead of a simple "can't find that" message, we get a weird XML document and a 403 error. A bit strange, huh? You'd think we'd get a 404 error for something missing, not a 403 error. But let's not worry about that right now. Let's focus on making this whole thing less confusing for our users.
First, click on the tab that says "Error Pages". Then select the option that says "Create custom error response", and fill in the information for the 403 error. Hit the Save button when you're done.
Now, try to open "another.html" again. This time, you should see our custom error page instead of that strange XML. Much better, right?
Step 8: Get real 404
Ever wondered why you sometimes get a 403 error from S3 when a file isn't found? It's because of security reasons.
Amazon S3 gives you an "AccessDenied" error when you ask for a file that doesn't exist, and you don't have the permission to see all the files in that bucket. It's a neat way of keeping things private, as it doesn't let anyone know if the file you're looking for actually exists or not.
So, what if we allow CloudFront to have the "s3:ListBucket" permission? This lets it see all the files in the bucket. Here's how you do it:
- Go to the permissions tab of the S3 bucket.
- Find the statement that you pasted previously and copy it.
- Please make a copy of that statement, but change it slightly. First, change the action to allow "s3:ListBucket". Then, make sure you remove "/*" from the end of the resource name. This new permission should be given to the bucket itself, not its contents.
Original policy:
{
"Version": "2008-10-17",
"Id": "PolicyForCloudFrontPrivateContent",
"Statement": [
{
"Sid": "AllowCloudFrontServicePrincipal",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::one-more-secure-website/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::{account_number}:distribution/E3QFHDB3Z8A00A"
}
}
}
]
}
Modified version:
{
"Version": "2008-10-17",
"Id": "PolicyForCloudFrontPrivateContent",
"Statement": [
{
"Sid": "AllowCloudFrontServicePrincipal",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::one-more-secure-website/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::{account_number}:distribution/E3QFHDB3Z8A00A"
}
}
}, {
"Sid": "AllowCloudFrontServicePrincipal",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::one-more-secure-website",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::{account_number}:distribution/E3QFHDB3Z8A00A"
}
}
}
]
}
Once you've done that and refresh the page, you'll see a different error message - "NoSuchKey". This means that CloudFront can now tell us when the file we're looking for isn't in our bucket.
To finish things off, let's add another custom error page for when a 404 error occurs. Once you've done that and refresh the page, you'll see our custom HTML message instead of the standard error message.
Lessons Learned
I hope you've found this article about hosting a static website using S3 and CloudFront helpful and perhaps even learned something extra. Let's sum it all up:
- You now have the skills to host a website securely without leaning on the S3 static website feature and making a bucket public.
- Every architectural choice has its pros and cons. Navigating through the world of AWS, you might find many paths leading to the same destination. The obvious path isn't always the wisest.
- In this tutorial, we've crafted a simple infrastructure. While it doesn't cover all the aspects of a real-world project, like versioning, logs, or complex topics such as CORS, it gives you a solid foundation to build upon.
I hope you enjoyed this journey with me. Feel free to share it, leave your thoughts, or ask questions if you found it helpful. Let's keep the conversation going. Until next time, happy coding!
Top comments (0)