Deploying an Angular App to AWS S3 using Terraform - Part 1
Hey there !! 🦥 In this blog, I will demonstrate how to automate the deployment of an Angular web application to AWS S3 using Terraform. By the end of this tutorial, you'll have a fully automated setup to push static files from your Angular project to an S3 bucket, making it accessible via an S3 website endpoint.
Prerequisites
Before we begin, make sure you have the following tools installed:
Terraform: Install Terraform
AWS CLI: Install AWS CLI
Angular Project: You should have an Angular project built and ready to be deployed.
AWS Account: You'll need an active AWS account with appropriate permissions to create and manage S3 buckets.
Let’s quickly set the above prerequisites 🤸
( For Terraform and AWS Cli installation & configuration please refer appendix )
Set Up Your Angular Project
Ensure your Angular project is built and ready for deployment. If you haven't built it yet follow the below steps.
Github repo : AasifaShaik029/reactive-form-angular: Implementing reactive forms in angular (github.com)
Let’s install node and angular CLI.
git clone https://github.com/AasifaShaik029/reactive-form-angular.git
cd reactive-form-angular
node -v
nvm install v20.17.0
npm install -g @angular/cli
ng version
npm install
npm outdated
npm update
npm install
ng build
ng serve
🌷ng build command builds the application for production (or for deployment), generating optimized static files in the dist/
directory. You can see dist folder is created once we run the ng build command.
🌷The dist/
folder is crucial because it includes all the necessary files (HTML, CSS, JavaScript, and other assets) your application needs to run in a production environment. When you deploy your application, you'll typically upload the contents of this dist/
folder to your server or hosting service.
🪻The ng serve
command is used to start a development server for your Angular application. ( to check if app is running )
🪻 open http://localhost:4200/ to see the angular app running.
Initialize Terraform Configuration
Create a file called main.tf
and configure the necessary resources for your S3 bucket.
Here's the full Terraform configuration: ( main.tf )
provider "aws" {
region = "eu-west-1"
}
variable "bucket_name" {
default = "angular-reactive-form-002"
}
variable "mime_types" {
default = {
htm = "text/html"
html = "text/html"
css = "text/css"
ttf = "font/ttf"
js = "application/javascript"
map = "application/javascript"
json = "application/json"
ico = "image/x-icon"
}
}
# Use locals for the upload directory instead of variables
locals {
upload_directory = "${path.cwd}/dist/app/browser/"
}
resource "aws_s3_bucket" "reactive_form" {
bucket = var.bucket_name
website {
index_document = "index.html"
error_document = "index.html"
}
}
resource "aws_s3_bucket_public_access_block" "s3_public_block" {
bucket = aws_s3_bucket.reactive_form.id
block_public_acls = false
block_public_policy = false
ignore_public_acls = false
restrict_public_buckets = false
}
resource "aws_s3_bucket_ownership_controls" "s3_ownership" {
bucket = aws_s3_bucket.reactive_form.id
rule {
object_ownership = "BucketOwnerPreferred"
}
}
resource "aws_s3_bucket_policy" "allow_public_access" {
bucket = aws_s3_bucket.reactive_form.id
policy = data.aws_iam_policy_document.allow_public_access.json
}
data "aws_iam_policy_document" "allow_public_access" {
statement {
actions = ["s3:GetObject"]
principals {
type = "AWS"
identifiers = ["*"]
}
resources = [
"arn:aws:s3:::${var.bucket_name}/*"
]
effect = "Allow"
}
}
resource "aws_s3_object" "website_files" {
for_each = fileset(local.upload_directory, "**/*.*")
bucket = aws_s3_bucket.reactive_form.bucket
key = replace(each.value, local.upload_directory, "")
source = "${local.upload_directory}${each.value}"
acl = "public-read"
content_type = lookup(var.mime_types, split(".", each.value)[length(split(".", each.value)) - 1], "application/octet-stream")
}
output "website_domain" {
value = aws_s3_bucket.reactive_form.website_domain
}
output "website_endpoint" {
value = aws_s3_bucket.reactive_form.website_endpoint
}
Explanation of Code:
Provider Block: Specifies AWS as the cloud provider and sets the region.
Variables: Defined for the S3 bucket name and file MIME types.
Local Block: We define upload_directory using path.cwd to point to the folder where the build files are located.
S3 Bucket Resource: Creates the S3 bucket with website hosting enabled.
Public Access Block: Ensures that the bucket is publicly accessible by disabling public access restrictions.
Ownership Controls: Ensures that ownership of objects is managed by the bucket owner.
S3 Object Resource: Uploads files from the build directory to the S3 bucket. The fileset function is used to read all files in the directory, and content_type is set dynamically based on file extensions.
Outputs: Displays the website domain and endpoint after deployment
Open the command prompt from the file location and execute the below commands.
# This will download the necessary provider plugins and prepare your workspace.
terraform init
terraform apply
# Terraform will show a preview of the resources it will create. Type yes to confirm the deployment.
terraform apply
Access Your Angular App
You can now access your Angular app using the S3 website URL. The URL will be similar to the following format:
http://angular-reactive-form-002.s3-website.eu-west-1.amazonaws.com
Under properties —> static website hosting —> copu URL
In this tutorial, we used Terraform to deploy an Angular web application to an S3 bucket. This is a great way to automate your deployment process and ensure your app is always available via the S3 static site hosting. With the added advantage of using Terraform, you can now version control your infrastructure and collaborate with your team effortlessly.
Appendix
Terraform installation
Please refer below blog for Terraform installation process.
Terraform Installation - Step by Step (hashnode.dev)
AWS CLI Installation and Configuration
Please refer below blog for AWS CLI installation & configuration process.
Subscribe to my newsletter
Read articles from Aasifa Shaik directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Aasifa Shaik
Aasifa Shaik
I am a DevSecOps Engineer at Renesas, where I specialize in integrating security practices within the DevOps pipeline. My work focuses on automating security, ensuring compliance, and securing applications throughout their lifecycle.