In this example, I am using Cloudflare as my DNS provider, Amazon s3 for the static site hosting, and Cloudfront for https.
Create the S3 Bucket
The first thing you need to do is create an AWS s3 bucket, and a zone in Cloudflare
resource "cloudflare_zone" "jasonraimondi_com" {
zone = "jasonraimondi.com"
}
resource "aws_s3_bucket" "static_jasonraimondi_com" {
bucket = "examplebucket"
policy = file("jasonraimondi_com_bucket_policy.json")
region = "us-east-1"
website {
error_document = "404.html"
index_document = "index.html"
}
}
Add content to the bucket
Seed a index.html
file into your bucket.
mkdir site
echo "<h1>Hello crazy world!</h1>" > site/index.html
aws s3 sync site s3://examplebucket
Create a cloudfront distribution for the s3 bucket
You need to create both an aws_cloudfront_origin_access_identity and an aws_cloudfront_distribution
resource "aws_cloudfront_origin_access_identity" "jasonraimondi_com" {
comment = "access-identity-${aws_s3_bucket.static_jasonraimondi_com.bucket_domain_name}"
}
resource "aws_cloudfront_distribution" "jasonraimondi_com" {
aliases = [
aws_acm_certificate.jasonraimondi_com.domain_name,
]
comment = "jasonraimondi.com static site"
origin {
domain_name = aws_s3_bucket.static_jasonraimondi_com.bucket_domain_name
origin_id = "S3-${aws_s3_bucket.static_jasonraimondi_com.id}"
s3_origin_config {
origin_access_identity = aws_cloudfront_origin_access_identity.jasonraimondi_com.cloudfront_access_identity_path
}
}
enabled = true
is_ipv6_enabled = true
default_root_object = "index.html"
default_cache_behavior {
allowed_methods = ["GET", "HEAD"]
cached_methods = ["GET", "HEAD"]
target_origin_id = "S3-${aws_s3_bucket.static_jasonraimondi_com.id}"
forwarded_values {
query_string = false
cookies {
forward = "none"
}
}
viewer_protocol_policy = "redirect-to-https"
min_ttl = 0
default_ttl = 86400
max_ttl = 31536000
}
restrictions {
geo_restriction {
restriction_type = "none"
locations = []
}
}
viewer_certificate {
acm_certificate_arn = aws_acm_certificate.jasonraimondi_com.arn
cloudfront_default_certificate = false
minimum_protocol_version = "TLSv1.2_2018"
ssl_support_method = "sni-only"
}
custom_error_response {
error_caching_min_ttl = 300
error_code = 400
response_code = 404
response_page_path = "/404.html"
}
custom_error_response {
error_caching_min_ttl = 300
error_code = 403
response_code = 404
response_page_path = "/404.html"
}
}
Enable https using Amazon Certificate Manager
We will need to create an using the Amazon Certificate Manager provider. We are also going to need to add a cloudflare_record DNS record that will allow ACM to sign the certificate.
Create an aws_acm_certificate using Amazon Certificate Manager and add with appropriate Cloudflare records.
resource "aws_acm_certificate" "jasonraimondi_com" {
provider = aws.east_1
domain_name = "jasonraimondi.com"
validation_method = "DNS"
}
resource "cloudflare_record" "jasonraimondi_com" {
zone_id = cloudflare_zone.jasonraimondi_com.id
name = aws_acm_certificate.jasonraimondi_com.domain_validation_options.0.resource_record_name
value = trimsuffix(aws_acm_certificate.jasonraimondi_com.domain_validation_options.0.resource_record_value, ".")
type = aws_acm_certificate.jasonraimondi_com.domain_validation_options.0.resource_record_type
ttl = 1
}
resource "cloudflare_record" "jasonraimondi_com_root" {
zone_id = cloudflare_zone.jasonraimondi_com.id
name = "@"
value = aws_acm_certificate.jasonraimondi_com.domain_name
type = "CNAME"
ttl = 1
}
Fix the subdirectory index.html navigation issue
You may have noticed that if you have subdirectories such as /about/index.html
and you want the user to be able to navigate to https://example.com/about
with no success.
You’ll need to add a lamba function to have requests for URI paths that end in “/” are rewritten into “/index.html” before the request is passed on to the CloudFront Origin.
There is a great project that I am using https://github.com/digital-sailors/standard-redirects-for-cloudfront
resource "aws_cloudfront_distribution" "jasonraimondi_com" {
...
default_cache_behavior {
...
lambda_function_association {
event_type = "origin-request"
include_body = false
lambda_arn = "arn:aws:lambda:us-east-1:191669008337:function:serverlessrepo-standard-r-StandardRedirectsForClou-9U6H7EG2RX95:1"
}
}
}