# Step-by-Step Guide: Deploying a React-Node.js Application on Amazon EC2

[Here is a link to our GitLab where you can find all the code used in this tutorial.](https://gitlab.com/9-aws-service/react-nodejs-app)

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1742695414621/99b04383-8d61-45d5-b536-90ccca6d7b8a.png align="center")

# **Prerequisites:**

* AWS account
    
* Docker Hub Account
    
* Basic Docker knowledge and experience
    
* Basic Linux knowledge and experience
    
* Basic SSH and networking knowledge and experience
    

# **Objectives:**

* Create and configure an AWS EC2 instance.
    
* Install Docker on the EC2 instance.
    
* Fetch an image from a private Docker repository on Docker Hub.
    
* Start a Docker container using the fetched image on the EC2 instance.
    
* Configure external access to the application from a web browser.
    
* Access the App
    

## **1-Create an AWS EC2 instance.**

Amazon EC2 (Elastic Compute Cloud) is a web service provided by Amazon Web Services (AWS) that offers scalable computing capacity in the cloud. It allows users to rent virtual servers, known as instances, to run applications and services. So as a simple use case, we're going to deploy a web application on ec2 instance.

* **Launch an EC2 Instance**:
    
    * Go to the AWS Management Console.
        
    * Navigate to EC2 &gt; Instances &gt; Launch Instance.
        

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1742655458191/91fd06f0-53a6-4dda-90d9-b1ecfe20ac62.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1742655513357/bd24096e-4de9-4739-b528-ba2d480f3d79.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1742655699389/f4e72922-0b72-468b-9e1f-949b86b8692d.png align="center")

At this point, you can add a name and optionally a tag to your EC2 instance to help identify and manage it more easily. Since your EC2 instance named `my-instance` is hosting Docker, tagging it with `server-with-docker` is a useful way to categorize and identify its purpose.

Choosing the right Amazon Machine Image (AMI) is crucial for the successful deployment and operation of your application on an EC2 instance. By carefully evaluating factors such as the operating system, pre-installed software, security updates, community support, cost, and customization needs, you can select an AMI that aligns with your technical requirements and operational goals.

For our demo, selecting the `Amazon Linux 2023 AMI , t2.micro` that is free tier eligible is an excellent choice.

### Key Pair (Login):

A key pair in AWS is a set of security credentials used to securely connect to your EC2 instances. It consists of a public key and a private key:

1. **Public Key**:
    
    * The public key is stored by AWS and is associated with your EC2 instance. It is used to encrypt data sent to the instance.
        
2. **Private Key**:
    
    * The private key is downloaded and kept by you. It is used to decrypt data sent from the instance and to securely connect to the instance via SSH.
        

* Select the private key file format:
    
    * Choose `.pem` if you are using a Mac or Linux system, as it is compatible with the OpenSSH tool used for SSH connections.
        
    * Choose `.ppk` if you are using a Windows system, as it is compatible with PuTTY, a tool used for SSH connections on Windows.
        
* RSA and ED25519 are two different types of cryptographic algorithms used for generating key pairs in SSH and other security protocols.
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1742659047284/1c3e33c8-2b79-4a33-88fd-640d658f7b21.png align="center")

We named the key `docker-server` and since you are on a Linux system, have chosen RSA as the cryptographic algorithm, selecting the `.pem` format for your private key is the appropriate choice.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1742662807814/38e5e7ef-1e1c-4bf2-b5e6-38b25f5a73f0.png align="center")

After downloading the key, you can move it to the `.ssh` directory on your PC to keep it organized and easily accessible for SSH connections.

**Configuring network settings:**

When configuring network settings for your EC2 instance, consider the following key aspects:

1. **VPC (Virtual Private Cloud)**:
    
    * Ensure your instance is launched within a VPC. This provides a secure and isolated network environment. We will use the default one.
        
2. **Subnet:**
    
    * help organize and secure your network by controlling access and traffic flow between different parts of your infrastructure.
        
3. **Security Groups**:
    
    * When configuring firewall rules for your instance through a Security Group in AWS, you can define both inbound and outbound rules. Inbound rules control the incoming traffic to your instance, while outbound rules manage the outgoing traffic. Define rules to allow necessary traffic, such as SSH (port 22) for management or HTTP/HTTPS (ports 80/443) for web applications
        
        ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1742665956307/1f65ffd3-59ae-4482-ac9c-b7d078a5c69d.png align="center")
        
        * The `Auto-assign Public IP` feature allows you to automatically assign a public IP address to an instance when it is launched in a subnet that is configured to support public IP addresses. This is particularly useful for instances that need to communicate with the internet directly.
            
        * setting the source type to `My IP` allows you to create a rule that permits traffic from your current public IP address. This is useful for securing access to your instances by ensuring that only your specific IP address can connect to them.
            

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1742665460265/6cb41773-93f9-49ba-8d1b-812f594d3a53.png align="left")

