🌐💻 Building a Multi-AZ Three-Tier Architecture on AWS: A Comprehensive Guide
Tags: aws, webdev, cloud, architecture
Published: 2023-04-21 08:37:06

## Introduction
As a budding cloud engineer, I was recently given the task of creating a three-tier architecture for a web application that previously had a straightforward one-tier architecture. A fault-tolerant, scalable design that could accommodate increasing traffic and demand was the aim. I successfully designed and implemented a three-tier architecture on AWS using multiple availability zones for high availability and fault tolerance after some research and testing. Anyone who wishes to carry out a similar task can use this blog post as a guide.

_LongPostAlert!_

---

## Architectural Diagram
The first step is to create a three-tier architecture. There are several tools available for this purpose. This [AWS webpage](https://aws.amazon.com/architecture/icons/) provides a summary of several websites that can be used, and I suggest [draw.io](https://www.draw.io/?splash=0&libs=aws4). A sample architectural plan created is shown below.

![Three-Tier Architecture](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a4bfe3j6khm753oq2enm.png)

---

## Deployment
The resources needed can be divided into various sections which will be discussed below.

### VPC
The VPC can be created as shown in the following figure. 

![VPC Creation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/61r73mtoew8cjuh4c0ed.png)

Next is to edit VPC settings to enable DNS resolution and hostnames.

![Edit VPC Settings](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a74tfutx1d8o82n9ja3m.png)

### Subnets
The architecture requires six subnets, with three in each availability zone. Two subnets are private while only one is public in each availability zone.


![Subnet Creation 1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/56vxgyu5gbgnx7e2m6qi.png)

![Subnet Creation 2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cr33xnbpw08pj5341q0z.png)

For the public subnets, their settings can be edited to enable auto-assign public IPv4 settings.


![Edit Subnet 1 Settings](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zr90mwt02oy7jrgmpuc7.png)

![Edit Subnet 2 Settings](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yn6ne4u39p04k12wgzwk.png)

### Security Groups
Next is to create the security groups. 

1. The first is the `web-elb-sg` which allows HTTP access from all sources.

![Web ELB SG](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v9uicuoiyksn6wne0eb2.png)

2. The `web-sg` is created next which allows HTTP access from `web-elb-sg`.

![Web SG](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i3xmvoq4jpkoghnhicdb.png)

3. The `app-elb-sg` is created next which allows HTTP access from `web-sg`.

![App ELB SG](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x9jid29dlb0szsg8obj5.png)

4. The `app-sg` is next which allows HTTP access from `app-elb-sg`.

![App SG](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h21nrkq585ibd1caymzr.png)

5. Finally, `db-sg` is created which allows MySQL access from `app-sg`.

![DB SG](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8l37tk983lj5vmrc7cq3.png)

### Internet Gateway
Since this is a new VPC, an internet gateway has to be created and attached to the VPC as shown below.

![Create Internet Gateway](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kqiqbfzfaq8tgi4puipd.png)

![Attach IGW To VPC](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uzbmijcu15sx4d6ocq14.png)

### Route Tables
When a VPC is created, a default route table is created. Any subnets that have no explicit route table associations will be associated with the default route table. 

A `web-RT` route table can then be created with a route with `0.0.0.0/0` destination with the internet gateway as the target. 

![Create Route Table](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j3e0upxtq8tpw8bhb9dp.png)

![Edit Route Table](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bug5xfe2r5p0ylqz44h9.png)

The public subnets can then be associated with this route table.

![Edit Subnet Associations](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a626kihfnerozpp1rkt2.png)

### Launch Templates

1. Web Tier Launch Template
A launch template is then created to be used in the web tier. This is associated with the `web-sg` security group, with auto-assign public IP enabled. 

![Web Tier Launch Template 1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/br5o6qubvzgxoqs6pn1s.png)

Some user data can be included to enable Apache web server to run in the instances after creation.

![Web Tier Launch Template 2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hqf1oz5kwiz6ff0hwugx.png)

2. App Tier Launch Template
A launch template is then created to be used in the app tier. This is associated with the `app-sg` security group. 

![App Tier Launch Template](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sjvabjtkosc1qba3777y.png)

### Target Groups

1. Web Tier Target Group
A target group is then created to be used for the web tier. 

![Web Tier Target Group 1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xmdux5p0g6ytqrtsuprt.png)

No instances are registered at the moment, but they will be registered automatically once they will be launched by the Auto Scaling Group.

![Web Tier Target Group 2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jlejl0ehjoi5n146j20r.png)

2. App Tier Target Group.
This is a similar process to the web tier target group.

![App Tier Target Group 1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uoux154eyebf1w3yycgr.png)

![App Tier Target Group 2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/47v9n9bfpeq3ifhqanjt.png)

### Application Load Balancers

1. Web Tier
This is set up with the internet-facing scheme. Under mappings, the two public subnets in the two AZs are selected. This is associated with the `web-elb-sg` security group. 

![Web Tier ALB 1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wnsmqudgdncdrpc79ooo.png)

A `HTTP:80` listener is then associated with the `WebTierTargetGroup`.

![Web Tier ALB 2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7hrlcvs03xzk16xvc47o.png)


2. App Tier
This is set up with the internal scheme. Under mappings, the two app private subnets in the two AZs are selected. This is then associated with the `app-elb-sg` security group. 

![App Tier ALB 1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fpehwtuyk185vnj4yano.png)

A `HTTP:80` listener is associated with the `AppTierTargetGroup`.

![App Tier ALB 2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9dh7stt03wqm7pj962ue.png)

### Auto Scaling Groups

1. Web Tier
The `WebTierASG` is created and associated with the `WebTierLaunchTemplate`. 

![Web Tier ASG 1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ce7dknoyi9ruu8ie02c0.png)

The two web public subnets are selected to be used by the ASG. 

![Web Tier ASG 2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/75m39noa5o2fhy6u23qo.png)

This is then associated with the `WebTierELB`, with ELB health checks enabled. 

![Web Tier ASG 3](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4nk3jkt5dbayd65tvr86.png)

The group size is selected as shown, with a target tracking scaling policy using the `Average CPU utilization` metric.

![Web Tier ASG 4](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bybf8q84x3u4c8tm1y48.png)

![Web Tier ASG Review](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rcmruyln14svmouoxee8.png)

2. App Tier
The `AppTierASG` is created and associated with the `AppTierLaunchTemplate`. 

![App Tier ASG 1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c0481i9igoubjk6wjgi1.png)

The two app private subnets are selected to be used by the ASG.

![App Tier ASG 2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6evydd7wlky9cxup7jra.png)

This is then associated with the `AppTierELB`. 

![App Tier ASG 3](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k14jrcxz8dfgvdtycpsw.png)

The group size is selected as shown, with a target tracking scaling policy using the `Average CPU utilization` metric.

![App Tier ASG 4](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2hwra22c7gwvi8430nry.png)

![App Tier ASG Review](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/72vev0s4elnnyd36t3cw.png)

---

## Web Tier Test
After the auto scaling groups are set, it kicks in and creates the instances. Two instances are created initially in each tier since the desired capacity is set to two. 

![Desired EC2 Capacity](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/flr7wwp0j91dcvz1pgsw.png)

Upon visiting the ELB endpoint, it can be seen that we get responses from both instances as shown below.

![Web ELB Returning Traffic From Instance 1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p5gvnkbkobftebfhpy29.png)

![Web ELB Returning Traffic From Instance 2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hcc35si0jntdf2074cne.png)

However, since the minimum capacity is set to one, once the target tracking policy kicks in and the web servers are idle, the capacity is reduced to one in each tier.

![Minimum EC2 Capacity](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/libt52jbmtfoc15yiy9j.png)

---

### DB Subnet Group
The DB subnet group is created specifying the two availability zones and the two DB subnets created earlier on.

![DB Subnet Group](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2xsw6oh6kxz34sv84tbd.png)

### RDS Database Creation
This is created using RDS using the Aurora(MySQL Compatible) engine. Multi-AZ deployment is enabled. The subnet group created in the previous section is selected, specifying the `db-sg` as the security group to be used.

![RDS 1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/trn45crx7o012drtyri0.png)

![RDS 2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/69xhc6oswn0zj3f992r7.png)

This creates two DB instances, one in each AZ. One is set as the writer instance in `us-east-1b` and the other as the reader instance in `us-east-1a`. 

![RDS Instances](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/elw6onuinub5l08lmtfp.png)

In order to test failover to see what happens if the writer fails, we can see that the writer instance switches to `us-east-1a`.

![RDS Failover](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9td30jolmthn7hh7jz2z.png)

![RDS Instances After Failover](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ir79qkkkc0ecmxg58cw5.png)

### CloudFront Distribution
A CloudFront distribution is created with with the web tier ELB as the origin domain using the HTTP protocol. A custom header is added so that requests coming through the distribution will include it. This will be essential to distinguish traffic that come via the distribution and those that go directly to the ELB.

![CloudFront Configuration](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mpv3v5vogk8w5jdic3sa.png)

### WAF Web ACL
A WAF web ACL is used to block any traffic to the ELB that do not contain the custom header, implying that only traffic that go through CloudFront will be allowed to the ELB.

The `CustomHeaderACL` is created and associated with the `WebTierELB`. 

![Web ACL 1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/did4q3sf6tou0aqnjz4e.png)

A rule is added to block any request that do not contain the custom header specified in the previous step. 

![Web ACL 2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2e4krmr9iwnfhbovwo41.png)

The default action is left as `Allow` to permit any request that does not match the set rule.

![Web ACL 3](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2inv9cxgha5jeyi8ok20.png)

![Web ACL Review](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tbt0qszlg58j8tq0vt7j.png)

---

## CloudFront Test
Traffic that is sent via the CloudFront endpoint is allowed as shown below.

![CloudFront Traffic Success](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cppc5em54gigzmb27g8w.png)

Traffic sent using the ALB endpoint is now denied.

![Web ELB Direct Traffic Denied](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l9gdrw084w575fow6mrx.png)

---

## Outro

> Think of deleting unused AWS resources like eating your vegetables - it may not be fun, but it's necessary for a healthy and cost-efficient cloud environment 🥦💰💪

Experimenting with these resources can be a fantastic experience, giving you the thrill when you get the desired outcome and even more fun when you have to troubleshoot and figure out why something went wrong.