How to deploy an application on EC2 using Terraform

Key takeaways:

  • Terraform provisions infrastructure as code (IaC), facilitating safe, efficient infrastructure management.

  • A security group is created to allow only public port 3000, ensuring limited access to the EC2 instance.

  • EC2 instance configuration includes setting AMI, instance type, and storage, attaching the security group.

  • Ingress allows incoming TCP traffic on port 3000; egress permits all outbound traffic.

  • An EC2 instance is created to run a React app, cloned from GitHub, using a user data script.

  • The user data script installs Git, Node.js, and the app upon instance launch.

  • Terraform blocks define an output variable for the instance’s public IP.

  • After writing and configuring Terraform code, initialize (terraform init), plan (terraform plan), and apply (terraform apply) to provision infrastructure.

  • The app can be accessed via the instance’s public IP with port 3000 post-provisioning.

Terraform is a software tool utilized to provision Infrastructure as code (IaC). Terraform is used for building, editing, and versioning infrastructure safely and efficiently.

Now, we will create a security group and set up a React application on an EC2 instance. The security group will only use public port 3000 to ensure the security of the EC2 instance.

First, we will look into the code and then provision the infrastructure. At the end, let's look at how we can create a security group. Then, we’ll launch an EC2 instance to host a React application. We’ll configure the instance by specifying its AMIAMI stands for Amazon Machine Image. It is a pre-configured template in Amazon Web Services (AWS) that contains the operating system, application server, and applications you need to launch an instance in Amazon EC2 (Elastic Compute Cloud), instance type, and storage, attaching the security groupIn AWS, a security group acts as a virtual firewall that controls inbound and outbound traffic to EC2 instances. It is stateful, automatically allowing return traffic, and uses rules based on IP protocol, port range, and IP addresses. Security groups can be associated with multiple instances, and changes to rules are applied immediately without needing to restart the instances. we previously created.

Here is an architecture diagram of the provisioned infrastructure.

Architecture diagram
Architecture diagram

Create a security group

A security group controls the inbound and outbound traffic for an associated resource. In other words, it acts as a firewall for the resource. We will create a security group to allow limited access to our EC2 instance; the security group instance_sg will only use public port 3000 to ensure the security of the EC2 instance. 

resource "aws_security_group" "instance_sg" {
name = "allow-port-3000"
description = "Allow incoming traffic on port 3000"
ingress {
from_port = 3000
to_port = 3000
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"] # Allow traffic from any source IP
}
egress {
from_port = 0
to_port = 0
protocol = "-1" # Allow all outbound traffic
cidr_blocks = ["0.0.0.0/0"]
}
}

Note: Ingress refers to the rules that control incoming traffic to your instances. In the provided example, the ingress block allows incoming TCP traffic on port 3000 from any source IP address (0.0.0.0/0)

Egress refers to the rules that control outgoing traffic from your instances. In the provided example, the egress block allows all outbound traffic to any IP address (0.0.0.0/0) on all ports and protocols.

Explanation

Let’s take a look at the above code and understand it block by block. 

  • Lines 1–17: This block defines an AWS security group named allow-port-3000 that allows incoming TCP traffic on port 3000 from any source IP and allows all outbound traffic.

    • Lines 5–10: Allows incoming TCP traffic on port 3000 from any IP address (0.0.0.0/0).

    • Lines 11–16: Permits all outbound traffic on any port and protocol to any IP address (0.0.0.0/0).

Create an EC2 instance

widget

Amazon Elastic Compute Cloud (EC2) provides resizable computing capacity in the cloud.

It allows users to run virtual servers, known as instances, for various computing tasks. EC2 offers a secure, flexible, and scalable solution, enabling businesses to easily deploy, manage, and scale applications without investing in physical hardware.

We have created a security group that only allows inbound traffic on port 3000. Now, we will create an EC2 instance, such that we will add a script to clone the application from GitHub and run it in the user data of our EC2 instance. 

resource "aws_instance" "my_app"{
ami= "ami-0fa1ca9559f1892ec"
instance_type= "t2.micro"
key_name= null
security_groups = [aws_security_group.instance_sg.name]
user_data=<<-EOF
#!/bin/bash
sudo yum -y update &&\
sudo yum -y install git &&\
sudo yum install https://rpm.nodesource.com/pub_16.x/nodistro/repo/nodesource-release-nodistro-1.noarch.rpm -y &&\
sudo yum install nodejs -y --setopt=nodesource-nodejs.module_hotfixes=1 &&\
git clone https://github.com/Educative-Content/my-reactapp.git &&\
cd my-reactapp &&\
npm install &&\
npm start
EOF
tags={
Name="clab-app"
}
}
output "public_ip" {
value = aws_instance.my_app.public_ip
}