Configuring storage for an EC2 instance involves setting up and managing the storage volumes attached to your instance. we’ll chose

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1742665326440/b93acf63-7f42-4793-9094-0444ab28c00e.png align="center")

Our instance is ready to be launched.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1742665558582/ec10483c-cb05-4104-a965-a50a84c398aa.png align="center")

Returning to the instances dashboard, we have:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1742665689246/24237f26-da79-4a62-adc8-05c672c97ccc.png align="center")

## 2-Install Docker on the EC2 instance

Since we downloaded the key and moved it to the `.ssh` directory on your PC, it is now organized and easily accessible for SSH connections.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1742662565850/e7331f3d-fc06-4690-91ca-376e74e36224.png align="center")

We ensure the correct permissions are set for the `.pem` file by using the command `chmod 400 your-key-name.pem` to maintain security.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1742662579284/621f7890-927d-4012-a7a8-b5bc44e49ebc.png align="center")

What `chmod 400` does:

* **4**: Grants read permission to the owner of the file.
    
* **0**: Denies all permissions (read, write, execute) to the group.
    
* **0**: Denies all permissions (read, write, execute) to others.
    

We can now SSH into the EC2 instance. So, we will need the public DNS or IP address of your instance.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1742694727674/d9330d46-2cd5-4e8e-a7d6-8cb6a237235b.png align="center")

The command :

* `ssh -i your-key-name.pem ec2-user@your-instance-public-ip` is used to connect to an Amazon EC2 instance using SSH with the instance's **public IP address ,**
    
* `ssh -i your-key-name.pem ec2-user@your-instance-public-dns` If we use the DNS.
    

Command Breakdown

1. `ssh`: The Secure Shell (SSH) command used to connect to a remote server.
    
2. `-i your-key-name.pem`: Specifies the private key file (`your-key-name.pem`) for authentication. This key is the one we downloaded when you created the EC2 instance.
    
3. `ec2-user`: The default username for Amazon Linux and Amazon Linux 2 AMIs. For other AMIs, the username may differ:
    
    * **Ubuntu**: `ubuntu`
        
    * **CentOS**: `centos`
        
    * **Debian**: `admin`
        
    * **Red Hat**: `ec2-user`
        
4. `your-instance-public-dns`: The public DNS name or public IP address of your EC2 instance. You can find this in the EC2 Management Console under the **Public IPv4 DNS** or **Public IPv4 address** field.
    

In our case, we will use the IP address:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1742671895424/2a817b2c-4bdb-46d4-a16e-823567cf4b47.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1742672142860/9cb15993-6d31-4d54-b242-1806f9b747b6.png align="center")

In `ec2-user@ip-172-31-18-208`, `172-31-18-208` represents the private IP of our EC2 instance.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1742672444293/3e98c756-3d1b-4795-bf01-1238aa0099c7.png align="center")

After connecting with SSH, check the package manager and always update it. This is useful for keeping the repositories up-to-date. Since we are using an Amazon AMI, we use `yum`.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1742672753531/6cc4eb98-baf4-4bb4-8d06-a9f58a1f94b2.png align="center")

Now we can run `sudo yum install docker` to install Docker. After installation, verify it's installed correctly by using `docker --version` . Next, we start the Docker daemon with `sudo service docker start` and check if it's running.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1742674511511/dbdc9229-1503-42fa-b0c6-f0c921e423ff.png align="center")

We want to run Docker commands without using `sudo`. To do this, we need to add `ec2-user` to the Docker group by using the command: `sudo usermod -aG docker $USER`.

After running this command, it's important to log out and log back in for the changes to take effect.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1742674764390/09667895-28fe-4cfd-ac1a-4217756d14ba.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1742674857867/65e4658d-1e08-4276-bc8f-fa7ede5a3ef7.png align="center")

## 3-Fetch an image from a private Docker repository on Docker Hub

First, we'll build and tag our image locally and push it to our Docker Hub repository.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1742687612932/d549fd62-f148-4a67-ae6e-1123a493068e.png align="center")

This is our Dockerfile, and the app starts at port 3080 inside the Docker container.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1742687252823/ecf8c820-0d46-4301-9578-1c197db8c2c9.png align="center")

