Terraform code for creating infrastructure on AWS for a Jekyll or any other static website.
Note: The majority of the code is based on the following repositories:
- pirxthepilot/terraform-aws-static-site
- IAM-related parts are derived from brianmacdonald/terraform-aws-s3-static-site
- Deploys almost everything needed to host a static website.
- Uses the apex domain for the main URL (e.g.,
https://example.com). - Supports multiple subdomains, which redirect to the apex domain.
- Keeps your S3 bucket private—only CloudFront can access it via Origin Access Identity (OAI).
- Includes a URL rewrite function to append
index.htmlto the URI, enabling CloudFront to serve paths likehttps://example.com/foo, not justhttps://example.com. - Outputs the CloudFront distribution ID, AWS Access Key, and AWS Secret Key for use in automated deployments.
- Terraform state is saved in an S3 bucket.
This Terraform code creates the following AWS resources for your static website:
- S3 bucket
- Requisite IAM roles and bucket access policies
- S3 Origin Access Identity (OAI)
- Route53 DNS records
- TLS certificates (with DNS validation)
- CloudFront distribution
- CloudFront function for redirect and rewrite rules
This code does not deploy the following:
- Your domain's Route53 zone. You must manually configure this and provide the zone ID to use with this module.
Let's create the S3 state bucket (please use a unique one, as this one might already be taken), which will be used for the Terraform state:
aws s3api create-bucket --bucket "myblog-tf-state" --region "us-east-1" --acl private --profile prod
If necessary, update the bucket name in main.tf.
In the Terraform variables file, blog.tfvars, configure at least the following. It is assumed that the AWS profile name prod is used for this deployment.
domain = "my-site.com"
route53_zone_id = "Z00XXXXXXXXXXXX"
subdomains = ["www"]
domain- Your site's domain (e.g.,example.com).subdomains(optional) - A list of subdomains to configure. All subdomains will redirect to the apex domain URL. Default:[](no subdomains).route53_zone_id- The Route53 zone ID for your domain.block_ofac_countries(optional) - Whether to block OFAC-sanctioned countries. Default:false.cache_ttl(optional) - CloudFront cache TTL values. See variables.tf for default values.
Using OpenTofu:
tofu init
tofu plan -var-file="blog.tfvars"
tofu apply -var-file="blog.tfvars"
Or using Terraform:
terraform init
terraform plan -var-file="blog.tfvars"
terraform apply -var-file="blog.tfvars"