Explanation

Let’s take a look at the above code and understand it block by block. 

  • Lines 1–23: This block defines an AWS EC2 instance named my_app. It specifies the Amazon Machine Image (AMI)An Amazon Machine Image (AMI) is a pre-configured template for EC2 instances that includes the operating system, application server, and applications. It allows you to quickly launch new instances with identical configurations., instance type, security group, user data script, and tags. The user data script installs Git, Node.js, and a React app from a GitHub repository when the instance is launched.

  • Lines 24–26: This block defines an output variable named public_ip that retrieves the public IP address of the EC2 instance.

Now that we have a clear understanding of each Terraform block we are going to use, let’s provision the infrastructure.

Configure resources

We have put together the above-discussed code and a new Terraform provider block that uses credentials to access the mentioned AWS account and deploy infrastructure in the specified region.

provider "aws"{
    region="us-east-1"
}
resource "aws_security_group" "instance_sg" {
  name        = "allow-port-3000"
  description = "Allow incoming traffic on port 3000"

  ingress {
    from_port   = 3000
    to_port     = 3000
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]  # Allow traffic from any source IP
  }
    egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"  # Allow all outbound traffic
    cidr_blocks = ["0.0.0.0/0"]
  }
}
resource "aws_instance" "my_app"{
    ami= "ami-0fa1ca9559f1892ec"
    instance_type= "t2.micro"
    key_name= null
    security_groups  = [aws_security_group.instance_sg.name]

    user_data=<<-EOF
    #!/bin/bash
    sudo yum -y update &&\
    sudo yum -y install git &&\
    sudo yum install https://rpm.nodesource.com/pub_16.x/nodistro/repo/nodesource-release-nodistro-1.noarch.rpm -y &&\
    sudo yum install nodejs -y --setopt=nodesource-nodejs.module_hotfixes=1 &&\
    git clone https://github.com/Educative-Content/my-reactapp.git &&\
    cd my-reactapp &&\
    npm install &&\
    npm start
    EOF


    tags={
        Name="clab-app"
    }
}
output "public_ip" {
  value = aws_instance.my_app.public_ip
}
Configure resources as code

Click the “Run” button and type the following command to initialize the terraform directory, terraform init is used to resolve and install dependencies.

After initializing the directory, use terraform plan to see the execution plan; it’s an optional step. After this, execute the configuration file using terraform apply, it asks for confirmation, then type yes, and then Terraform will create the requested infrastructure.

terraform init
terraform apply

Note: The application may take upto three minutes to be available after running the EC2 instance.

Copy the public IP from the terminal, paste it into the address bar of the new web page, and add the port 3000 at the end.

<Public_IP_Address>:3000

Congratulations! Our application is live.

Conclusion

In conclusion, deploying an application on EC2 using Terraform allows for a streamlined and automated infrastructure setup.

By defining resources such as security groups and EC2 instances in code, we not only ensure a consistent deployment process but also gain flexibility to easily scale or modify the infrastructure. This approach simplifies application management, enabling secure, efficient, and repeatable deployments directly from the command line.

With Terraform’s infrastructure-as-code capabilities, we can focus more on application functionality while leaving infrastructure provisioning and management to automated, reliable scripts.

Frequently asked questions

Haven’t found what you were looking for? Contact Us


Can Terraform be used for application deployment?

Yes, Terraform can deploy applications by provisioning the required infrastructure and automating setup processes.


What is a 3-tier application using Terraform?

A 3-tier application in Terraform typically involves provisioning a setup with a presentation layer (e.g., frontend servers), application layer (e.g., backend servers), and data layer (e.g., database servers), all managed as code.


What is the API limit for Terraform?

Terraform itself does not have an API limit, but API limits are determined by the provider services (e.g., AWS, Azure) it interacts with.


Is Terraform an API?

No, Terraform is not an API. It is an Infrastructure as code (IaC) tool that uses provider APIs to provision and manage resources.


Is Terraform written in YAML or JSON?

Though JSON is also supported, Terraform configurations are primarily written in HashiCorp configuration language (HCL).


Free Resources

Copyright ©2025 Educative, Inc. All rights reserved