Introduction
In this post, we’ll walk through the process of hosting a static website on AWS S3 using Terraform. By the end, you’ll have a static website hosted in an S3 bucket, ready to be accessed by anyone on the web.
This is the first part of a three-part series on hosting a static website in AWS. Here, we’ll focus on provisioning and configuring an S3 bucket to host static files for a simple website. In later parts, we’ll enhance this setup by distributing the website securely via CloudFront and configuring DNS with Route 53.
Why choose S3 for Static Site hosting?
S3 is an ideal choice for hosting static websites, and here’s why:
- Cost-Effective: S3 offers a pay-as-you-go model, making it highly affordable, especially for small sites with limited traffic.
- High Availability and Durability: S3 guarantees 99.999999999% durability and is highly available across multiple regions, ensuring your site stays up and running.
- Scalability: S3 can automatically handle traffic spikes without any additional configuration or management, making it ideal for sites with unpredictable traffic.
- Global Reach via CloudFront Integration: By integrating with Amazon CloudFront, you can distribute your website to edge locations globally, ensuring faster load times for users.
- No Maintenance: AWS manages the infrastructure, allowing you to focus on content rather than server management.
Why not to choose S3 for Static Site hosting?
While S3 is a great solution for many use cases, there are a few limitations:
- Limited to Static Content: S3 only supports static content. It cannot process dynamic requests, so websites requiring server-side logic will need additional services.
- Custom Domain Complexity: Setting up a custom domain and SSL encryption via S3 requires additional services like Route 53 and CloudFront, which can be complex for beginners.
Terraform Configuration for S3 Static Site Hosting
Let’s walk through the steps to provision and configure an S3 bucket for static website hosting using Terraform.
Step 1: Create the bucket
The first step is to define the S3 bucket that will store and serve your static website files.
# s3.tf
resource "aws_s3_bucket" "site" {
bucket = var.bucket_name
force_destroy = true
}
- bucket: The name of your S3 bucket.
- force_destroy: Setting this to true ensures that the bucket can be destroyed even if it contains objects.
Step 2: Configure public access
To ensure that the bucket’s contents are accessible by the public (for a static website), we configure public access settings.
# s3.tf
resource "aws_s3_bucket_public_access_block" "enable_public_access" {
bucket = aws_s3_bucket.site.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = false
}
This configuration ensures that,
- block_public_acls: Application of Public ACLs to the bucket and its objects are denied. Any attempt to make objects public using an ACL will be denied.
- block_public_policy: Attaching public bucket policies are blocked.
- ignore_public_acls: Any public ACLs already attached to objects in the bucket are ignored, effectively overriding and preventing any public access granted via ACLs.
- restrict_public_buckets: the bucket can still be made publicly accessible by users who have appropriate permissions. It doesn’t prevent all public access; it only blocks public access using ACLs and policies. When set to
true
, it would prevent the bucket from being publicly accessible at all, even if someone tries to make it public through the AWS console or API.
Step 3: Create the bucket policy
Now, we create a policy that allows public users to retrieve objects from the bucket.
# s3.tf
resource "aws_s3_bucket_policy" "bucket_policy" {
bucket = aws_s3_bucket.site.id
policy = data.aws_iam_policy_document.s3_public_access_policy.json
depends_on = [aws_s3_bucket_public_access_block.enable_public_access]
}
data "aws_iam_policy_document" "s3_public_access_policy" {
statement {
sid = "PublicReadGetObject"
effect = "Allow"
principals {
type = "AWS"
identifiers = ["*"]
}
actions = [
"s3:GetObject"
]
resources = [
"${aws_s3_bucket.site.arn}/*",
]
}
}
This policy grants public read access to all objects within the bucket, which is essential for serving static website files.
Step 4: Enable and configure static hosting
In this step, we configure the S3 bucket for static website hosting.
# s3.tf
resource "aws_s3_bucket_website_configuration" "website_config" {
bucket = aws_s3_bucket.site.id
index_document {
suffix = var.index_document_suffix
}
error_document {
key = var.error_document
}
Here, we configure:
- index_document: The default file to load when accessing a directory (e.g.,
index.html
). - error_document: The file to serve when a user navigates to a non-existent page (e.g.,
404.html
).
Step 5: Provide values for the variables
Finally, let’s define the variables used in the Terraform configuration.
# variables.tf
variable "bucket_name" {
description = "The name of the S3 bucket"
type = string
}
variable "index_document_suffix" {
description = "The index document suffix"
type = string
default = "index.html"
}
variable "error_document" {
description = "The error document"
type = string
default = "404.html"
}
Deploying the Static Website
Once the infrastructure is provisioned, the next step is to upload the static content to the S3 bucket. You can manually copy files or use automated CI/CD pipelines for deployment.
Accessing the static website
Once the website files are uploaded to the S3 bucket, you can access your website using the S3 generated public URL. You can find this URL in the Static Website Hosting section of your S3 bucket’s properties.
Limitations of Hosting a Static Site Directly from S3
Clicking on the link will get you to the static site that is being hosted. An image of this shown below.
As you maybe able to see,
- No HTTPS: S3 does not support HTTPS for websites hosted on the bucket’s default URL. As a result, your site will be served over HTTP only, which is not secure.
- Direct Access to Bucket Contents: Users can access all files in your bucket if they have the direct path, which might expose sensitive content unintentionally.
- No CDN: Without CloudFront, there’s no Content Delivery Network (CDN) in place, which can lead to slower load times for users far from the bucket’s region.
Conclusion
Hosting a static website on AWS S3 using Terraform is an easy and cost-effective solution for simple websites that don’t require server-side processing. While it has several advantages like scalability, high availability, and low costs, there are some limitations, especially when it comes to security and global performance.
In the next part of the series, we will overcome some of these limitations by configuring Amazon CloudFront to securely distribute the static website with HTTPS, faster content delivery, and improved caching.
By combining S3 with CloudFront and Route 53, you’ll have a powerful, secure, and globally distributed solution for your static website hosting. Stay tuned!