Three Tier Application - Setup

Harshit SharmaHarshit Sharma
7 min read

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?

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:

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

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

Make the folder using the command:

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

Now let's clone the repo by:

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.

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

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 ๐Ÿ™ƒ

sudo nano api.py

Now look out for the line:

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:

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:

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:

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:

python3 api.py

And you should see something like this:

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:

sudo apt update
sudo apt install nginx

After it is installed, check for its status:

systemctl status nginx

The output of this command should look like this:

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:

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

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

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

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

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:

sudo nginx -t
sudo nginx -s reload

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

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:

      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:

      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:

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:

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:

sudo yum install firewalld

Enable the firewall service:

sudo systemctl enable firewalld
sudo reboot

We can then verify the state of firewall using:

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:

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

๐Ÿ”— YouTube

๐Ÿ”— GitHub

0
Subscribe to my newsletter

Read articles from Harshit Sharma directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Harshit Sharma
Harshit Sharma