# Three Tier Application - Setup

## What is a three-tier architecture?

A three-tier architecture is a software design pattern used to structure applications or systems into three distinct layers or tiers. Each tier serves a specific purpose and communicates with the other tiers in a well-defined manner. This architecture is commonly used in web-based applications but can be applied to various types of software systems.

1. Presentation Tier (Frontend):
    
    * The presentation tier is the topmost layer and is responsible for interacting directly with users or clients.
        
    * It handles user interface components and presents data to users in a human-readable format.
        
    * This tier typically includes web browsers, mobile apps, or other client-side interfaces.
        
2. Application Tier (Middle Tier):
    
    * The application tier, also known as the business logic layer or middle tier, contains the application's core logic and processing.
        
    * It processes user requests received from the presentation tier and performs computations or business-specific operations.
        
    * This layer acts as an intermediary between the presentation tier and the data tier.
        
3. Data Tier (Backend):
    
    * The data tier, also referred to as the data access layer or backend, deals with data storage and retrieval.
        
    * It manages the storage, retrieval, and manipulation of data from various data sources, such as databases or external APIs.
        
    * The application tier communicates with the data tier to fetch and store data required for processing user requests.
        

### Advantages of the three-tier architecture include:

* Modularity: Each tier can be developed and maintained independently, promoting code reusability and easier scalability.
    
* Scalability: The separation of concerns allows each tier to be scaled individually, improving the overall performance and efficiency of the system.
    
* Security: By isolating the data tier from direct access by clients, the architecture enhances data security and reduces the risk of unauthorized access.
    
* Flexibility: Different technologies can be used in each tier, enabling developers to choose the most suitable tools for specific tasks.
    

## How are we building our three-tier application?

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1691403387346/d39874a1-9a8a-4995-83fd-da793ddd42c3.png align="center")

Our infrastructure will consist of two Virtual Machines: One running the backend code along with the database, the other running the nginx frontend. We will try to set up a local DNS as well for the user \[your computer\].

As a result, we want that our app will be accessible to the user via nginx only. We don't want the user to directly access the backend machine (that will be done by configuring a firewall on the backend machine).

### Setting up the backend machine

Our backend machine is running CentOS. Before launching the code on the backend machine, we have to set up the development environment on it. Follow these steps:

```bash
sudo yum install python3 python3-devel git
sudo yum groupinstall 'Development Tools'
```

Now as the development environment is ready, we need to get the code on the machine. I already have a GitHub repo for the code. Here is the link:

[https://github.com/wiz4host/StaticContents/tree/main/todo-app-api](https://github.com/wiz4host/StaticContents/tree/main/todo-app-api)

We will put the code under the folder: `/var/www/app/todo/`

Make the folder using the command:

```bash
mkdir -p /var/www/app/todo/
```

Now let's clone the repo by:

```bash
wget -O todo-app-api.zip https://raw.githubusercontent.com/wiz4host/StaticContents/main/todo-app-api/todo-app-api.zip
# If you don't have unzip present, install it using sudo yum install unzip
uzip todo-app-api.zip
cd todo-app-api/
```

Now the code must be present in `todo-app-api` folder.

Before running the app, we need to install various dependencies as well. You may see in this folder that we have a file named `requirements.txt`. We will use this file to install all the required dependencies.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1691409109776/b48cf88b-8112-4ca2-bd8d-c4af73e5304b.png align="center")

Make sure that you are in `ToDo-App-API/` folder and run the following command:

```bash
pip3 install -r requirements.txt
```

Woah, our app is ready to run........ not yet! Let's do the changes in the code.

Open up the api.py file, with whatever text editor you want to use. I'll be using nano 🙃

```bash
sudo nano api.py
```

Now look out for the line:

```bash
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///path/to/todo.db'
```

You have to replace the `path/to/todo.db` with the actual path to `todo.db`. Now if you're following me right now, the `todo.db` path must be `/var/www/app/todo/ToDo-App-API/todo.db`. So change that line to:

```bash
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////var/www/app/todo/ToDo-App-API/todo.db'
```

One more thing to do in the code. Scroll down to the bottom of the code so that you can see the following line:

```bash
app.run(host='0.0.0.0', port=5000)
```

You will have to change this `0.0.0.0` to your machine's IP Address. In my case it is `10.1.1.103`, so I'll change it to:

```bash
app.run(host='10.1.1.103', port=5000)
```

**But why would we do that??**

A Virtual Machine, or any machine in general, has many network interfaces. If we put `0.0.0.0` in the host variable, then our app will run on all the interfaces and we don't want this to happen. We only want it to run on the `10.1.1.103` IP, that's why we changed it.

Now your code is ready to run! Let's run it by:

```bash
python3 api.py
```

And you should see something like this:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1691568023282/6ec77bbf-2e9f-452b-8019-cd54afdea0d4.png align="center")

