Deploying a Secure Static Website with Amazon S3 and CloudFront
Learn how to deploy a static website using Amazon S3 and Amazon CloudFront. Explore CDN caching, HTTPS, Origin Access Control, security best practices, troubleshooting, and website updates.
Deploying a Secure Static Website with Amazon S3 and CloudFront
Introduction
Deploying a website is one of the first practical projects many cloud computing students build. However, hosting a website is not just about uploading HTML files. A production-ready deployment also needs reliable content delivery, HTTPS, appropriate access controls, and a clear process for updating content.
AWS provides two services that work well together for this purpose: Amazon Simple Storage Service (Amazon S3) and Amazon CloudFront.
Amazon S3 provides durable object storage for website files, while CloudFront distributes content through a global content delivery network (CDN). With Origin Access Control (OAC), we can configure CloudFront to retrieve files from a private S3 bucket without making the bucket publicly accessible.
In this tutorial, we will explore the architecture, deployment workflow, security configuration, caching behaviour, and troubleshooting techniques for a static website hosted on AWS.
1. Understanding the Architecture
Before deploying anything, it is important to understand how the services interact.
Our architecture contains four main components:
- Amazon S3: Stores HTML, CSS, JavaScript, images, and other static assets.
- Amazon CloudFront: Delivers website content from its cache or retrieves it from S3 when necessary.
- Origin Access Control (OAC): Allows CloudFront to access the S3 origin securely while keeping the bucket private.
- AWS Certificate Manager (ACM): Provides TLS certificates for HTTPS when using a custom domain with CloudFront.
The request flow looks like this:
- A visitor opens the website in a browser.
- The browser sends a request to the CloudFront distribution.
- If the requested object is cached at the relevant CloudFront edge location, CloudFront can return the cached response.
- If the object is not cached or needs revalidation, CloudFront retrieves it from the S3 origin.
- CloudFront returns the content to the visitor and may cache it according to the configured cache policy.
This architecture separates storage from content delivery and helps reduce direct exposure of the origin bucket.
2. What You Need Before Starting
You will need:
- An AWS account with permission to create and configure S3 and CloudFront resources.
- A static website containing an
index.htmlfile. - Basic familiarity with the AWS Management Console.
- A small amount of time to wait for the CloudFront distribution to deploy.
You can start with a simple HTML page instead of a full frontend application.
For example, create an
index.html file:1
2
3
4
5
6
7
8
9
10
11
12
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My AWS Website</title>
</head>
<body>
<h1>Hello from AWS!</h1>
<p>This website is delivered using Amazon S3 and CloudFront.</p>
</body>
</html>You can later replace this page with a React build, a portfolio website, or another frontend application that produces static assets.
Remember that this architecture serves static files. Applications that require server-side execution, authentication logic, or database access need additional services.
3. Create an Amazon S3 Bucket
The first step is to create a bucket that will store the website files.
- Open the Amazon S3 console.
- Choose Create bucket.
- Enter a globally unique bucket name.
- Select an AWS Region.
- Keep Block Public Access enabled.
- Create the bucket.
- Open the bucket and upload your
index.htmlfile and other website assets.
For this architecture, you do not need to enable S3 static website hosting. We will use the bucket's regular S3 origin endpoint with CloudFront rather than its website endpoint.
This distinction is important because the regular S3 origin supports the private-bucket access pattern used with Origin Access Control.
Security principle: Do not make the bucket public just to make the website accessible. CloudFront can serve the public website while the underlying S3 bucket remains private.
4. Create a CloudFront Distribution
CloudFront will act as the public entry point for the website.
Follow these steps:
- Open the Amazon CloudFront console.
- Choose Create distribution.
- Select your S3 bucket as the origin.
- Configure Origin Access Control, creating a new OAC if necessary.
- Use the recommended signed-request behaviour for the OAC.
- Configure the default root object as
index.html. - Choose an appropriate viewer protocol policy, such as redirecting HTTP requests to HTTPS.
- Review the remaining settings and create the distribution.
When selecting the origin, use the regular S3 bucket origin rather than an S3 website endpoint. OAC is designed for supported S3 origins, not S3 static website endpoints.
CloudFront distributions take time to deploy. Wait until the distribution status indicates that deployment is complete before testing the website.
5. Configure Origin Access Control
Creating an OAC is only part of the configuration. The S3 bucket must also permit the CloudFront distribution to read the objects.
After configuring the distribution:
- Open the CloudFront distribution.
- Locate the S3 origin and its OAC settings.
- Confirm that the origin is associated with the intended OAC.
- Update the S3 bucket policy to allow the CloudFront service principal to read the website objects.
- Restrict that permission to the specific distribution using the appropriate
AWS:SourceArncondition.
A typical policy structure looks like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowCloudFrontReadOnly",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::YOUR_BUCKET_NAME/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "YOUR_CLOUDFRONT_DISTRIBUTION_ARN"
}
}
}
]
}Replace
YOUR_BUCKET_NAME and YOUR_CLOUDFRONT_DISTRIBUTION_ARN with your actual values before applying the policy.This is an illustrative policy for reading objects through a specific CloudFront distribution. It is not a complete permissions policy for every possible website configuration.
The important details are:
- The permitted action is
s3:GetObject. - The resource is limited to objects in the intended bucket.
- The source condition restricts access to the specified CloudFront distribution.
- Public access does not need to be enabled on the bucket.
If you encounter an Access Denied response, check the bucket policy, OAC configuration, origin selection, and object permissions.
6. Enable HTTPS
HTTPS encrypts traffic between visitors and CloudFront.
CloudFront provides a default distribution domain name, so you can test the site over HTTPS without first purchasing a custom domain.
If you want to use your own domain, such as
www.example.com, you will need to:- Register or configure a domain.
- Request a public certificate using AWS Certificate Manager in the US East (N. Virginia) Region for use with CloudFront.
- Validate ownership of the domain.
- Add the domain as an alternate domain name on the CloudFront distribution.
- Attach the matching certificate.
- Configure DNS records to direct the domain to CloudFront.
The certificate must cover the domain names configured on the distribution.
Once the configuration is complete, visitors can access the website using HTTPS.
7. Understand CloudFront Caching
One of the major advantages of CloudFront is caching.
Without effective caching, repeated requests may require CloudFront to retrieve objects from the S3 origin. With caching, eligible responses can be served directly from CloudFront edge locations.
Caching behaviour depends on the cache policy, object headers, and distribution configuration.
For example, frequently updated HTML files may need a shorter cache lifetime, while versioned JavaScript and CSS assets can often use longer cache lifetimes.
A practical strategy is:
- Use relatively short caching for HTML documents that change frequently.
- Use long caching for versioned assets, such as
app.a1b2c3.js. - Apply suitable
Cache-Controlheaders to uploaded objects. - Use a CloudFront invalidation when you need cached content refreshed before its normal expiry.
Versioned filenames are particularly useful because a new filename represents a new asset, reducing the need to invalidate every cached file after each deployment.
8. Update the Website
Once the website is deployed, publishing a new version is straightforward.
- Update the local website files.
- Upload the changed files to the S3 bucket.
- Confirm that the uploaded objects have the expected content and metadata.
- If required, create a CloudFront invalidation for paths such as
/index.html. - Open the CloudFront URL and verify the updated website.
For a larger project, this process can be automated through a CI/CD pipeline.
For example, a pipeline could build a frontend application, upload its static output to S3, and request a CloudFront invalidation when necessary.
For production deployments, avoid exposing AWS credentials in frontend code or committing long-lived credentials to a source repository. Use an appropriately secured deployment identity with limited permissions.
9. Common Problems and Their Solutions
Problem 1: CloudFront returns Access Denied
Check whether the S3 bucket policy allows the correct CloudFront distribution to read objects. Confirm that OAC is enabled and associated with the origin.
Problem 2: The root URL does not load the website
Verify that the default root object is set to
index.html and that the file exists at the expected location in the bucket.Problem 3: Changes do not appear immediately
CloudFront may still be serving cached content. Check the object's cache headers and distribution cache policy, then invalidate the relevant paths if necessary.
Problem 4: The website works on one URL but not another
Check whether you are using the correct CloudFront domain, custom domain, DNS records, and certificate configuration.
Problem 5: A frontend route returns a 403 or 404
Single-page applications often use client-side routing. A request to a nested route may reach S3 as an object request for a file that does not exist.
Review your CloudFront error handling and application routing strategy. Do not blindly convert every 403 response into a successful HTML response, because this can hide genuine permission errors.
10. Cost and Resource Cleanup
S3 and CloudFront have usage-based pricing. Costs can depend on storage, requests, data transfer, invalidations, and other configuration details.
Before starting, review the current AWS pricing pages for the Regions and features you intend to use.
After testing, remove resources you no longer need, including the CloudFront distribution, test bucket contents, and S3 bucket itself if it was created solely for this tutorial.
A CloudFront distribution may take time to disable before it can be deleted. Follow the console workflow and check that the bucket is empty before attempting to remove it.
Always review your actual resources and billing rather than assuming that a small demonstration will be free.
Conclusion
Amazon S3 and CloudFront provide a practical foundation for hosting and delivering static websites on AWS.
S3 stores the website files, CloudFront distributes them to visitors, and Origin Access Control helps protect the origin bucket. HTTPS, thoughtful cache policies, and controlled deployment permissions make the setup more suitable for real applications.
This architecture is useful for portfolios, documentation sites, landing pages, and static frontend builds.
The larger lesson is that cloud deployment involves more than making an application accessible. Security, performance, maintainability, and cost management should be part of the design from the beginning.
Discussion: If you were deploying your portfolio on AWS, which would you prioritize first: tighter origin security, faster content delivery, or automated deployments?
#amazon-s3 #amazon-cloudfront #aws #cloudcomputing #devops
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article