# Static site hosting for the repertory frontend (tunes.dumpnet.chat) # S3 static website hosting behind CloudFront (for HTTPS) + ACM cert. # NOTE: bucket name currently matches the live hostname (repertory.dumpnet.chat) # because it's also used as an S3-website CNAME target internally. When this # moves to tunes.dumpnet.chat, rename the bucket + update the Route53 record # + alt name below to match. resource "aws_s3_bucket" "repertory_frontend" { bucket = "repertory.dumpnet.chat" force_destroy = true } resource "aws_s3_bucket_website_configuration" "repertory_frontend" { bucket = aws_s3_bucket.repertory_frontend.id index_document { suffix = "index.html" } } resource "aws_s3_bucket_public_access_block" "repertory_frontend" { bucket = aws_s3_bucket.repertory_frontend.id block_public_acls = false block_public_policy = false ignore_public_acls = false restrict_public_buckets = false } resource "aws_s3_bucket_policy" "repertory_frontend" { bucket = aws_s3_bucket.repertory_frontend.id policy = jsonencode({ Version = "2012-10-17" Statement = [ { Sid = "PublicReadGetObject" Effect = "Allow" Principal = "*" Action = "s3:GetObject" Resource = "${aws_s3_bucket.repertory_frontend.arn}/*" } ] }) depends_on = [aws_s3_bucket_public_access_block.repertory_frontend] } # --- ACM cert for CloudFront (must be in us-east-1, which this provider already is) --- resource "aws_acm_certificate" "repertory_frontend" { domain_name = "repertory.${var.domain}" validation_method = "DNS" lifecycle { create_before_destroy = true } } resource "aws_route53_record" "repertory_frontend_cert_validation" { for_each = { for dvo in aws_acm_certificate.repertory_frontend.domain_validation_options : dvo.domain_name => { name = dvo.resource_record_name record = dvo.resource_record_value type = dvo.resource_record_type } } zone_id = data.aws_route53_zone.dumpnet.zone_id name = each.value.name type = each.value.type records = [each.value.record] ttl = 300 } resource "aws_acm_certificate_validation" "repertory_frontend" { certificate_arn = aws_acm_certificate.repertory_frontend.arn validation_record_fqdns = [for r in aws_route53_record.repertory_frontend_cert_validation : r.fqdn] } # --- CloudFront distribution in front of the S3 website endpoint --- resource "aws_cloudfront_distribution" "repertory_frontend" { enabled = true default_root_object = "index.html" aliases = ["repertory.${var.domain}"] origin { domain_name = aws_s3_bucket_website_configuration.repertory_frontend.website_endpoint origin_id = "repertory-frontend-s3-website" custom_origin_config { http_port = 80 https_port = 443 origin_protocol_policy = "http-only" # S3 website endpoints are HTTP-only origin_ssl_protocols = ["TLSv1.2"] } } default_cache_behavior { allowed_methods = ["GET", "HEAD"] cached_methods = ["GET", "HEAD"] target_origin_id = "repertory-frontend-s3-website" viewer_protocol_policy = "redirect-to-https" forwarded_values { query_string = false cookies { forward = "none" } } } restrictions { geo_restriction { restriction_type = "none" } } viewer_certificate { acm_certificate_arn = aws_acm_certificate_validation.repertory_frontend.certificate_arn ssl_support_method = "sni-only" minimum_protocol_version = "TLSv1.2_2021" } } resource "aws_route53_record" "repertory_frontend" { zone_id = data.aws_route53_zone.dumpnet.zone_id name = "repertory.${var.domain}" type = "A" alias { name = aws_cloudfront_distribution.repertory_frontend.domain_name zone_id = aws_cloudfront_distribution.repertory_frontend.hosted_zone_id evaluate_target_health = false } } output "repertory_frontend_bucket" { value = aws_s3_bucket.repertory_frontend.id } output "repertory_frontend_website_endpoint" { value = aws_s3_bucket_website_configuration.repertory_frontend.website_endpoint } output "repertory_frontend_cloudfront_domain" { value = aws_cloudfront_distribution.repertory_frontend.domain_name }