Deploy a Static Website in AWS S3 Using Terraform

Deploy a Static Website in AWS S3 Using Terraform

Individuals and businesses must have a web presence in today's digital world. Whether you're a developer trying to exhibit your portfolio or a firm launching a new product, rapidly and efficiently creating a website is critical. Amazon Web Services (AWS) delivers a dependable and cost-effective hosting platform. Terraform is a sophisticated infrastructure-as-code tool for defining and provisioning AWS resources. This blog will walk you through deploying a static website in AWS S3 using Terraform.

Prerequisites

Before we dive into the deployment process, make sure you have the following prerequisites in place:

  1. AWS Account: You need an AWS account to access AWS services.

  2. Terraform Installed: Download and install Terraform from the official website.

  3. AWS CLI: Install the AWS Command Line Interface (CLI) and configure it with your AWS credentials. You can install it from here.

  4. Static Website Files: Prepare the static website files (HTML, CSS, JavaScript, images, etc.) you want to deploy. Place them in a directory.

Steps to Deploy a Static Website in AWS S3 Using Terraform

Let's start by setting up your Terraform configuration. Create a file named main.tf and add the following code:

Step 1: AWS Provider Configuration

provider "aws" {
  region     = "us-east-1" # Change this to your desired region
  access_key = "your key" # Add your AWS access key ID here
  secret_key = "your secret key" # Add your AWS secret access key here
}

This block configures the AWS provider, specifying the AWS region and your access key and secret key. It tells Terraform which cloud provider to interact with and how to authenticate.

Step 2: S3 Bucket Resource

resource "aws_s3_bucket" "my-static-website" {
  bucket = "mydemostaticwebsite-2324413" # give a unique bucket name
  tags = {
    Name = "my-demo-static-website"
  }
}

Here, you define an S3 bucket resource using the aws_s3_bucket resource type. It creates an S3 bucket with the specified name and sets tags to provide metadata for the bucket.

Step 3: S3 Bucket Website Configuration

resource "aws_s3_bucket_website_configuration" "my-static-website" {
  bucket = aws_s3_bucket.my-static-website.id

  index_document {
    suffix = "index.html"
  }

  error_document {
    key = "error.html"
  }
}

