06.07.2023

Implementing a Reverse Proxy with Nginx on Ubuntu Server 22.04

One of the fundamental functions of a reverse proxy is to serve as a protective buffer, shielding the backend servers by intercepting and handling requests from clients. By doing so, it effectively hides valuable information about the servers, such as their IP addresses and other sensitive details. This adds an extra layer of security to your infrastructure, making it harder for potential attackers to directly target your servers.

Installing and configuring Nginx

Let's get everything up to date and install your web server.

apt update
apt install nginx

Change Nginx's configuration to determine how it handles incoming requests and serves the appropriate responses:

nano /etc/nginx/sites-available/default

Inside this file, you can configure Nginx to suit your specific requirements. It allows you to define server blocks, SSL certificates, and other directives to optimize the performance and security of your reverse proxy setup. But why we came here is to comment out the line related to IPv6, save the changes and exit the file.

Run this:

dpkg --configure -a

The command ensures that all packages on the system are properly configured by going through the installation and configuration process for any pending packages. It checks the status of all installed packages and configures them according to their respective installation scripts.

Double-check that Nginx is in good working order.

service nginx status

Now you should configure a firewall to ensure that only necessary traffic can reach your reverse proxy. We will use Uncomplicated Firewall (UFW) for this purpose.

Install ufw:

apt install ufw

Turn it on:

ufw enable

Allow HTTP traffic to go through by:

ufw allow 'Nginx HTTP'

Check the status and current rules of the firewall:

ufw status

Let's create the config file named after our domain.

Inside this file, define the specific settings for your proxy: server name, listening ports, and the location where incoming requests will be forwarded:

server {
listen 80;
#listen [::]:80;
server_name test_domain.ru www.test_domain.ru;
location / {
proxy_pass ip_addres_app;
include proxy_params;
}
}

Replace ip_address_app with the actual IP address or domain name of your backend server.

The proxy is configured using the /etc/nginx/proxy_params file. The default settings are fine for this example, but you can change them if you need to.

Enable the reverse proxy by making a symbolic link:

ln -s /etc/nginx/sites-available/test_domain.ru /etc/nginx/sites-enabled/

A symbolic link, also known as a symlink or soft link, is a special type of file that acts as a pointer or reference to another file or directory in the file system. It allows you to create a shortcut to a file or directory, providing a convenient way to access or reference it from a different location.

Run a test to be sure nothing is broken:

nginx -t

If no errors are shown:

service nginx restart

At the moment, Nginx is configured with a reverse proxy. The next step is to install and configure the application testing server.

Testing

Now, to test the reverse proxy you just made let's start a Gunicorn (short for "Green Unicorn"). It is a server designed to work with web requests to Python web applications while Nginx is not that good at doing it. So, to test the functionality of your proxy we will run a simple Python application to validate if this whole stack is working.

Install it:

apt install gunicorn

Create the file:

nano wsgi.py

Put this text into it:

def wsgi(environ, start_response):
start_response("200 OK", [])
return iter([b"Welcome, to new wsgi server"])

This wsgi.py file contains a simple application that responds with a "200 OKstatus message.

The command starts Gunicorn with two worker processes:

gunicorn --workers=2 wsgi:wsgi

Upon starting Gunicorn, a master process is initiated to oversee the overall functioning of the server. The master process assumes the responsibility of managing the worker processes, accommodating configuration changes, and monitoring the health of the workers. The actual task of handling requests is assigned to the worker processes.

Each worker process operates independently, with the capability to manage one or more requests concurrently. The number of worker processes can be tailored to suit specific requirements, considering factors such as available system resources, anticipated traffic load, and the characteristics of your application.

By employing multiple worker processes, Gunicorn optimizes the handling of requests, allowing for parallel processing and improved response times. This approach ensures efficient utilization of system resources and enables the server to handle a higher volume of concurrent requests without becoming overwhelmed.

Open a browser from the remote host and enter the address/domain of our server. We should get a message like this:

Conclusions

With this guide you have learned: