Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: setup cloudfront #63

Merged
merged 1 commit into from
Jul 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
**/.terraform
**/secret.auto.tfvars
81 changes: 0 additions & 81 deletions ]

This file was deleted.

25 changes: 25 additions & 0 deletions deployments/infrastructure/base/acm.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
provider "aws" {
alias = "virginia"
region = "us-east-1"
}

resource "aws_acm_certificate" "app" {
domain_name = var.app_base_url
validation_method = "DNS"
provider = aws.virginia

lifecycle {
create_before_destroy = true
}

tags = {
App = var.app_name
Env = var.env
}
}

resource "aws_acm_certificate_validation" "app" {
certificate_arn = aws_acm_certificate.app.arn
validation_record_fqdns = [for record in aws_route53_record.app_validation : record.fqdn]
provider = aws.virginia
}
16 changes: 2 additions & 14 deletions deployments/infrastructure/base/app_runner.tf
Original file line number Diff line number Diff line change
Expand Up @@ -60,18 +60,6 @@ resource "aws_apprunner_auto_scaling_configuration_version" "app" {
}
}

resource "aws_apprunner_custom_domain_association" "app" {
domain_name = var.app_base_url
service_arn = aws_apprunner_service.app.arn
enable_www_subdomain = false
}

output "app_certificate_validation_records" {
value = aws_apprunner_custom_domain_association.app.certificate_validation_records
sensitive = true
}

output "app_dns_target" {
value = aws_apprunner_custom_domain_association.app.dns_target
sensitive = true
output "app_url" {
value = aws_apprunner_service.app.service_url
}
72 changes: 72 additions & 0 deletions deployments/infrastructure/base/cloudfront.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
locals {
app_runner_origin_id = "${var.app_name}-${var.env}-app"
}


resource "aws_cloudfront_cache_policy" "app" {
name = "${var.app_name}-${var.env}-content-cache-policy"

min_ttl = 0
default_ttl = 3600
max_ttl = 86400

parameters_in_cache_key_and_forwarded_to_origin {
cookies_config {
cookie_behavior = "whitelist"
cookies {
items = ["user_id"]
}
}
headers_config {
header_behavior = "none"
}

query_strings_config {
query_string_behavior = "all"
}
}
}

resource "aws_cloudfront_distribution" "app" {
enabled = true
is_ipv6_enabled = true
price_class = "PriceClass_200"

origin {
origin_id = local.app_runner_origin_id
domain_name = aws_apprunner_service.app.service_url
custom_origin_config {
http_port = 80
https_port = 443
origin_protocol_policy = "https-only"
origin_ssl_protocols = ["TLSv1.2"]
}
}

aliases = [var.app_base_url]

default_cache_behavior {
allowed_methods = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]
cached_methods = ["GET", "HEAD"]
target_origin_id = local.app_runner_origin_id
cache_policy_id = aws_cloudfront_cache_policy.app.id
compress = true
viewer_protocol_policy = "redirect-to-https"
}

viewer_certificate {
acm_certificate_arn = aws_acm_certificate_validation.app.certificate_arn
ssl_support_method = "sni-only"
}

restrictions {
geo_restriction {
restriction_type = "none"
}
}

tags = {
App = var.app_name
Env = var.env
}
}
32 changes: 32 additions & 0 deletions deployments/infrastructure/base/route53.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
data "aws_route53_zone" "goti" {
name = "goti.one"
}

resource "aws_route53_record" "cdn" {
zone_id = data.aws_route53_zone.goti.zone_id
name = var.app_base_url
type = "A"

alias {
name = aws_cloudfront_distribution.app.domain_name
zone_id = aws_cloudfront_distribution.app.hosted_zone_id
evaluate_target_health = false
}
}

resource "aws_route53_record" "app_validation" {
for_each = {
for dvo in aws_acm_certificate.app.domain_validation_options : dvo.domain_name => {
name = dvo.resource_record_name
record = dvo.resource_record_value
type = dvo.resource_record_type
}
}

allow_overwrite = true
name = each.value.name
records = [each.value.record]
ttl = 3600
type = each.value.type
zone_id = data.aws_route53_zone.goti.zone_id
}
7 changes: 7 additions & 0 deletions internal/api/handler/ajax_home_page.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"html/template"
"net/http"

"gotiny/internal/api/middleware"
"gotiny/internal/api/util"
)

Expand Down Expand Up @@ -31,3 +32,9 @@ func (h *AjaxHomePageHandler) Path() string {
func (h *AjaxHomePageHandler) Method() string {
return http.MethodGet
}

func (h *AjaxHomePageHandler) Middlewares() []func(http.Handler) http.Handler {
return []func(http.Handler) http.Handler{
middleware.GetCacheMiddleware(86400),
}
}
1 change: 1 addition & 0 deletions internal/api/handler/ajax_link_details_page.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,6 @@ func (h *AjaxLinkDetailsPageHandler) Method() string {
func (h *AjaxLinkDetailsPageHandler) Middlewares() []func(http.Handler) http.Handler {
return []func(http.Handler) http.Handler{
h.linkTokenValidator.Handle,
middleware.GetCacheMiddleware(86400),
}
}
22 changes: 22 additions & 0 deletions internal/api/middleware/cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package middleware

import (
"fmt"
"net/http"
)

func NoCacheMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
writer.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
next.ServeHTTP(writer, request)
})
}

func GetCacheMiddleware(ttl int) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
writer.Header().Set("Cache-Control", fmt.Sprintf("max-age=%d", ttl))
next.ServeHTTP(writer, request)
})
}
}
10 changes: 2 additions & 8 deletions internal/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,13 @@ func newMux(
mux.Method(http.MethodGet, "/api/docs", redoc)
mux.Method(http.MethodGet, "/api/swagger-ui", swaggerUI)
mux.Method(http.MethodGet, "/api/swagger.yaml", http.FileServer(http.Dir("./")))
mux.With(addCacheHeader).
mux.With(app_middleware.GetCacheMiddleware(86400)).
Method(http.MethodGet, "/public/*", http.FileServer(http.Dir("./web/")))

for _, h := range handlers {
mux.Group(func(r chi.Router) {
middlewares := app_middleware.GetMiddlewaresToAttach(h)
r.Use(app_middleware.NoCacheMiddleware)
for _, m := range middlewares {
r.Use(m)
}
Expand All @@ -122,10 +123,3 @@ func loadTemplates() (*template.Template, error) {

return t, nil
}

func addCacheHeader(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Cache-Control", "max-age=86400")
next.ServeHTTP(w, r)
})
}