Terraform AWS Lightweight Hosting
A Terraform module that provides an opinated solution for hosting lightweight websites using AWS S3 and AWS Lambda.
This Terraform module was developed to simplify hosting sites created using Static Site Generation (SSG) frameworks. I use it to host the web properties I personally manage.
In order to use this module, you must:
-
Have a completely static frontend.
I highly recommend using a static site generator like Astro, Gatsby or Next.js. -
Manage your domain name via Route 53.
Route 53 is used to automatically provision ACM certificates. While I could organize this module to remove this requirement, as stated above, this module is opinated 🙂.
If no lambda parameters are specified, no lambda will be deployed.
This Terraform module supports both Terraform and OpenTofu.
This Terraform stack will be unable to serve files without any extensions.
Since CloudFront doesn’t natively support directory index documents, this project includes a CloudFront Function to emulate the functionality. Unfortunately, this breaks support for files without any extensions.
CloudFront doesn’t support custom error pages per origin, and instead applies custom responses globally.
In order to provide support for custom 404 documents, a custom error response is defined for HTTP 403
and HTTP 404
responses. Therefore,
any API response with a 403
or 404
status code will return a 404
response with your error_document
as the body of the response.
Examples
Basic Usage with no Lambda
module "static_hosting" {
# Alternatively, you may use
# source = "git::https://gitlab.com/finewolf-projects/terraform-aws-lightweight-hosting.git?ref=v6.1.0"
source = "gitlab.com/finewolf-projects/terraform-aws-lightweight-hosting/aws"
version = "6.1.0"
domains = ["example.org", "www.example.org"]
zone_ids = ["Z00000000000000000000", "Z00000000000000000000"]
index_document = "index.html"
error_document = "404.html"
}
Usage with a Lambda Backend
module "static_hosting" {
source = "gitlab.com/finewolf-projects/terraform-aws-lightweight-hosting/aws"
version = "6.1.0"
domains = ["example.org", "www.example.org"]
zone_ids = ["Z00000000000000000000", "Z00000000000000000000"]
index_document = "index.html"
error_document = "404.html"
lambda_memory_size = 256
lambda_package_config = {
filename = "/home/ci/builds/node-application.zip"
s3_bucket = aws_s3_bucket.storage_bucket.id
s3_key = "lambda/node-application.zip"
runtime = "nodejs18.x"
handler = "index.handler"
}
lambda_timeout = 20
lambda_log_retention = 7
lambda_environment = {
ThisIs__ACustom__EnvVar = "HelloWorld"
}
}
# Storage bucket for artifacts
resource "aws_s3_bucket" "storage_bucket" {
bucket = "example.org-artifacts"
}
resource "aws_s3_bucket_ownership_controls" "storage_bucket_ownership" {
bucket = aws_s3_bucket.storage_bucket.id
rule {
object_ownership = "BucketOwnerEnforced"
}
}
resource "aws_s3_bucket_public_access_block" "bucket_public_access_block" {
bucket = aws_s3_bucket.storage_bucket.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
resource "aws_s3_bucket_versioning" "bucket_versioning" {
bucket = aws_s3_bucket.storage_bucket.id
versioning_configuration {
status = "Suspended"
}
}