# Deploying a Two-Tier Application Architecture on AWS

## Overview

A **two-tier application architecture** is one of the most common patterns used to build modern web applications. It separates the application into two main layers:

1. **Application Layer** – Runs the frontend and backend logic, usually on a web server or application server.
    
2. **Database Layer** – Stores and manages data using a database server.
    

This separation makes the application easier to manage, scale, and secure compared to a single-tier setup. In this blog, we’ll walk through how to deploy a two-tier application on AWS.

## Objectives

Our goal is to design and deploy a **two-tier application** on AWS consisting of:

* An **application layer** running on Amazon EC2.
    
* A **database layer** running on Amazon RDS.
    

We will use AWS networking services to securely connect the two layers.

## Prerequisites

Before starting, make sure you have:

* An active **AWS account**.
    
* Basic knowledge of **Linux commands**.
    
* Understanding of how **EC2 and RDS** work.
    

## **High-Level Architecture**

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758193075819/c322bebe-18a2-4b9f-94f0-02180d352845.jpeg align="center")

## Task 1 — Create a VPC and networking

1. **Open AWS Management Console** and choose the nearest region (e.g., **ap-south-1 (Mumbai)**).
    
2. **Create a VPC**
    
    * Services → VPC → Create VPC
        
    * Name: `VPC-EpicReads`
        
    * IPv4 CIDR: `10.0.0.0/16`
        
    * Tenancy: Default
        
    * Add tags (Name = `VPC-EpicReads`) → Create
        

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758196372837/3e2e1c34-92fb-4df4-bf4c-553e1034ce24.png align="center")

3. **Create subnets** (across 2 Availability Zones for separation)
    
    * Create Public Subnet 1: `10.0.1.0/24` (AZ: us‑east‑1a / ap‑south‑1a)
        
    * Create Public Subnet 2: `10.0.1.0/24` (AZ: us‑east‑1b / ap‑south‑1b)
        
    * Create Private Subnet 1: `10.0.2.0/24` (AZ: us‑east‑1a / ap‑south‑1a)
        
    * Create Private Subnet 2: `10.0.3.0/24` (AZ: us‑east‑1b / ap‑south‑1b)
        
    * Tag the subnets with clear names (e.g., `PublicSubnet1-EpicReads`, `PrivateSubnet1-EpicReads`).
        

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758196563443/210453fc-9fa3-4c49-b0f5-8670717eb9a8.png align="center")

4. **Create and attach an Internet Gateway (IGW)**
    
    * VPC → Internet Gateways → Create IGW → Name it `IGW-EpicReads` → Create
        
    * Actions → Attach to VPC → select `VPC-EpicReads`
        

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758196738520/00f0ba24-bbd7-4d9a-90d4-4b7ce3486bde.png align="center")

5. **Create a Public Route Table and route 0.0.0.0/0 → IGW**
    
    * VPC → Route Tables → Create Route Table (`RouteTable-Public-EpicReads`) and pick `VPC-EpicReads`
        
    * Edit routes: add `0.0.0.0/0` → target = `igw-xxxx` (your IGW)
        
    * Subnet Associations → Associate `PublicSubnet1` and `PublicSubnet2`
        
6. **(Optional) Create a NAT Gateway** if you need outbound internet from private subnets (e.g., for patching or package downloads). Place NAT in a public subnet and create a private route table that points 0.0.0.0/0 to the NAT.
    
7. **Network ACLs (optional but recommended for subnet‑level controls)**
    
    * VPC → Network ACLs → Create NACL and attach to the VPC
        
    * Edit inbound/outbound rules as needed (allow HTTP/HTTPS/SSH where applicable).
        
