Introduction to Terraform to Host a Static Webpage
Created on August 13, 2023
Written by Some author
Read time: 4 minutes
Summary: In this blog post, we will dive into how we can set up terraform for static website deployment.
Introduction
Setting up a static
website on AWS can be a straightforward process when using Terraform to manage
your infrastructure. In this guide, we'll walk you through the steps required
to configure and deploy a static website on AWS using Terraform. We'll cover topics
such as creating an S3 bucket, setting up a Route53 domain, configuring SSL
certificates, and deploying your website.
By the end of this
guide, you'll have a fully functional static website hosted on AWS that is
accessible via your own custom domain name with SSL encryption provided by AWS
Certificate Management. This guide assumes a basic understanding of AWS
services, Terraform, and web development. Let's get started!
Step 1: Creating an S3 Bucket for Website Hosting
To start, you'll need
an AWS account and the AWS CLI installed. Begin by configuring your Terraform
project. In your Terraform configuration file, specify the creation of an S3
bucket for website hosting. You can use a configuration like this:
resource "aws_s3_bucket" "static_site" {
bucket = "${var.bucket_name}"
website {
index_document
= "index.html"
error_document
= "error.html"
}
}
resource "aws_s3_bucket_website_configuration" "static_site" {
bucket =
aws_s3_bucket.static_site.id
index_document
{
suffix = "index.html"
}
error_document
{
key = "error.html"
}
}
resource "aws_s3_bucket_public_access_block" "s3_bucket_public_access_block" {
bucket =
aws_s3_bucket.static_site.id
block_public_acls = false
block_public_policy = false
ignore_public_acls = false
restrict_public_buckets
= false
}
resource "aws_s3_bucket_ownership_controls" "s3_bucket_acl_ownership" {
bucket =
aws_s3_bucket.static_site.id
rule {
object_ownership
= "BucketOwnerPreferred"
}
depends_on
= [aws_s3_bucket_public_access_block.s3_bucket_public_access_block]
}
resource "aws_s3_bucket_acl" "s3_bucket_acl" {
bucket = aws_s3_bucket.static_site.id
acl = "public-read"
depends_on
= [aws_s3_bucket_ownership_controls.s3_bucket_acl_ownership]
}
resource "aws_s3_bucket_policy" "static_site" {
bucket =
aws_s3_bucket.static_site.id
policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Principal = "*",
Action = [
"s3:*"
]
Effect = "Allow",
Resource = [
"${aws_s3_bucket.static_site.arn}",
"${aws_s3_bucket.static_site.arn}/*"
],
},
{
Sid = "PublicReadGetObject",
Principal = "*",
Action = [
"s3:GetObject"
],
Effect = "Allow",
Resource = [
"${aws_s3_bucket.static_site.arn}",
"${aws_s3_bucket.static_site.arn}/*"
],
}
],
})
depends_on
= [aws_s3_bucket_public_access_block.s3_bucket_public_access_block]
}
Step 2:
Configuring Cloud Front for Content Delivery
After creating the S3
bucket for website hosting, you'll need to configure CloudFront for content
delivery. Start by creating a new CloudFront distribution in your Terraform
configuration file. You can use a configuration like this:
resource "aws_cloudfront_distribution" "s3_distribution" {
origin {
domain_name
= aws_s3_bucket.static_site.bucket_regional_domain_name
origin_id = "S3-${var.bucket_name}" #
Provide a unique origin ID
}
enabled = true
comment = "CloudFront
distribution for S3-based static site"
default_root_object
= "index.html"
default_cache_behavior
{
allowed_methods = ["GET", "HEAD"]
cached_methods = ["GET", "HEAD"]
target_origin_id
= "S3-${var.bucket_name}" # Use
the same origin ID as defined above
forwarded_values
{
query_string
= false
cookies {
forward = "none"
}
}
viewer_protocol_policy
= "redirect-to-https"
min_ttl = 0
default_ttl = 3600
max_ttl = 86400
}
price_class
= "PriceClass_200" # Use
appropriate price class
restrictions {
geo_restriction
{
restriction_type
= "none"
}
}
aliases = [ "${var.custom_domain}" ]
viewer_certificate
{
acm_certificate_arn = "${aws_acm_certificate.sample_cert.arn}"
ssl_support_method = "sni-only"
minimum_protocol_version
= "TLSv1.1_2016"
}
}
This configuration sets up CloudFront to use the S3 bucket as
its origin, with the default cache behavior set to redirect HTTP traffic to
HTTPS and a minimum time-to-live of 0 seconds. Additionally, it sets up SSL
encryption using the SSL certificate created in the next step.
Step 3: Creating an SSL Certificate
To enable SSL
encryption for your static website, you'll need to create an SSL certificate
using AWS Certificate Manager. In your Terraform configuration file, add a
resource to create the certificate. You can use a configuration like this:
resource "aws_acm_certificate"
"example" {
domain_name = var.domain_name
validation_method
= "DNS"
}
resource "aws_route53_record" "cert_validation" {
zone_id
= aws_route53_zone.main.zone_id
name = aws_acm_certificate.example.domain_validation_options.0.resource_record_name
type = aws_acm_certificate.example.domain_validation_options.0.resource_record_type
records =
[aws_acm_certificate.example.domain_validation_options.0.resource_record_value]
ttl = "60"
}
This configuration creates an SSL certificate for your domain
name using DNS validation.
With these steps, you
now have a fully functional static website hosted on AWS, with SSL encryption
provided by AWS Certificate Management and content delivery through CloudFront.
Step 4: Setting up a Route53 Domain
For a personalized
domain name, set up a Route53 hosted zone and configure a record that points to
your S3 bucket. The Terraform configuration for the Route53 record might look
like this:
resource "aws_route53_zone" "my_domain" {
name = "${var.custom_domain}"
}
resource "aws_route53_record" "cloudfront_a_record" {
zone_id
= aws_route53_zone.my_domain.zone_id
name = "${var.custom_domain}"
type = "A"
alias {
name = aws_cloudfront_distribution.s3_distribution.domain_name
zone_id = aws_cloudfront_distribution.s3_distribution.hosted_zone_id
evaluate_target_health
= false
}
}
resource "aws_route53_record" "validation_record" {
for_each
= {
for dvo
in aws_acm_certificate.sample_cert.domain_validation_options
: dvo.domain_name => dvo
}
name = each.value.resource_record_name
type = each.value.resource_record_type
zone_id
= aws_route53_zone.my_domain.zone_id
records = [each.value.resource_record_value]
ttl = "300"
}
Step 5:
Deploying Your Website
Now you can upload
your website files to the S3 bucket using the AWS CLI or the AWS Management
Console. Once uploaded, your website will be accessible via the CloudFront
distribution and your custom domain name. Any changes you make to your website
can be redeployed simply by uploading the updated files to the S3 bucket.
Congratulations, you now have a fully functional static website hosted on AWS
with SSL encryption and content delivery through CloudFront!
Notice that you also
need to keep in mind of updating your domain's DNS records to point to the
CloudFront distribution. Otherwise, there will not be anything new show up via
your domain.
To deploy via
terraform, simply run
terraform init
terraform apply
These commands initialize and apply your Terraform
configuration, creating your S3 bucket, CloudFront distribution, and Route53
record. Upon completion, your website will be hosted on AWS and available
through your custom domain name.