Building a Next.js application with Terraform, S3, and CloudFront

Photo by Growtika on Unsplash

Building a Next.js application with Terraform, S3, and CloudFront

In this blog post, I’ll walk you through how to build a portfolio website using Next.js, Terraform, AWS S3, and CloudFront. This setup ensures a scalable, secure, and globally distributed website for an optimal user experience.


Project Architecture

  1. Frontend:

    • Built using Next.js.

    • Deployed as a static website using S3.

  2. Infrastructure:

    • Automated with Terraform.

    • AWS services used:

      • S3: Stores static files (HTML, CSS, JS).

      • CloudFront: Provides a CDN for global distribution.

      • Origin Access Identity (OAI): Secures S3 content, making it accessible only through CloudFront.


Key Features

  1. Infrastructure as Code:

    • Terraform provisions S3, CloudFront, and related resources.

    • Allows easy replication of the setup for future projects.

  2. Performance Optimization:

    • CloudFront caches content globally, ensuring fast load times.

    • TTL settings manage efficient caching strategies.

  3. Security:

    • S3 bucket configured with ownership controls, public access block, and an OAI for CloudFront.

    • HTTPS enabled through CloudFront’s default certificate.


Step-by-Step Implementation

1. Develop the Website

Using Next.js:

  • Create a static website:

      npx create-next-app@latest my-portfolio
      cd my-portfolio
      npm run build
    
  • Output static files are in the out/ directory.


2. Write Terraform Code

S3 Bucket

Configuring an S3 bucket for static website hosting:

resource "aws_s3_bucket" "website_bucket" {
  bucket = "portfolio-website-bucket"
  tags = {
    Environment = "Production"
    Project     = "Portfolio"
  }
}
CloudFront Distribution

Setting up CloudFront for global delivery:

resource "aws_cloudfront_distribution" "website_distribution" {
  origin {
    domain_name = aws_s3_bucket.website_bucket.bucket_regional_domain_name
    origin_id   = "S3-Website"
    s3_origin_config {
      origin_access_identity = aws_cloudfront_origin_access_identity.origin_access_identity.cloudfront_access_identity_path
    }
  }

  default_cache_behavior {
    target_origin_id = "S3-Website"
    viewer_protocol_policy = "redirect-to-https"
    allowed_methods = ["GET", "HEAD"]
    cached_methods  = ["GET", "HEAD"]
  }

  viewer_certificate {
    cloudfront_default_certificate = true
  }
}

3. Deploy with Terraform

  1. Initialize Terraform:

     terraform init
    
  2. Plan Resources:

     terraform plan
    
  3. Apply Configuration:

     terraform apply
    

Terraform will provision all AWS resources, including the S3 bucket, CloudFront distribution, and OAI.


4. Upload Static Files to S3

Use the AWS CLI to sync files to S3:

aws s3 sync ./out s3://portfolio-website-bucket

Lessons Learned

  1. Managing Dependencies:

    • Ensuring resources like the bucket policy and OAI are created in the correct order was crucial.
  2. Debugging Terraform Issues:

    • Dealing with common Terraform errors (e.g., invalid attributes or missing dependencies) helped reinforce my understanding of AWS services.
  3. Global Reach and Performance:

    • Testing the site after deploying through CloudFront demonstrated significant performance improvements compared to direct S3 hosting.

Conclusion

Building this portfolio project with Terraform, S3, and CloudFront was a rewarding experience. It allowed me to create a professional-grade website with scalability and performance in mind while learning more about AWS and Infrastructure as Code.

If you have any questions or suggestions, feel free to reach out in the comments or connect with me!