8. **Security Groups (instance‑level firewall)**
    
    * EC2 → Security Groups → Create `SG-EpicReads` (for application)
        
        * Inbound: SSH (TCP 22) from your IP, HTTP (TCP 80) from 0.0.0.0/0
            
        * Outbound: allow all (or limit to RDS SG on TCP 3306)
            
    * Create EpicReads-DBSG (for RDS)
        
        * Inbound: MySQL/Aurora (TCP 3306) **source:** `SG-Web-EpicReads` (Reference the web SG to allow only app instances to reach DB)
            
        * Outbound: default (allow all) or restrict to app SG.
            

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758197064675/7f358858-253e-4a1f-9e0c-27c05c800412.png align="center")

## Task 2 — Launch EC2 instance (Application server)

1. **Launch Instance**
    
    * EC2 → Instances → Launch Instances
        
    * Name: EpicReads-WebServer
        
    * Choose AMI: Amazon Linux 2
        
    * Instance type: `t2.micro` (free tier) or choose as required
        
    * Key pair: select or create a key pair (download `.pem`)
        
    * Network: select `VPC-EpicReads`
        
    * Subnet: `PublicSubnet1-EpicReads`
        
    * Auto-assign Public IP: **Enable**
        
    * Security group: `SG-EpicReads`
        
    * Storage: default is fine for demo
        
    * Launch instance
        
2. **SSH into the EC2 instance (from your workstation)**
    
    * Ensure `.pem` has correct permissions: `chmod 400 key-pair.pem`
        
    * Example SSH command (Amazon Linux/AMI):
        
        ```plaintext
        ssh -i key-pair.pem ec2-user@<public-ip>
        ```
        
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758197539407/9a9d6bfd-0f49-46df-a0ea-af0232cf8d73.png align="center")
    
3. **Update and install web server and PHP (Amazon Linux 2 )**
    

```plaintext
sudo yum update -y
```

It is used to install the Apache web server on a Linux system.

```plaintext
sudo yum install -y httpd
```

Start and enable the Apache webserver.

```plaintext
sudo systemctl start httpd
sudo systemctl enable httpd
```

Install PHP and extensions required by WordPress.

```plaintext
sudo yum install -y php php-mysqlnd php-xml php-fpm
```

```plaintext
sudo systemctl restart httpd
```

4. **Verify Apache is working**
    
    Open browser and navigate to: `http://<public-ip>` → you should see Apache default page.
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758198091657/1fb6ed0b-dc0b-40e8-bc82-b83af7936119.png align="center")

## Task 3 — Deploy WordPress

> These commands assume you are on the EC2 instance and in `/var/www/html`.

1. Download WordPress:
    
    Change the directory to /var/www/html/
    
    ```plaintext
    cd /var/www/html/
    ```
    
    Download **latest WordPress package & Extract it**
    
    ```plaintext
    sudo wget https://wordpress.org/latest.tar.gz
    sudo tar -xzvf latest.tar.gz
    ```
    
    Copy the configuration file to wp-config.php file
    
    ```plaintext
    sudo cp wp-config-sample.php wp-config.php
    ```
    
    Set Permission for Wordpress file.
    
    ```plaintext
    sudo chown -R apache:apache /var/www/html/wordpress
    sudo chmod -R 755 /var/www/html/wordpress
    ```
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758199384294/c639dd9e-f99a-4246-bf1f-094d0c2ee069.png align="center")
    
    ## Task 4 — Create the Database (RDS MySQL)
    
    1. **Create a DB Subnet Group**
        
        * RDS → Subnet groups → Create DB subnet group
            
        * Name: `epicreads-subnetgroup`
            
        * VPC: `VPC-EpicReads`
            
        * Add the **private subnets** (`PrivateSubnet1`, `PrivateSubnet2`)
            
    2. **Create RDS instance (MySQL)**
        
        * RDS → Databases → Create database
            
        * Standard create → Engine: **MySQL**
            
        * Template: Free tier (or as required)
            
        * DB instance identifier: `wordpress`
            
        * Master username: choose a username (store it securely)
            
        * Password: choose a strong password (store it securely)
            
        * Connectivity: choose `VPC-EpicReads` and DB subnet group `epicReads-subnetgroup`
            
        * Public accessibility: **No** (keep DB in private subnet)
            
        * VPC security group: attach `EpicReads-DBSG`
            
        * Additional configuration: initial DB name `wordpress` (optional)
            
        * Create DB
            
    3. **Edit DB security group inbound rules**
        
        * EC2 Security → Security Groups → select `EpicReads-DBSG`
            
        * Inbound rule: MySQL/Aurora (TCP 3306) Source: **SG-EpicReads** (so only app SG can reach DB)
            
        
        ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758200108185/13a7fa16-14b9-4d88-8c0a-faec7ab307f2.png align="center")
        
    4. **Capture the RDS endpoint** from the RDS Console. You will use this in the WordPress config.
        
        ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758200255036/bf1cd660-1fbd-45b2-9bd2-4a3e8ffeae2e.png align="center")
        

