
Posted on • Originally published atbahaanoah.com on
Static Website Infrastructure on AWS with Terraform
As a software engineer, you likely understand the importance of automation and reproducibility in your workflow. One way to achieve this is by usingTerraform, it was one of the technologies that I learned in 2022 and since then it has been the goto tool for me for any infrastructure work. In this post, I'll take you through how to use Terraform to create the necessary resources for hosting a static website on AWS, making your life a lot easier.
Required Utilities
Install these tools before proceeding:
- AWS CLI
- Terraform -Install Terraform
Configure the AWS CLI with a user that has sufficient privileges to create all the resources we will be using in this blog, and it's always a best practice to give least privileges rather than an admin access. Verify that the CLI can authenticate properly by runningaws sts get-caller-identity
.
Overview
We will utilize the following services to create static website hosting infrastructure:
- AWS S3 Bucket as the hosting and storage for the website files and rearouses.
- Route 53 as DNS resolver.
- AWS Certificate Manager for securing the website and managing the ssl certificate.
- Amazon CloudFront to optimize the performance and improve security.
Using all of these services should be free of charge except for Route 53 will charge you around 00.51$ and in general if you are not in thefree tier you will be charged around 3$~4$ per month based on the traffic you are getting.
Setting Up Variables
After setting up the tools, let's create the following environment variables to store commonly used values. First things first we will create ourmain.tf
file and place the following in it.
terraform { required_version = "~> 1.0" required_providers { aws = { source = "hashicorp/aws" version = "~> 4.0" } }}locals { # change that to your domain name domain_name = "bahaanoah.com" # I like to tag everything that's being created by terraform tags = { "terraform" = true }}# I will be using UAE region but feel free to use whichever you preferprovider "aws" { region = "me-central-1"}
Create S3 Bucket
At this step we are going to create S3 bucket with public access and add website configuration to it usingResource: aws_s3_bucket.
Creates3.tf
file and add the following code:
resource "aws_s3_bucket" "this" { bucket = local.domain_name tags = local.tags force_destroy = true}resource "aws_s3_bucket_policy" "allow_public_access" { bucket = aws_s3_bucket.this.id policy = jsonencode( { Statement = [ { Action = "s3:GetObject" Effect = "Allow" Principal = "*" Resource = "arn:aws:s3:::${local.domain_name}/*" Sid = "Stmt1661600983594" }, ] Version = "2012-10-17" } )}resource "aws_s3_bucket_versioning" "this" { bucket = aws_s3_bucket.this.id versioning_configuration { status = "Disabled" }}resource "aws_s3_bucket_website_configuration" "this" { bucket = aws_s3_bucket.this.bucket index_document { suffix = "index.html" } error_document { key = "404/index.html" }}
Once done go ahead and apply what we have created so far.
terraform initterraform apply
Create Route 53 Hosted Zone
At this step will create a hosted zone to manage our dns records usingResource: aws_route53_zone.
Createroute53.tf
file and place the code below:
resource "aws_route53_zone" "primary" { name = local.domain_name tags = local.tags}
Go ahead and apply the changes.
terraform apply
After applying this change you should see a hosted zone with NS and SOA records created in route 53, copy the NS record values and update your domain nameservers, in my case I have my domain registered inGodaddy all I needed to do is change the default nameservers and use custom nameservers the add the NS values from AWS there.
Issue SSL Certificate
We will issue SSL certificate using AWS Certificate Manager withResource: aws_acm_certificate and create some DNS records in route 53 to validate it at this step.
Createacm.tf
file and place the code below:
# if you are using different region from us-east-1 you will need to do that step # because cloudfront only works with certificates issued in us-east-1provider "aws" { alias = "virginia" region = "us-east-1"}resource "aws_acm_certificate" "this" { domain_name = local.domain_name validation_method = "DNS" tags = local.tags lifecycle { create_before_destroy = true } provider = aws.virginia}resource "aws_route53_record" "validation" { for_each = { for dvo in aws_acm_certificate.this.domain_validation_options : dvo.domain_name => { name = dvo.resource_record_name record = dvo.resource_record_value type = dvo.resource_record_type } } allow_overwrite = true name = each.value.name records = [each.value.record] ttl = 60 type = each.value.type zone_id = aws_route53_zone.primary.zone_id provider = aws.virginia depends_on = [ aws_acm_certificate.this, aws_route53_zone.primary ]}
Go ahead and apply the changes.
terraform apply
If you connected your domain to the NS record from previous step it should take a couple of minutes and your certificate status will change to "Issued"
Create CloudFront
At this step we will create CloudFront withResource: aws_cloudfront_distribution and connect it to theS3 Bucket we created earlier, then eventually create an A record in thehosted zone we created that's aliased to this cloudfront distribution.
Createcloudfront.tf
file and place the code below:
resource "aws_cloudfront_distribution" "this" { origin { domain_name = aws_s3_bucket_website_configuration.this.website_endpoint origin_id = aws_s3_bucket_website_configuration.this.website_endpoint connection_attempts = 3 connection_timeout = 10 custom_origin_config { http_port = 80 https_port = 443 origin_keepalive_timeout = 5 origin_protocol_policy = "http-only" origin_read_timeout = 30 origin_ssl_protocols = [ "TLSv1", "TLSv1.1", "TLSv1.2", ] } } enabled = true is_ipv6_enabled = true aliases = [local.domain_name] default_cache_behavior { allowed_methods = ["GET", "HEAD"] cached_methods = ["GET", "HEAD"] target_origin_id = aws_s3_bucket_website_configuration.this.website_endpoint viewer_protocol_policy = "redirect-to-https" compress = true min_ttl = 0 default_ttl = 3600 max_ttl = 86400 smooth_streaming = false forwarded_values { query_string = false cookies { forward = "none" } } } restrictions { geo_restriction { locations = [] restriction_type = "none" } } tags = local.tags viewer_certificate { acm_certificate_arn = aws_acm_certificate.this.arn cloudfront_default_certificate = false minimum_protocol_version = "TLSv1.2_2021" ssl_support_method = "sni-only" } depends_on = [ aws_s3_bucket.this, aws_acm_certificate.this ]}
Go ahead and apply the changes.
terraform apply
Once applied let's create the DNS record, openroute53.tf
file and add the code below:
# update the resource name to your domain nameresource "aws_route53_record" "bahaanoah-com" { name = local.domain_name type = "A" zone_id = aws_route53_zone.primary.zone_id alias { name = aws_cloudfront_distribution.this.domain_name zone_id = aws_cloudfront_distribution.this.hosted_zone_id evaluate_target_health = false }}
Go ahead and apply the changes.
terraform apply
If you reached that point and got everything to be working well done!, you should have your infrastructure up and running, go ahead and upload your website in the S3 bucket we created and check it out.
Cleanup
If you are not going to use it and was just trying and would like to clean up destroy everything to avoid any charges in the future.
terraform destroy
Conclusion
Terraform is a powerful tool for automating the process of creating and managing infrastructure on AWS. By using the services outlined in this post, you can easily set up a secure and performant static website that is easy to maintain and update. However, it is important to keep in mind that this is just the basic setup and there are many other options and features that can be added and configured for different needs and use cases.
As a next step, I would suggest to have a look at thisgithub repository that's containing the code I used to create the Infrastructure for my website it's pretty much the same as we explained with some extra steps for www redirection. I would also recommend having a look atCloudFront Invalidation to manage your cache better and finally if you are working in a team I suggest to have some CI/CD pipeline to automate your infrastructure deployments with some code review process in place, find out more hereRunning Terraform in Automation.
Thanks for reading, I hope this was helpful. Please feel free toreach out if you need more help or have any suggestions.
Top comments(0)
For further actions, you may consider blocking this person and/orreporting abuse