To build the docker image, we use the command : `docker build -t legrabg7/demo:1.0 .`

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1742687774618/2ec7bed3-2ec6-4619-ac2b-708d86d45874.png align="center")

Command Breakdown

1. `docker build`: The command to build a Docker image.
    
2. `-t legrabg7/demo:1.0`: Tags the image with a name (`legrabg7/demo`) and a version (`1.0`).
    
    * `legrabg7/demo`: The name of the image, typically in the format `<username>/<repository>`.
        
    * `1.0`: The tag or version of the image.
        
3. `.`: Specifies the build context (the directory containing the Dockerfile and any other files needed for the build).
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1742687987420/d4058b2a-a558-4202-89dc-8a1cc9aa1fc1.png align="center")
    
    Using the command `docker images`, you can view a list of all the Docker images available on your system.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1742689338156/af09949c-ffbf-418b-9a35-3c599e9eedcb.png align="center")
    
    Now, we need to push this image to our private Docker Hub repository. To do this, we must first log in to Docker Hub via the CLI using the command `docker login -u username`.
    
    Command Breakdown
    
    1. `docker login`: The command to authenticate with a Docker registry.
        
    2. `-u username`: Specifies your Docker Hub or registry username.
        
    3. `-p password`: (Optional) Specifies your password. If not provided, Docker will prompt you for it interactively.
        

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1742689754707/d03801e4-5ad6-4d77-a255-9252febdcff3.png align="center")

And we push the imge : `dokcer push legrabg7/demo:1.0`

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1742690007074/3c9d3981-6e0e-4637-a2ab-d67f9d47ef5c.png align="center")

We check the repository to see if the image has been uploaded.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1742691124223/be5e4fa0-fe3a-414a-a869-564b34bdb4f3.png align="center")

## 4-Start a Docker container using the fetched image on the EC2 instance

The next step is to SSH into our EC2 instance, log in to our private Docker Hub, and pull the image from that Docker repository.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1742691330748/cbc51308-ac10-4e50-be93-aff03bbabb59.png align="center")

Now, run our image using the command: `docker run -d -p 3000:3080 legrang7/demo-app:1.0`.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1742691455225/239be3f8-477e-4600-aeb2-87245a7ab75e.png align="center")

1. `docker run`: The command to create and start a container from an image.
    
2. `-d`: Runs the container in **detached mode** (in the background).
    
3. `-p 3000:3080`: Maps port `3080` inside the container to port `3000` on the host machine(ec2).
    
    * `3000`: The port on the host machine.
        
    * `3080`: The port inside the container.
        

With `docker ps` command, we can see our running container:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1742693451714/69aefde3-54a7-4303-b43b-7ef821d0f1d9.png align="center")

## 5-Configure external access to the application from a web browser

The application starts inside the container on port 3080, and we make it accessible on the EC2 instance through port 3000. This setup means that when you access the EC2 instance on port 3000, the traffic is directed to port 3080 inside the container, allowing you to interact with the application.

We have a security group attached with configured firewall rules. Currently, only port 22 is open on the server. We need to open port 3000 as well, so requests from the browser can reach our instance on port 3000.

Step 1: Identify the Security Group

1. Go to the **AWS Management Console** &gt; **EC2** &gt; **Instances**.
    
2. Select your EC2 instance.
    
3. In the **Description** tab, locate the **Security groups** section. Note the name of the security group (e.g., `launch-wizard-1`).
    

---

Step 2: Edit Inbound Rules

1. Go to **EC2** &gt; **Security Groups** in the left-hand menu.
    
2. Select the security group associated with your instance.
    
3. Click on the **Inbound rules** tab.
    
4. Click **Edit inbound rules**.
    

---

Step 3: Add Inbound Rules

1. Click **Add rule** to create a new rule.
    
2. Configure the rule based on the type of traffic you want to allow:
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1742692908205/f65658d6-c590-4e48-9838-ecd7fc2cffbb.png align="center")
    
    In our case, we want to allow anyone, anywhere (0.0.0.0/0) to access port 3000.
    

## 6-Access the App from the Browser

Finally, because this application has a user interface, We can access it through the browser by using either the public IP or the DNS and port 3000.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1742694584050/95cdccc0-a0e9-4f39-9267-d8a009a2e35b.png align="center")

# **Conclusion**

To wrap up, we have successfully created an EC2 instance and installed Docker on it. We then fetched an image from a private Docker repository on Docker Hub and started a Docker container on the instance. Finally, we configured external access from a web browser to the application running on the EC2 instance.

Thank you so much for following along with this tutorial. Stay tuned for more tutorials on DevOps concepts.