This block configures the S3 bucket to act as a static website. It specifies the index document (the default file to load when accessing the website's root) and the error document (the page to display 404 errors).

Step 4: S3 Bucket Ownership Controls

resource "aws_s3_bucket_ownership_controls" "my-static-website" {
  bucket = aws_s3_bucket.my-static-website.id
  rule {
    object_ownership = "BucketOwnerPreferred"
  }
}

This block sets up ownership controls for the S3 bucket, ensuring that the bucket owner is preferred for objects within the bucket.

Step 5: S3 Bucket Public Access Block

resource "aws_s3_bucket_public_access_block" "my-static-website" {
  bucket = aws_s3_bucket.my-static-website.id

  block_public_acls       = false
  block_public_policy     = false
  ignore_public_acls      = false
  restrict_public_buckets = false
}

Here, you configure the public access block settings for the S3 bucket. In this example, public access is allowed for various locations. You can adjust these settings based on your security requirements.

Step 6: S3 Bucket ACL

resource "aws_s3_bucket_acl" "my-static-website" {
  depends_on = [
    aws_s3_bucket_ownership_controls.my-static-website,
    aws_s3_bucket_public_access_block.my-static-website,
  ]

  bucket = aws_s3_bucket.my-static-website.id
  acl    = "public-read"
}

This block sets the bucket access control list (ACL) for the S3 bucket, allowing public read access. It depends on the previous two blocks to ensure proper ownership controls and public access settings.

Step 7: Create an index.html and upload the index.html File to S3 Bucket

Keep index.html in the same directory where main.tf is located.

resource "aws_s3_object" "index_html" {
  bucket       = aws_s3_bucket.my-static-website.id
  key          = "index.html"  # The name you want for the file in the S3 bucket
  source       = "index.html"  # The path to your local index.html file
  content_type = "text/html"

  # Make the object publicly accessible
  acl = "public-read"
}

This block uploads the index.html file from your local directory to the S3 bucket. It also sets the content type and makes the object publicly accessible.

Step 8: S3 Static Website URL Output

output "website_url" {
  value = "http://${aws_s3_bucket.my-static-website.bucket}.s3-website.us-east-1.amazonaws.com"
}

This block defines an output variable that displays the URL of your static website after Terraform applies the configuration. The URL is constructed using the bucket name and the S3 website endpoint.

Step 9: S3 Bucket Policy

resource "aws_s3_bucket_policy" "bucket-policy" {
  bucket = aws_s3_bucket.my-static-website.id

  policy = <<POLICY
{
  "Id": "Policy",
  "Statement": [
    {
      "Action": [
        "s3:DeleteObject",
        "s3:GetObject",
        "s3:ListBucket",
        "s3:PutObject",
        "s3:PutObjectAcl"
      ],
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::mydemostaticwebsite-2324413/*",
        "arn:aws:s3:::mydemostaticwebsite-2324413"
        ],
      "Principal": "*"
    }
  ]
}
POLICY
}

This block defines an S3 bucket policy that allows various actions on objects within the bucket and sets the principal to "*" (anyone). This policy ensures public access to the bucket's contents.

Step 10: Overall Code

The overall above code looks like this.

# main.tf

# Configure the AWS provider with your credentials and desired region
provider "aws" {
  region     = "us-east-1" # Change this to your desired region
  access_key = "your key"  # Add your AWS access key ID
  secret_key = "your secret key"  # Add your AWS secret access key here
}

# Create an S3 bucket and website configuration
resource "aws_s3_bucket" "my-static-website" {
  bucket = "mydemostaticwebsite-2324413" # give a unique bucket name
  tags = {
    Name = "my-demo-static-website"
  }
}

resource "aws_s3_bucket_website_configuration" "my-static-website" {
  bucket = aws_s3_bucket.my-static-website.id

  index_document {
    suffix = "index.html"
  }

  error_document {
    key = "error.html"
  }
}

resource "aws_s3_bucket_ownership_controls" "my-static-website" {
  bucket = aws_s3_bucket.my-static-website.id
  rule {
    object_ownership = "BucketOwnerPreferred"
  }
}

resource "aws_s3_bucket_public_access_block" "my-static-website" {
  bucket = aws_s3_bucket.my-static-website.id

  block_public_acls       = false
  block_public_policy     = false
  ignore_public_acls      = false
  restrict_public_buckets = false
}

resource "aws_s3_bucket_acl" "my-static-website" {
  depends_on = [
    aws_s3_bucket_ownership_controls.my-static-website,
    aws_s3_bucket_public_access_block.my-static-website,
  ]

  bucket = aws_s3_bucket.my-static-website.id
  acl    = "public-read"
}

# Upload index.html from the current directory to the S3 bucket and make it public
resource "aws_s3_object" "index_html" {
  bucket       = aws_s3_bucket.my-static-website.id
  key          = "index.html"  # The name you want for the file in the S3 bucket
  source       = "index.html"  # The path to your local index.html file
  content_type = "text/html"

  # Make the object publicly accessible
  acl = "public-read"
}

# S3 static website URL
output "website_url" {
  value = "http://${aws_s3_bucket.my-static-website.bucket}.s3-website.us-east-1.amazonaws.com"
}

# S3 bucket policy
resource "aws_s3_bucket_policy" "bucket-policy" {
  bucket = aws_s3_bucket.my-static-website.id

  policy = <<POLICY
{
  "Id": "Policy",
  "Statement": [
    {
      "Action": [
        "s3:DeleteObject",
        "s3:GetObject",
        "s3:ListBucket",
        "s3:PutObject",
        "s3:PutObjectAcl"
      ],
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::mydemostaticwebsite-2324413/*",
        "arn:aws:s3:::mydemostaticwebsite-2324413"
        ],
      "Principal": "*"
    }
  ]
}
POLICY
}

Step 11: Deploying Your Static Website

  1. Open your terminal and navigate to the directory containing your main.tf file.

  2. Run the following Terraform commands:

     terraform init
    

    terraform init primarily initializes the AWS provider, installs the required provider plugin, validates the configuration files, sets up a local backend for state management, and prepares the project directory for further Terraform commands like terraform plan and terraform apply.

     terraform apply --auto-approve
    

    In the provided Terraform code, running terraform apply --auto-approve initiates applying infrastructure changes defined in the configuration without requiring manual confirmation. It automates the approval of changes, executes the planned actions, and provides the output, including the URL of the static website, as specified in the configuration. Use this flag cautiously and ensure you've reviewed your configuration carefully before applying changes, especially in production environments.

     Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
    
     Outputs:
    
     website_url = "http://mydemostaticwebsite-2324413.s3-website.us-east-1.amazonaws.com"
    

    Once the deployment is complete, Terraform will display the URL of your static website. You can access your website using this URL.

    On clicking the website_url, you can access your webpage.

    Conclusion

    In this blog post, you've learned how to create a static website on Amazon S3 using Terraform. By automating the infrastructure setup with Terraform, you can quickly deploy and manage your static websites on AWS. This approach provides a cost-effective and scalable solution for hosting your web content. Start building and deploying your static websites on AWS today!

Did you find this article valuable?

Support Anup kafle by becoming a sponsor. Any amount is appreciated!