AWS Networking with Terraform : Deploying a CloudFront distribution for EC2 Website
Tags: aws, awscommunitybuilder, terraform, upskilling
Published: 2024-03-15 18:22:39

In our earlier post, we implemented the seamless integration of Amazon S3 with CloudFront for hosting static websites. Today, we're taking it a step further by exploring how to integrate Amazon Content Delivery Networks (CDNs) CloudFront with websites hosted on EC2 instances. We'll be leveraging Terraform modules to streamline the process, ensuring modularity and scalability.

## Architecture Overview:
Before diving into the implementation details, let's outline the architecture we'll be working with:

![Architecture Diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qihh8tpsd5ehbxe62tj3.png)

## Step 1: Create an EC2 Web Server Instance in a VPC
We'll initiate the process by provisioning an EC2 instance within a Virtual Private Cloud (VPC).  We have used modules to create the components. Please refer to my GitHub repo in resources section.
```terraform
####################################################
# Create two VPC and components
####################################################

module "vpc" {
  source               = "./modules/vpc"
  name                 = "VPC-A"
  aws_region           = var.aws_region
  vpc_cidr_block       = var.vpc_cidr_block #"10.1.0.0/16"
  public_subnets_cidrs = [cidrsubnet(var.vpc_cidr_block, 8, 1)]
  enable_dns_hostnames = var.enable_dns_hostnames
  aws_azs              = var.aws_azs
  common_tags          = local.common_tags
  naming_prefix        = local.naming_prefix
}

####################################################
# Create EC2 Server Instances
####################################################

module "web_server" {
  source           = "./modules/web"
  instance_type    = var.instance_type
  instance_key     = var.instance_key
  subnet_id        = module.vpc.public_subnets[0]
  vpc_id           = module.vpc.vpc_id
  ec2_name         = "Web Server"
  sg_ingress_ports = var.sg_ingress_public
  common_tags      = local.common_tags
  naming_prefix    = local.naming_prefix
}
```

## Step 2: Create a CloudFront Distribution
Next, we'll set up a CloudFront distribution with origin of public DNS of EC2 instance hosting website.

```terraform
####################################################
# Create AWS Cloudfront distribution
####################################################
resource "aws_cloudfront_distribution" "cf-dist" {
  enabled             = true
  default_root_object = "index.html"

  origin {
    domain_name = var.ec2_public_dns
    origin_id   = var.ec2_public_dns
    custom_origin_config {
      http_port              = 80
      https_port             = 443
      origin_protocol_policy = "http-only"
      origin_ssl_protocols   = ["TLSv1.2"]
    }
  }

  default_cache_behavior {
    allowed_methods  = ["GET", "HEAD"]
    cached_methods   = ["GET", "HEAD"]
    target_origin_id = var.ec2_public_dns
    forwarded_values {
      query_string = false

      cookies {
        forward = "none"
      }
    }
    viewer_protocol_policy = "allow-all"
    min_ttl                = 0
    default_ttl            = 3600
    max_ttl                = 86400
  }

  price_class = "PriceClass_All"

  restrictions {
    geo_restriction {
      restriction_type = "whitelist"
      locations        = ["IN", "US", "CA"]
    }
  }

  viewer_certificate {
    cloudfront_default_certificate = true
  }

  tags = merge(var.common_tags, {
    Name = "${var.naming_prefix}-cloudfront"
  })
}
```

## Steps to Run Terraform
Follow these steps to execute the Terraform configuration:
```terraform
terraform init
terraform plan 
terraform apply -auto-approve
```
Upon successful completion, Terraform will provide relevant outputs.
```terraform
Apply complete! Resources: 8 added, 0 changed, 0 destroyed.

Outputs:

cloudfront_domain_name = "http://d3q4caj22i0xed.cloudfront.net"
```

## Testing the outcome
EC2 Instance with hosted website

![EC2 Instance](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/guomssboioxkvtj1q5ht.png)

CloudFront Distribution:

![Cloudfront Distribution](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p9267zb0gu71n3ucbsk4.png)

CloudFront Distribution Origin as EC2 as origin:
![CF Dist as EC2 as Origin](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4605i8ghsb0yktm4uqwy.png)

Using cloudfront domain name to access EC2 Website

![Website](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/66xhc58orxe1kfembhey.png)

Website accessed from country which is not in allowlist (used soft VPN)

![Geo Allowlist](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mi4qg51owy46cprukrff.png)

## Cleanup
Remember to stop AWS components to avoid large bills.
```terraform
terraform destroy -auto-approve
```

With the EC2-CloudFront integration successfully implemented, we've significantly enhanced our website's performance and reliability. 

In our upcoming module, we'll delve into setting up a failover website using S3 in conjunction with CloudFront distributions. 

## Resources:
GitHub Repo: https://github.com/chinmayto/terraform-aws-cloudfront-ec2
AWS CloudFront: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Introduction.html