## Task 5 — Connect WordPress to RDS

1. On your EC2 instance, set an environment variable (for testing):
    
    ```plaintext
    export MYSQL_HOST=<your-rds-endpoint>
    ```
    
2. Connect to the WordPress Database
    
    ```plaintext
    mysql --user=<your-username> --password=<your-password> wordpress
    ```
    
3. Access the wp-config.php
    
    ```plaintext
    sudo vi wp-config.php
    ```
    
4. Edit the DB\_NAME, DB\_USER, DB\_PASSWORD, DB\_HOST.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758200999287/92750cca-168f-4700-be9e-b542093a0d65.png align="center")
    
5. Go to this WordPress Secret Key Generator [https://api.wordpress.org/secret-key/1.1/salt/](https://api.wordpress.org/secret-key/1.1/salt/) and Replace the current script.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758201137405/3852d085-4591-460e-b384-14151348d220.png align="center")
    
6. Allow 'W3TC' plugin write the configuration data into DB
    
    ```plaintext
    define( 'W3TC_CONFIG_DATABASE', true );
    ```
    
7. Install the PHP XML extension on your Linux system.
    
    ```plaintext
    sudo yum install php-xml -y
    ```
    
8. Copy all the files from wordpress folder to html folder & Change Owner.
    
    ```plaintext
    cd ..
    sudo cp -r wordpress/* /var/www/html
    sudo chown -R apache:apache /var/www/html
    ```
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758201688170/9f65d3b1-359a-457b-b623-2f3f052949b4.png align="center")
    
9. Finally, start hosting the Apache web server
    
    ```plaintext
    sudo systemctl start httpd.service
    sudo systemctl enable httpd.service
    sudo systemctl restart php-fpm
    ```
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758201891684/28618c4d-bf9f-4fc9-bdbd-4248da0b6217.png align="center")
    

## Task 6 — Finalize WordPress setup in browser

1. In your browser, open: `http://<ec2-public-ip>/wp-admin/`.
    
2. Choose language → Click continue.
    
3. Enter site title, admin username, password, and email → Install WordPress.
    
4. Login with the admin credentials and verify you can create posts and that they are stored in the RDS database.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758202402923/dba1ff05-a198-4917-a7bb-616d8b75d959.png align="center")
    
5. Creating a test post.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758202229771/ee7cc293-4583-4885-b571-ea4f2b00dfb2.png align="center")
    
6. Access our site via public Ip address.
    
    ```plaintext
    http://<public-ip>
    ```
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758202522258/768d759d-9a51-4d9b-8877-f0f290aef924.png align="center")
    

## Conclusion

Deploying a two-tier application architecture on AWS provides a structured way to separate the application layer and the database layer. By setting up VPC, subnets, internet gateway, route tables, security groups, EC2 instances for the app, and RDS (or database server) for data storage, we can create a secure and scalable environment. This separation of concerns ensures better performance, easier management, and a strong foundation for running applications like WordPress on the cloud.
