diff --git a/README.md b/README.md index 951bb6a..a8bb61c 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,30 @@ # terraform-aws-publii-hosting + Terraform module to host a static site generated by Publii [![Terraform CI](https://github.com/chris-qa-org/terraform-aws-publii-hosting/actions/workflows/main.yml/badge.svg?branch=main)](https://github.com/chris-qa-org/terraform-aws-publii-hosting/actions/workflows/main.yml?branch=main) [![GitHub release](https://img.shields.io/github/release/chris-qa-org/terraform-aws-publii-hosting.svg)](https://github.com/chris-qa-org/terraform-aws-publii-hosting/releases/) +This module launches static hosting resources (eg. S3 bucket, Cloudfront) specifically for sites generated by the Static Site Generator [Publii][1] + +It can in most cases be used to host any static site, however this module adds some configurations for the features of [Publii][1] + +## Key features: + + - Creates an S3 bucket along with an IAM user which has the minimum required permissions to sync from [Publii][1] + - Creates a CloudFront endpoint (And optionally ACM certificates and Route53 records in an existing Hosted Zone) + - Creates a Lambda function to run a Cloudfront Invalidation when `files.publii.json` is created/updated (This file is updated on every sync) + - Optionally have CloudFront do the right thing when 'Pretty URLs' are enabled (This is achieved via a CloudFront function which adds `index.html` to the URI if there is no extention) + - Optionally redirect from the apex domain (eg. example.com) to www (www.example.com). If this is enabled (`var.cloudfront_enable_apex_to_www_redirect`), the 'Website Url' within 'Server' options should be set to www.yourdomain.com - [Publii S3 Server Settings docs (point 26)] + - Optionally enable WAF + - Optionally add custom origins and cache behaviours + +## Usage + + - [Full launch with existing Route53 Zone](./examples/full-launch-with-existing-route53-zone/README.tf) + - [Use existing certificate and create own Route53 records](./examples/use-existing-certificate-and-create-own-route53-records/README.tf) + - [Adding custom origins and cache behaviours](./examples/adding-custom-origins-and-cache-behaviours/README.tf) + ## Requirements @@ -107,3 +128,7 @@ Terraform module to host a static site generated by Publii | [project\_random\_id](#output\_project\_random\_id) | The random ID generated to ensure unique resource names | | [s3\_bucket\_frontend](#output\_s3\_bucket\_frontend) | S3 bucket frontend attributes | + + +[1]: https://getpublii.com/ +[2]: https://getpublii.com/docs/setup-static-website-hosting-amazon-s3.html diff --git a/examples/adding-custom-origins-and-cache-behaviours/README.md b/examples/adding-custom-origins-and-cache-behaviours/README.md new file mode 100644 index 0000000..91b9550 --- /dev/null +++ b/examples/adding-custom-origins-and-cache-behaviours/README.md @@ -0,0 +1,71 @@ +# Adding custom origins and cache behaviours + + - [main.tf](./main.tf) + +``` +provider "aws" { + region = "us-east-1" + alias = "useast1" + default_tags { + tags = { + Project = "my-project" + } + } +} + +resource "aws_route53_zone" "example" { + name = "example.com" +} + +module "aws_publii_hosting" { + source = "chris-qa-org/terraform-aws-publii-hosting/aws" + version = "v1.0.0" + + providers = { + aws.useast1 = aws.useast1 + } + + site_url = "example.com" + s3_bucket_acl = "private" + cloudfront_enable_ipv6 = true + cloudfront_enable_waf = true // Note: This will cost at least $5.00/month - https://aws.amazon.com/waf/pricing/ (default: false) + cloudfront_enable_apex_to_www_redirect = true + enable_publii_pretty_urls = true + route53_hosted_zone_options = { + id = aws_route53_zone.example.id + create_certificate_dns_validation_records = true + create_site_url_dns_records = true + } + + cloudfront_origins = [ + { + domain_name = aws_s3_bucket.example.bucket_regional_domain_name + origin_id = "example-custom-origin" + + s3_origin_config = { + origin_access_identity = aws_cloudfront_origin_access_identity.example.cloudfront_access_identity_path + } + } + ] + + cloudfront_ordered_cache_behaviors = [ + { + path_pattern = "/example/*" + allowed_methods = ["GET", "HEAD"] + cached_methods = ["GET", "HEAD"] + target_origin_id = "example-custom-origin" + + use_forwarded_values = true + query_string = false + headers = ["Origin"] + cookies_forward = "none" + + min_ttl = 0 + default_ttl = 86400 + max_ttl = 31536000 + compress = true + viewer_protocol_policy = "redirect-to-https" + } + ] +} +``` diff --git a/examples/adding-custom-origins-and-cache-behaviours/main.tf b/examples/adding-custom-origins-and-cache-behaviours/main.tf new file mode 100644 index 0000000..046cba7 --- /dev/null +++ b/examples/adding-custom-origins-and-cache-behaviours/main.tf @@ -0,0 +1,65 @@ +provider "aws" { + region = "us-east-1" + alias = "useast1" + default_tags { + tags = { + Project = "my-project" + } + } +} + +resource "aws_route53_zone" "example" { + name = "example.com" +} + +module "aws_publii_hosting" { + source = "chris-qa-org/terraform-aws-publii-hosting/aws" + version = "v1.0.0" + + providers = { + aws.useast1 = aws.useast1 + } + + site_url = "example.com" + s3_bucket_acl = "private" + cloudfront_enable_ipv6 = true + cloudfront_enable_waf = true // Note: This will cost at least $5.00/month - https://aws.amazon.com/waf/pricing/ (default: false) + cloudfront_enable_apex_to_www_redirect = true + enable_publii_pretty_urls = true + route53_hosted_zone_options = { + id = aws_route53_zone.example.id + create_certificate_dns_validation_records = true + create_site_url_dns_records = true + } + + cloudfront_origins = [ + { + domain_name = aws_s3_bucket.example.bucket_regional_domain_name + origin_id = "example-custom-origin" + + s3_origin_config = { + origin_access_identity = aws_cloudfront_origin_access_identity.example.cloudfront_access_identity_path + } + } + ] + + cloudfront_ordered_cache_behaviors = [ + { + path_pattern = "/example/*" + allowed_methods = ["GET", "HEAD"] + cached_methods = ["GET", "HEAD"] + target_origin_id = "example-custom-origin" + + use_forwarded_values = true + query_string = false + headers = ["Origin"] + cookies_forward = "none" + + min_ttl = 0 + default_ttl = 86400 + max_ttl = 31536000 + compress = true + viewer_protocol_policy = "redirect-to-https" + } + ] +} diff --git a/examples/full-launch-with-existing-route53-zone/README.md b/examples/full-launch-with-existing-route53-zone/README.md new file mode 100644 index 0000000..a68bdf9 --- /dev/null +++ b/examples/full-launch-with-existing-route53-zone/README.md @@ -0,0 +1,40 @@ +# Full launch with existing Route53 Zone + + - [main.tf](./main.tf) + +``` +provider "aws" { + region = "us-east-1" + alias = "useast1" + default_tags { + tags = { + Project = "my-project" + } + } +} + +resource "aws_route53_zone" "example" { + name = "example.com" +} + +module "aws_publii_hosting" { + source = "chris-qa-org/terraform-aws-publii-hosting/aws" + version = "v1.0.0" + + providers = { + aws.useast1 = aws.useast1 + } + + site_url = "example.com" + s3_bucket_acl = "private" + cloudfront_enable_ipv6 = true + cloudfront_enable_waf = true // Note: This will cost at least $5.00/month - https://aws.amazon.com/waf/pricing/ (default: false) + cloudfront_enable_apex_to_www_redirect = true + enable_publii_pretty_urls = true + route53_hosted_zone_options = { + id = aws_route53_zone.example.id + create_certificate_dns_validation_records = true + create_site_url_dns_records = true + } +} +``` diff --git a/examples/full-launch-with-existing-route53-zone/main.tf b/examples/full-launch-with-existing-route53-zone/main.tf new file mode 100644 index 0000000..97711a6 --- /dev/null +++ b/examples/full-launch-with-existing-route53-zone/main.tf @@ -0,0 +1,34 @@ +provider "aws" { + region = "us-east-1" + alias = "useast1" + default_tags { + tags = { + Project = "my-project" + } + } +} + +resource "aws_route53_zone" "example" { + name = "example.com" +} + +module "aws_publii_hosting" { + source = "chris-qa-org/terraform-aws-publii-hosting/aws" + version = "v1.0.0" + + providers = { + aws.useast1 = aws.useast1 + } + + site_url = "example.com" + s3_bucket_acl = "private" + cloudfront_enable_ipv6 = true + cloudfront_enable_waf = true // Note: This will cost at least $5.00/month - https://aws.amazon.com/waf/pricing/ (default: false) + cloudfront_enable_apex_to_www_redirect = true + enable_publii_pretty_urls = true + route53_hosted_zone_options = { + id = aws_route53_zone.example.id + create_certificate_dns_validation_records = true + create_site_url_dns_records = true + } +} diff --git a/examples/use-existing-certificate-and-create-own-route53-records/README.md b/examples/use-existing-certificate-and-create-own-route53-records/README.md new file mode 100644 index 0000000..7792b69 --- /dev/null +++ b/examples/use-existing-certificate-and-create-own-route53-records/README.md @@ -0,0 +1,60 @@ +# Use existing certificate and create own Route53 records + + - [main.tf](./main.tf) + +``` +provider "aws" { + region = "us-east-1" + alias = "useast1" + default_tags { + tags = { + Project = "my-project" + } + } +} + +module "aws_publii_hosting" { + source = "chris-qa-org/terraform-aws-publii-hosting/aws" + version = "v1.0.0" + + providers = { + aws.useast1 = aws.useast1 + } + + site_url = "example.com" + s3_bucket_acl = "private" + cloudfront_tls_certificate_arn = "arn:aws:acm:us-east-1:123456789012:certificate/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" + cloudfront_enable_ipv6 = true + cloudfront_enable_waf = true // Note: This will cost at least $5.00/month - https://aws.amazon.com/waf/pricing/ (default: false) + cloudfront_enable_apex_to_www_redirect = true + enable_publii_pretty_urls = true +} + +resource "aws_route53_zone" "example" { + name = "example.com" +} + +resource "aws_route53_record" "frontend" { + zone_id = aws_route53_zone.example.zone_id + name = "www.example.com" + type = "A" + + alias { + name = module.aws_publii_hosting.aws_cloudfront_distribution_frontend.domain_name + zone_id = module.aws_publii_hosting.aws_cloudfront_distribution_frontend.hosted_zone_id + evaluate_target_health = true + } +} + +resource "aws_route53_record" "apex_redirect" { + zone_id = aws_route53_zone.example.zone_id + name = "example.com" + type = "A" + + alias { + name = module.aws_publii_hosting.aws_cloudfront_distribution_frontend_www_redirect.domain_name + zone_id = module.aws_publii_hosting.aws_cloudfront_distribution_frontend_www_redirect.hosted_zone_id + evaluate_target_health = true + } +} +``` diff --git a/examples/use-existing-certificate-and-create-own-route53-records/main.tf b/examples/use-existing-certificate-and-create-own-route53-records/main.tf new file mode 100644 index 0000000..fc1e055 --- /dev/null +++ b/examples/use-existing-certificate-and-create-own-route53-records/main.tf @@ -0,0 +1,54 @@ +provider "aws" { + region = "us-east-1" + alias = "useast1" + default_tags { + tags = { + Project = "my-project" + } + } +} + +module "aws_publii_hosting" { + source = "chris-qa-org/terraform-aws-publii-hosting/aws" + version = "v1.0.0" + + providers = { + aws.useast1 = aws.useast1 + } + + site_url = "example.com" + s3_bucket_acl = "private" + cloudfront_tls_certificate_arn = "arn:aws:acm:us-east-1:123456789012:certificate/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" + cloudfront_enable_ipv6 = true + cloudfront_enable_waf = true // Note: This will cost at least $5.00/month - https://aws.amazon.com/waf/pricing/ (default: false) + cloudfront_enable_apex_to_www_redirect = true + enable_publii_pretty_urls = true +} + +resource "aws_route53_zone" "example" { + name = "example.com" +} + +resource "aws_route53_record" "frontend" { + zone_id = aws_route53_zone.example.zone_id + name = "www.example.com" + type = "A" + + alias { + name = module.aws_publii_hosting.aws_cloudfront_distribution_frontend.domain_name + zone_id = module.aws_publii_hosting.aws_cloudfront_distribution_frontend.hosted_zone_id + evaluate_target_health = true + } +} + +resource "aws_route53_record" "apex_redirect" { + zone_id = aws_route53_zone.example.zone_id + name = "example.com" + type = "A" + + alias { + name = module.aws_publii_hosting.aws_cloudfront_distribution_frontend_www_redirect.domain_name + zone_id = module.aws_publii_hosting.aws_cloudfront_distribution_frontend_www_redirect.hosted_zone_id + evaluate_target_health = true + } +}