# Application Load Balancer resource "aws_lb" "api" { name = "${var.app_name}-api-alb" internal = false load_balancer_type = "application" security_groups = [aws_security_group.alb.id] subnets = aws_subnet.public[*].id enable_deletion_protection = false enable_http2 = true tags = { Name = "${var.app_name}-api-alb" } } # ALB Security Group resource "aws_security_group" "alb" { name = "${var.app_name}-alb-sg" description = "Security group for ALB" vpc_id = aws_vpc.main.id ingress { from_port = 80 to_port = 80 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] description = "HTTP from anywhere" } ingress { from_port = 443 to_port = 443 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] description = "HTTPS from anywhere" } egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] description = "Allow all outbound" } tags = { Name = "${var.app_name}-alb-sg" } } # Target Group resource "aws_lb_target_group" "api" { name = "${var.app_name}-api-tg" port = 80 protocol = "HTTP" vpc_id = aws_vpc.main.id health_check { enabled = true healthy_threshold = 2 interval = 30 matcher = "200" path = "/" port = "traffic-port" protocol = "HTTP" timeout = 5 unhealthy_threshold = 2 } tags = { Name = "${var.app_name}-api-tg" } } # Attach EC2 instance to target group resource "aws_lb_target_group_attachment" "api" { target_group_arn = aws_lb_target_group.api.arn target_id = aws_instance.api.id port = 80 } # HTTP Listener (redirects to HTTPS) resource "aws_lb_listener" "api_http" { load_balancer_arn = aws_lb.api.arn port = "80" protocol = "HTTP" default_action { type = "redirect" redirect { port = "443" protocol = "HTTPS" status_code = "HTTP_301" } } } # Request ACM certificate resource "aws_acm_certificate" "api" { domain_name = "api.${var.domain_name}" validation_method = "DNS" lifecycle { create_before_destroy = true } tags = { Name = "${var.app_name}-api-cert" } } # Create DNS validation record in Cloudflare resource "cloudflare_record" "api_cert_validation" { for_each = { for dvo in aws_acm_certificate.api.domain_validation_options : dvo.domain_name => { name = dvo.resource_record_name record = dvo.resource_record_value type = dvo.resource_record_type } } zone_id = data.cloudflare_zone.domain[0].id name = replace(each.value.name, ".${var.domain_name}.", "") value = trimsuffix(each.value.record, ".") type = each.value.type ttl = 60 proxied = false } # Certificate validation resource "aws_acm_certificate_validation" "api" { certificate_arn = aws_acm_certificate.api.arn validation_record_fqdns = [for record in cloudflare_record.api_cert_validation : record.hostname] } # HTTPS Listener resource "aws_lb_listener" "api_https" { load_balancer_arn = aws_lb.api.arn port = "443" protocol = "HTTPS" ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06" certificate_arn = aws_acm_certificate_validation.api.certificate_arn default_action { type = "forward" target_group_arn = aws_lb_target_group.api.arn } } # Output ALB DNS output "alb_dns_name" { value = aws_lb.api.dns_name description = "ALB DNS name" } # Output ALB Zone ID (needed for Route53 alias) output "alb_zone_id" { value = aws_lb.api.zone_id description = "ALB Zone ID" }