Skip to content

Commit

Permalink
Performance improvements (#222)
Browse files Browse the repository at this point in the history
* chore: make fonts self hosted to speed up page load #218

* fix: accessibility issue with H4s out of alignment #218

* fix: make min height on attributes for touch areas #218

* refactor: update to use better nodejs version and pattern #219

* refactor: upgrade node to v20 for lambdas #219

* chore: update aws provider version #220

* chore: update configuration for AWS provider #220

* chore: upgrade terraform version #220

* feat: upgrade cloudfront to use modern ciphers and improve price class performance #221
  • Loading branch information
ajfisher authored Sep 21, 2024
1 parent a0fcd95 commit e06b17c
Show file tree
Hide file tree
Showing 16 changed files with 243 additions and 144 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
'use strict'
// this handler looks for requests that are effectively for directories
// coming through cloudfront. As it doesn't know that that means to serve
// the index file, it just throws a 404. This will perform the appropriate
// rerouting of the URL so that S3 can retrieve the right file and respond
// correctly.

exports.handler = (event, context, callback) => {
export const handler = async (event) => {
const request = event.Records[0].cf.request;
const { uri } = request;

Expand All @@ -15,5 +14,5 @@ exports.handler = (event, context, callback) => {
request.uri += '/index.html';
}

callback(null, request);
return request;
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// Thanks to https://www.ximedes.com/2018-04-23/deploying-gatsby-on-s3-and-cloudfront/
// for the approach which is very solid

exports.handler = (event, context, callback) => {
export const handler = async (event) => {
const request = event.Records[0].cf.request;
const response = event.Records[0].cf.response;
const headers = response.headers;
Expand Down Expand Up @@ -108,5 +108,5 @@ exports.handler = (event, context, callback) => {
}
].forEach(h => (headers[h.key.toLowerCase()] = [h]));

callback(null, response);
return response;
};
15 changes: 7 additions & 8 deletions infra/application/cloudfront.tf
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ resource "aws_cloudfront_origin_access_identity" "origin_access_identity" {
resource "aws_cloudfront_distribution" "web_app" {
enabled = true
is_ipv6_enabled = true
price_class = "PriceClass_100"
http_version = "http2"
price_class = "PriceClass_All"
http_version = "http2and3"
wait_for_deployment = false

aliases = ["ajfisher.me"]
Expand Down Expand Up @@ -47,8 +47,6 @@ resource "aws_cloudfront_distribution" "web_app" {
forwarded_values {
query_string = false

# headers = ["Origin"]

cookies {
forward = "none"
}
Expand Down Expand Up @@ -76,7 +74,7 @@ resource "aws_cloudfront_distribution" "web_app" {
viewer_certificate {
acm_certificate_arn = aws_acm_certificate.apex_cert.arn
ssl_support_method = "sni-only"
minimum_protocol_version = "TLSv1.2_2018"
minimum_protocol_version = "TLSv1.2_2021"
}

depends_on = [aws_acm_certificate_validation.apex_cert]
Expand All @@ -100,11 +98,12 @@ resource "aws_cloudfront_distribution" "redirect_distribution" {
is_ipv6_enabled = true

aliases = ["www.ajfisher.me"]
price_class = "PriceClass_100"
price_class = "PriceClass_All"
http_version = "http2and3"
wait_for_deployment = false

origin {
domain_name = aws_s3_bucket.redirect_to_apex.website_endpoint
domain_name = aws_s3_bucket_website_configuration.redirect_to_apex.website_endpoint
origin_id = "origin-redirect-app-${aws_s3_bucket.redirect_to_apex.id}"

// The redirect origin must be http even if it's on S3 for redirects to work properly
Expand Down Expand Up @@ -138,7 +137,7 @@ resource "aws_cloudfront_distribution" "redirect_distribution" {
viewer_certificate {
acm_certificate_arn = aws_acm_certificate.app_cert.arn
ssl_support_method = "sni-only"
minimum_protocol_version = "TLSv1.2_2018"
minimum_protocol_version = "TLSv1.2_2021"
}

restrictions {
Expand Down
4 changes: 2 additions & 2 deletions infra/application/lambda.tf
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ resource "aws_lambda_function" "redirect_lambda" {

source_code_hash = data.archive_file.cloudfront_lambda_functions.output_base64sha256

runtime = "nodejs14.x"
runtime = "nodejs20.x"
}

resource "aws_lambda_function" "header_lambda" {
Expand All @@ -79,6 +79,6 @@ resource "aws_lambda_function" "header_lambda" {

source_code_hash = data.archive_file.cloudfront_lambda_functions.output_base64sha256

runtime = "nodejs14.x"
runtime = "nodejs20.x"
}

48 changes: 35 additions & 13 deletions infra/application/s3.tf
Original file line number Diff line number Diff line change
@@ -1,34 +1,56 @@
# logfiles for the front end application
resource "aws_s3_bucket" "website_logs" {
bucket = "aj-web-logs-${var.env}"
acl = "log-delivery-write"
tags = {
src = "terraform"
component = "logs"
}
}

resource "aws_s3_bucket_server_side_encryption_configuration" "website-logs-encryption" {
bucket = aws_s3_bucket.website_logs.id

server_side_encryption_configuration {
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}

resource "aws_s3_bucket_ownership_controls" "website_logs" {
bucket = aws_s3_bucket.website_logs.id
rule {
object_ownership = "BucketOwnerPreferred"
}
}

resource "aws_s3_bucket_acl" "website_logs" {
depends_on = [aws_s3_bucket_ownership_controls.website_logs]

bucket = aws_s3_bucket.website_logs.id
acl = "log-delivery-write"
}

# redirection bucket
resource "aws_s3_bucket" "redirect_to_apex" {
bucket = "ajfisher-site-apex-redirect-${var.env}"
}

resource "aws_s3_bucket_website_configuration" "redirect_to_apex" {
bucket = aws_s3_bucket.redirect_to_apex.id

website {
redirect_all_requests_to = "https://ajfisher.me"
redirect_all_requests_to {
host_name = "ajfisher.me"
protocol = "https"
}
}

resource "aws_s3_bucket_server_side_encryption_configuration" "redirect-encryption" {
bucket = "ajfisher-site-apex-redirect-${var.env}"

server_side_encryption_configuration {
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions infra/application/versions.tf
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@

terraform {
required_version = ">= 1.0.9"
required_version = ">= 1.9.2"
required_providers {
archive = {
source = "hashicorp/archive"
}
aws = {
source = "hashicorp/aws"
version = "~> 3.63.0"
version = "~> 5.0"
configuration_aliases = [ aws.useast ]
}
}
Expand Down
116 changes: 55 additions & 61 deletions infra/application/web.tf
Original file line number Diff line number Diff line change
@@ -1,66 +1,16 @@
# policy for the bucket
#data "template_file" "bucket_policy" {
# template = <<EOF
#{
# "Version": "2012-10-17",
# "Statement": [{
# "Sid": "OnlyCloudfrontReadAccess",
# "Effect": "Allow",
# "Principal": {
# "AWS": "${aws_cloudfront_origin_access_identity.origin_access_identity.iam_arn}"
# },
# "Action": "s3:GetObject",
# "Resource": "arn:aws:s3:::aj-web-ajfisher-me-${var.env}/*"
# }]
#}
#EOF
#
#}

# data "template_file" "public_bucket_policy" {
# template = <<EOF
# {
# "Version": "2012-10-17",
# "Statement": [{
# "Sid": "PublicRead",
# "Effect": "Allow",
# "Principal": "*",
# "Action": "s3:GetObject",
# "Resource": "arn:aws:s3:::aj-web-ajfisher-me-${var.env}/*"
# }]
# }
# EOF
#
# }

# Location for the frontend code to reside
resource "aws_s3_bucket" "website_code" {
bucket = "aj-web-ajfisher-me-${var.env}"
acl = "private"

# acl = "public-read"

logging {
target_bucket = aws_s3_bucket.website_logs.id
target_prefix = "aj-web-logs-${var.env}/"
}

website {
index_document = "index.html"
error_document = "404.html"
}

cors_rule {
allowed_origins = ["https://www.ajfisher.me"]
allowed_headers = ["Authorization", "Content-Length"]
allowed_methods = ["GET", "HEAD"]
}

tags = {
src = "terraform"
component = "code"
}
# policy = data.template_file.bucket_policy.rendered
}

resource "aws_s3_bucket_policy" "website_code" {
bucket = aws_s3_bucket.website_code.id

policy = <<POLICY
{
"Version": "2012-10-17",
Expand All @@ -75,13 +25,57 @@ resource "aws_s3_bucket" "website_code" {
}]
}
POLICY
}

server_side_encryption_configuration {
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
resource "aws_s3_bucket_logging" "website_code" {
bucket = aws_s3_bucket.website_code.id

target_bucket = aws_s3_bucket.website_logs.id
target_prefix = "aj-web-logs-${var.env}/"
}

resource "aws_s3_bucket_website_configuration" "website_code" {
bucket = aws_s3_bucket.website_code.id

index_document {
suffix = "index.html"
}

error_document {
key = "error.html"
}
}

resource "aws_s3_bucket_cors_configuration" "website_code" {
bucket = aws_s3_bucket.website_code.id

cors_rule {
allowed_origins = ["https://ajfisher.me"]
allowed_headers = ["Authorization", "Content-Length"]
allowed_methods = ["GET", "HEAD"]
}
}

resource "aws_s3_bucket_ownership_controls" "website_code" {
bucket = aws_s3_bucket.website_code.id
rule {
object_ownership = "BucketOwnerPreferred"
}
}

resource "aws_s3_bucket_acl" "website_code" {
depends_on = [aws_s3_bucket_ownership_controls.website_code]

bucket = aws_s3_bucket.website_code.id
acl = "private"
}

resource "aws_s3_bucket_server_side_encryption_configuration" "website_code" {
bucket = aws_s3_bucket.website_code.id

rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
59 changes: 31 additions & 28 deletions infra/prod/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit e06b17c

Please sign in to comment.