Let's ignore the warnings as of now. The main thing is in the last line, our Application is running on the PORT 5000.

Let's save the firewall part for later.

### Setting up the frontend machine

Our frontend machine is running Ubuntu, and we need to have Nginx installed on this machine. You can install it using:

```bash
sudo apt update
sudo apt install nginx
```

After it is installed, check for its status:

```bash
systemctl status nginx
```

The output of this command should look like this:

```apache
Output:
nginx.service - A high performance web server and a reverse proxy server
   Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
   Active: active (running) since Fri 2023-08-5 16:08:19 UTC; 1 days ago
     Docs: man:nginx(8)
 Main PID: 2369 (nginx)
    Tasks: 2 (limit: 1153)
   Memory: 3.5M
```

Now NGINX is up and running on this machine. Let's create the folder for saving logs of our ToDo application:

```bash
mkdir -p /var/www/todo.app/logs/
```

Let's add a configuration file for the ToDo Application:

```bash
cd /etc/nginx/sites-enabled/
sudo nano todo.app.conf
```

Type this server block inside the `todo.app.conf` file:

```bash
server
{
    # It is going to listen on the port 80
    listen 80;
    # This server will be accessible only to those, who are
    # accessing it via this DNS: todo.app
    server_name todo.app;

    # These are the log files for our server
    access_log /var/www/todo.app/logs/access.log
    error_log /var/www/todo.app/logs/error.log
    
    # Now let's define the endpoints for the ToDo API
    # Currently we have two endpoints available for this API
    # 1. /login
    # 2. /users
    location /login {
        proxy_pass http://10.1.1.103:5000/login;
    }
    location /users {
        proxy_pass http://10.1.1.103:5000/users;
    }
}
```

After saving this file, you have to reboot nginx:

```bash
sudo nginx -t
sudo nginx -s reload
```

If everything with your configuration file is okay, then you should see this:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1691558632020/289c7b90-15af-4bb2-abd9-a2a361821c1b.png align="center")

If you see some error here try to resolve it. There might be some syntax issue with your configuration file.

### Setting up DNS on your base machine

As you can see in the `todo.app.conf` configuration file, the server will only respond to the requests if they are requested on the `todo.app` DNS. Let's create a DNS now!

* Locate your `hosts` file. It is present in this directory: `C:\Windows\System32\drivers\etc`
    
* Open up a command prompt as administrator, and:
    
    ```bash
    cd C:\Windows\System32\drivers\etc
    notepad hosts
    ```
    
* It should open up the `hosts` file in notepad. Now add the following line in the end of the `host` file:
    
    ```bash
    10.1.1.102    todo.app
    ```
    

And we are pretty much done with the infrastructure! Try to reach out to `todo.app/login` from your browser, or any API tool you use (such as Postman).

You should see something like this:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1691568156824/47193557-a9e1-4371-aadc-bda4bb55320d.png align="center")

`Status: 200 OK`

This is all we need to hear as a developer!

Wait, we are not done yet!

If you try to reach out to `http://10.1.1.103:5000/login`, you can see that it is also reachable:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1691568188068/097e7a1c-cfc1-4c54-bf79-00f2fe77f4e2.png align="center")

We don't want this to happen, that is, we don't want anyone else to access your App Server instead of our frontend machine \[10.1.1.102\]. So let's setup a firewall on the CentOS Backend machine.

### Setting up a firewall on the backend

Setting up a firewall is simple. Follow along with these steps:

Installing the `firewalld` utility:

```bash
sudo yum install firewalld
```

Enable the firewall service:

```bash
sudo systemctl enable firewalld
sudo reboot
```

We can then verify the state of firewall using:

```bash
sudo firewall-cmd --state
# OR
sudo systemctl status firewalld
```

Add this *rich rule* which will allow traffic on port 5000 from our frontend IP `10.1.1.103` only:

```bash
sudo firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="10.1.1.102" port protocol="tcp" port="5000" accept'
sudo firewall-cmd --reload
sudo firewall-cmd --zone=public --list-all
```

You should see your rule there.

Now restart your Python application on your server.

Now let's try to reach out to the server:

* When we try to reach out to `http://todo.app/login` we should see the same `Status: 200 OK`
    
* But when we try to reach out to `http://10.1.1.103:5000/login` we are not able to make the request there.
    

That means our firewall is working fine!

And with that our three-tier application infrastructure is ready!

## Conclusion

If you find this blog informative, then please like and comment on it. It means a lot!

Connect with us:

🔗 [**LinkedIn**](https://www.linkedin.com/in/wiz4host-it-technologies-328987141/)

🔗 [**YouTube**](https://www.youtube.com/channel/UC1gupaDgPO4Ns0eEr4MzKwA)

🔗 [**GitHub**](https://github.com/wiz4host)
