Introduction This project showcases how to deploy a React.js web application from start to finish using AWS services, automation tools, and infrastructure as code (IaC). The main goal is to create a scalable infrastructure using CI/CD pipelines, automated resource scaling, and Terraform for one-click deployment.
- React.js Web Application Deployment: Cloning the React.js app from GitHub, building, testing, and deploying it via AWS CI/CD pipeline.
- Deployment to EC2 and S3: Hosting the application on EC2 instances and S3 for static hosting.
- CI/CD Pipeline with AWS CodePipeline: Automating the build, test, and deployment processes.
- Auto-Scaling: Automatically adjusting the number of instances based on traffic.
- One-Click Deployment Using Terraform: Automating the AWS resource setup with Terraform.
- Deployment: Deploy the React app with manual steps.
- Auto-Scaling: Adjust system resources automatically based on traffic.
- Security: Follow AWS security practices.
- Automation: Use Terraform for reliable and repeatable AWS setup.
To start, clone the React.js application’s source code from GitHub:
git clone https://github.com/react-navigation/create-react-app-example
Configure an EC2 instance for hosting the web application. Prior to that these are the following steps to create and configure VPC, subnets, route tables, and security groups.
EC2 (Elastic Compute Cloud) is good for hosting dynamic content and applications that need backend processing:
- Customizable Server: Full control over the operating system and software.
- Scalability: Ability to change capacity based on traffic.
- Security: Options to control traffic with security settings.
Before creating an EC2 instance, several configurations need to be set up to ensure a secure and functioning environment.
Purpose: A VPC isolates our resources in a private network, giving us control over IP address ranges, subnet configuration, routing, and internet access.
- How to Set Up:
- Go to the AWS Console > VPC Dashboard > Create VPC.
- Configure with a CIDR block, e.g.,
10.0.0.0/16
. - Click on AWS (top left corner).
- Enter the VPC dashboard.
- A list of services will pop up.
- Select VPC.
-
Click on Create VPC and configure the settings as follows:
-
Name Tag: Assign a recognizable name, e.g.,
MyProjectVPC
. -
IPv4 CIDR Block: Set the range, such as
10.0.0.0/14
. This range provides 65,536 IP addresses, adequate for dividing into multiple subnets. -
IPv6 CIDR Block: Optional, only if you need IPv6 support. For most web applications, IPv4 is sufficient.
-
Tenancy: Choose Default unless you have specific reasons to opt for dedicated tenancy, which isolates hardware but incurs a higher cost.
-
- After creating the VPC, we need to divide it into smaller networks (subnets).
- Click on Subnets on the left-hand menu, then select Create Subnet.
- Name Tag: Provide a clear name such as
PublicSubnet
,AppSubnet
, orDBSubnet
to indicate their roles. - Availability Zone: Optionally select an availability zone to distribute resources for high availability.
- IPv4 CIDR Block: Define the IP range for each subnet, ensuring they are within our VPC's range and do not overlap.
Configuration for PublicSubnet.
We can clearly see the Subnet’s are successfully created
- Purpose: Route tables determine how network traffic is directed within the VPC.
- Go to Route Tables in the VPC Dashboard.
- Create a route table for your VPC, and name it appropriately (e.g.,
PublicRouteTable
). - Associate Subnets:
- Attach the
PublicRouteTable
to your Public Subnet.
- Attach the
Click on Create route table.
As, we can see, the route table, was successfully created!
- Purpose: Allows resources in the VPC to access the internet.
- Create an Internet Gateway and attach it to your VPC.
- Modify the route table of the public subnet to route internet-bound traffic through the Internet Gateway.
- Click on Create Internet Gateway in the top-right corner. .
The Internet gateway was made successfully. But it is in a "detached" state because we didn’t connect it to a VPC. To change it to "attached," click on “Attach to a VPC” in the top right corner.
Attach to the VPC, which we created earlier
We can see now, the state of the IGW is in Attached state, this means we successfully attached the IGW to the VPC of our current project
- Purpose: Security groups act as virtual firewalls, controlling incoming and outgoing traffic.
We can see, web-server LB has been created
We need to launch EC2 instances for our web, app, and database tiers. This step occurs after setting up the network components.
- Go to the search bar, type EC2, and tap on EC2 Dashboard.
For launching the EC2 instance in the web subnet (e.g., 10.0.1.0/24
) to host our React.js application:
- Configuration: Choose an appropriate Amazon Machine Image (AMI), such as Amazon Linux, and select an instance type (e.g.,
t2.micro
for development). - Security Group: Attach the security group that allows HTTP (port 80) and HTTPS (port 443) traffic.
Note: I’m using AMI because we’re implementing CI/CD with AWS CodePipeline. It’s cost-effective and performs well, so I chose AMI.
- Click on Instances in the left-hand menu to view all your running EC2 instances.
- Check the Instance State. Ensure it says "running." If it's in a different state (e.g., "stopped"), you’ll need to start the instance.
This method allows you to connect to your instance directly from the browser without needing an SSH client or key pair. However, this works only for instances that support EC2 Instance Connect (e.g., Amazon Linux 2, Ubuntu 20.04).
-
Navigate to EC2 Dashboard:
- Go to the AWS Management Console.
- Select EC2 from the services list or search for it in the search bar.
-
Select the Instance:
- In the Instances section, find the instance you want to connect to.
- Ensure the instance state is running.
-
Click the Connect Button:
- Select the instance and click the Connect button at the top of the page.
-
Choose the EC2 Instance Connect Method:
- By default, the EC2 Instance Connect tab will be selected.
-
Enter User Details (if needed):
- In most cases, for Amazon Linux or Ubuntu, the default user is already set to
ec2-user
orubuntu
.
- In most cases, for Amazon Linux or Ubuntu, the default user is already set to
Click on Connect
Here we can see, we successfully logged in to the machine:
Next we can, clone the github repo, here
Amazon Linux 2 doesn’t come with Node.js installed by default, so we need to install it first to run a React app.
sudo yum update -y
Amazon Linux 2 doesn’t have the latest Node.js version in its default repositories. The best practice is to use NVM (Node Version Manager) to install the version of Node.js that your React app requires.
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash
You can close and reopen your terminal, or use the command below:
source ~/.bashrc
nvm install --lts
node -v
This layout maintains clarity with headings and code blocks, making it easy for users to follow. You can paste this directly into your README file. If you have more content to add or need any modifications, just let me know!
Once you have cloned the project, change to the project’s directory. For example, assuming the project was cloned to ~/create-react-app-example
, use the following command:
cd ~/create-react-app-example
Now that you are in the project directory and have Node.js installed, install the project’s dependencies using npm. This will read the package.json file in your React project and install all the necessary dependencies listed under dependencies.
npm install
If you’re planning to deploy your React application, you will need to build it first. This process compiles the app into static files that can be served.
To build the application, use the following command:
npm run build
If we want to test the app locally (for development or debugging), we can use the following command
Now we can go with the Public address, of the EC2 instance
We’re going to append the port :3000 to the public IPLike this ( http://13.201.67.239:3000 )
The site is now fetching from the machine and is publicly accessible.
Log in to the AWS Console:
- Open your browser and navigate to the AWS Console.
Search for CodePipeline:
- In the AWS Console, locate the search bar at the top.
- Type
CodePipeline
in the search bar and select it from the list.
Create Pipeline:
- Once inside the CodePipeline service, click on the Create Pipeline button to begin setting up your continuous integration and continuous delivery (CI/CD) pipeline.
Configure the Pipeline Settings:
- Pipeline Name: Enter a unique name for the pipeline.
- Service Role: Select the default AWS-managed service role unless you want to specify a custom role.
- Click Next to proceed to the next step of the pipeline setup.
Source Provider:
- Select
GitHub
.
Repository:
- Sign in to GitHub if not already authenticated.
- Choose the GitHub repository where the React app is hosted.
Branch:
- Select the branch (usually
Main
) from which the code should be pulled.
Click Next to proceed.
-
Build Provider: Select
AWS CodeBuild
. -
Create a New Build Project (if you don’t have one):
-
Project Name: Enter a name for the build project.
-
Environment:
- Managed Image: Choose the environment image, for example, select "Ubuntu" as the operating system and "Node.js" as the runtime.
-
Build Specification: Use the built-in editor to define the build steps for the React app.
-
After we click on next step, site will ask to leave, means the information, is saved, and its going to prior site, which we can see continuation of the steps
Service Role: We can use the default service role or create a new one with the necessary permissions (like access to GitHub, S3, or EC2).
Click on S3 >
Later it shows error in the bucket, this pop-up because we did’nt created any S3 bucket yet
To troubleshoot this issue, now we need to go to Amazon service console: and type S3
And select the option, and later click on Create Bucket
-
Bucket Name: Enter a globally unique name for the bucket (e.g.,
my-react-app-bucket
). Bucket names must be unique across all of AWS and can only contain lowercase letters, numbers, hyphens, and periods. -
Region: Select the AWS Region where you want the bucket to be created (e.g., Asia Pacific (Mumbai)
ap-south-1
).
- Block Public Access Settings: By default, S3 blocks all public access. If you intend to host a public static website, you will need to uncheck the box for "Block all public access" after creating the bucket. You can also set permissions later.
Review and Create: – Review the settings and click on the Create bucket button.
- After creating the bucket, you need to adjust the bucket policy to allow public access. To do this:
- Select the newly created bucket.
- Go to the Permissions tab.
- Click on Bucket Policy and add a policy that looks something like this (replace
my-react-app-3
with your bucket name):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-react-app-bucket/*"
}
]
}
- Since you’re hosting a static site:
- Go to the Properties tab of your bucket.
- Scroll down to the Static website hosting section.
- Click on Edit, select Use this bucket to host a website, and specify
index.html
as the Index document.
We’re going to Objects > Upload Files: · we can now upload files to our bucket or configure our CodePipeline to deploy to this bucket.
Click on Upload
Now we can see. It shows the bucket we created!
Click on next, and click on Create pipeline!
We successfully automated the entire process of building, testing, and deploying the application.
To automatically increase the number of EC2 instances during high traffic, you can set up Auto Scaling in AWS. Here’s a quick guide:
-
Create Launch Configuration: Define how new instances should be configured (AMI, instance type, etc.).
-
Set Up Auto Scaling Group:
- Go to EC2 Dashboard → Auto Scaling Groups → Create Auto Scaling Group.
- Select your launch configuration.
- Specify the minimum and maximum number of instances (e.g., min=1, max=5).
-
Configure Scaling Policies:
- Create policies to scale out (add instances) when CPU usage exceeds a certain threshold (like 70%).
- Set policies to scale in (remove instances) when usage drops below a lower threshold (like 30%).
-
Attach to Load Balancer (if needed): If you’re using a load balancer, attach it to your Auto Scaling group to distribute traffic evenly.
-
Designed a Terraform runbook that simplifies the setup of AWS resources. This one-click deployment script eliminates the need for manual setup, maintains consistency, and allows for quick changes or copies of the setup when needed.
-
With Terraform’s infrastructure as code approach, you can reduce mistakes and make deployment simple.
# Setting up the AWS provider to use in this config
provider "aws" {
region = "us-east-1" # Where in the world our resources will live
}
# Creating a VPC to keep our resources organized and isolated
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16" # Defining the IP range for our VPC
}
# Now, let's create a public subnet within that VPC
resource "aws_subnet" "public" {
vpc_id = aws_vpc.main.id # Telling it which VPC to use
cidr_block = "10.0.1.0/24" # This is the IP range for our subnet
}
# Time to spin up an EC2 instance for our React app
resource "aws_instance" "react_app" {
ami = "ami-0c55b159cbfafe1f0" # The AMI ID we need (make sure it's suitable for your region!)
instance_type = "t2.micro" # Choosing a small instance type (perfect for testing!)
subnet_id = aws_subnet.public.id # Putting this instance in our public subnet
tags = { # Adding some tags to make this instance easy to identify
Name = "ReactAppServer" # Giving it a friendly name
}
}
# Let's create an S3 bucket to host our React app
resource "aws_s3_bucket" "react_app_bucket" {
bucket = "my-react-app-bucket" # Pick a unique name for your bucket (this one needs to be global)
acl = "public-read" # Allow public read access, so anyone can see our app
# Setting this bucket up for static website hosting
website {
index_document = "index.html" # This is the homepage for our site
}
}
# Uploading the built React app's index.html to our S3 bucket
resource "aws_s3_bucket_object" "react_app" {
bucket = aws_s3_bucket.react_app_bucket.bucket # Referring to our bucket created above
key = "index.html" # Name of the file in the bucket
source = "build/index.html" # Path to the built file we want to upload
acl = "public-read" # Making sure it’s publicly readable
}
# Outputting the website URL for easy access
output "s3_website_url" {
value = aws_s3_bucket.react_app_bucket.website_endpoint # This is the link to our S3 website
}
Give a ⭐️ if this project helped you, Happy learning!