Using NGINX Proxypass to Set Up a Reverse Proxy Server

Published:22 July 2022 - 7 min. read

Inam Ul Haq Image

Inam Ul Haq

Read more tutorials by Inam Ul Haq!

Azure Cloud Labs: these FREE, on‑demand Azure Cloud Labs will get you into a real‑world environment and account, walking you through step‑by‑step how to best protect, secure, and recover Azure data.

Are you planning to create a web application that is only accessible in a private network? Why not use NGINX ProxyPass (proxy_pass) to set up NGINX as a reverse proxy server?

The proxy_pass directive in the ngx_http_proxy_module of NGINX lets you configure NGINX to expose your web application to the world while keeping privacy control. And in this tutorial, you’ll learn about different configurations to define your application’s privacy and increased performance.

Read on and keep your web application secure with NGINX ProxyPass!

Prerequisites

This tutorial will be a hands-on demonstration. If you’d like to follow along, be sure you have the following:

  • A Linux server – This tutorial uses Ubuntu 20.04 LTS.
  • NGINX and Docker are installed and running on your Linux machine.
  • A web application running on 127.0.0.1:8000.

What is an NGINX ProxyPass or Reverse Proxy Server?

Before diving deep into NGINX proxy_pass, take a look at what is a reverse proxy server first. Reverse Proxy servers provide an additional layer of security for web applications.

In addition, reverse proxy servers are used for load-balancing, providing a single face for a server application that spans across different servers.

A reverse proxy server is a kind of server that listens to client requests and forward or relays the requests to the relevant web application. At the same time, it responds to the client with the web application’s response.

Configuring NGINX Server as a Reverse Proxy Server

By default, NGINX works as a static content web server, so you’ll configure NGINX as a reverse proxy server by editing NGINX’s configuration files. Depending on your Linux server’s operating system and its distribution, NGINX’s configuration files can be found at one of the places below:

  • /etc/nginx
  • /usr/local/nginx/conf
  • /usr/local/etc/nginx

But since this tutorial uses Ubuntu, you’ll work on the configuration file located at the /etc/nginx directory:

1. Run the following commands to change your working directory (cd) to the /etc/nginx directory, and list all files and directories (ls) inside the working directory.

cd /etc/nginx
ls

Below, you can see the nginx.conf file, which is the base file for NGINX configurations.

Listing files inside the /etc/nginx directory
Listing files inside the /etc/nginx directory

2. Next, run the below rm command, which doesn’t provide output but deletes the sites-available/default file.

sudo rm sites-available/default

3. Create a new file called sites-available/default file with your preferred text editor.

sudo nano sites-available/default

4. Now, add the configuration below to the sites-available/default file, save the changes and close the editor. The following server block (defined using the server directive) contains the entire configuration for a virtual host.

The directives below control the configuration:

  • listen - This directive specifies which port a particular server block should listen to for requests.
  • access_log and error_log - These directives specify the path for a server block to write access and error logs.
  • location – This directive specifies configurations depending on the URI of the request. In the configuration below, every request to the server block is handled by proxy_pass.
  • proxy_pass – This directive specifies the proxied server’s address. The configuration below tells NGINX to pass every request to the proxied application on http://127.0.0.1:8000.
server {
    # The listen directive serves content based on the port defined
    listen 80; # For IPv4 addresses
    listen [::]:80; # For IPv6 addresses

    # Replace the below if you have a domain name pointed to the server
    server_name your-domain.com;

    access_log /var/log/nginx/reverse-access.log;
    error_log /var/log/nginx/reverse-error.log;

    location / {
				# Specify the proxied server's address
        proxy_pass http://127.0.0.1:8000>;
    }
}

Note that the NGINX server can serve more than one application with server blocks.

5. Run the following command to test (-t) your NGINX configuration.

sudo nginx -t
Testing NGINX configuration
Testing NGINX configuration

6. Next, run the below systemctl command to restart the NGINX service so that new configurations can take effect.

sudo systemctl restart nginx

If there’s an error in the configuration, the NGINX service will not restart. Instead, you’ll see instructions on how to find the logs. On ubuntu, you can see logs running the journalctl -xe command.

7. Finally, navigate to your web server’s domain name or IP address to access the application through NGINX reverse proxy server shown below.

Accessing the web application through NGINX reverse proxy server
Accessing the web application through NGINX reverse proxy server

Passing Headers to Handle Proxied Requests

Apart from proxy_pass, NGINX offers many other directives to handle requests to your server blocks. One of these directives is proxy_set_header, which lets you pass/rewrite headers to handle proxied requests.

This tutorial can’t cover all headers, but you’ll go through some of the most common headers (Host, X-Forwarded-For, and X-Real-IP).

1. Add the following statement above the proxy_pass in your server block under location to pass the Host header in your sites-available/default file. The Host header is sent by HTTP clients/browsers with the application domain name they are trying to access.

proxy_set_header Host $host;

By default, NGINX rewrites the Host header to the proxied server’s address ($host) before passing the Host header to the proxied server. The $host variable is set by NGINX, which holds the value of the original request’s Host header or server block’s server_name value.

When the proxied application receives the request, the Host header is set to http://127.0.0.1:8000. Essentially NGINX sets the Host header to your proxy server’s domain name/IP address. This behavior lets your application know it’s being accessed by a designated address rather than from 127.0.0.1.

2. Next, add the statement below to the sites-available/default file as you did in step one.

Your application uses the X-Forwarded-For header to identify the client’s IP address trying to access the application. This header identifies proxy servers used for the request to reach your application.

Below, the $proxy_add_x_forwarded_for variable holds the value of the request’s X-Forwarded-For header with the client’s IP address.

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

3. Add the last statement below to your sites-available/default file.

Web applications use the X-Real-IP header set to the $remote_addr variable to hold the IP address of the HTTP client accessing the server.

proxy_set_header X-Real-IP $remote_addr;

After applying the common configurations used for a reverse proxy server with the previous steps, you’ll get the complete configuration below.

server {
    listen 80;
    listen [::]:80;

    # Replace the below if you have a domain name pointed to the server
    server_name your-domain.com;

    access_log /var/log/nginx/reverse-access.log;
    error_log /var/log/nginx/reverse-error.log;

    location / {
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_pass <http://127.0.0.1:8000>;
    }
}

4. Now, run the systemctl command below, which doesn’t provide output but restarts the NGINX service.

sudo systemctl restart nginx

5. Finally, try accessing your web application in your browser with the new configuration. If all goes well, you’ll see the output below.

Verifying the web application is accessible with different configuration
Verifying the web application is accessible with different configuration

Sending Redirect Response

Imagine your application sends a redirect response using the Location header that looks like this, Location: <http://127.0.0.1/user/edit/3. You can see that the 127.0.0.1 address is not descriptive about what’s being accessed. So can you fix it? Yes!

Add either of the following proxy_redirect directives inside the location block in the sites-available/default file. This directive rewrites the Location or Refresh header sent by the proxied application to the actual URL being used to access your application.

proxy_redirect <http://127.0.0.1/user/edit/3>  <http://your-domain.com/user/edit/3>;
# For changing all URLs, you can use the one below
proxy_redirect <http://127.0.0.1/>  <http://your-domain.com/>;

Hiding and Permitting Headers

NGINX, by default, hides some headers sent to the client by proxied applications. But by using the proxy_hide_header directive, you can tell NGINX to hide more headers.

Add the directive below to the location block in the sites-available/default file to automatically hide the headers from the response sent to the HTTP client.

Hiding headers help secure sensitive information of the app and the app headers from being misused by malicious attackers.

proxy_hide_header Cache-Control;

Or, perhaps you want some header permitted sent to the client that is otherwise hidden. If so, you can use the proxy_pass_header directive like the one below.

proxy_pass_header Date;

Increasing Performance with NGINX Load Balancing

Load balancing is a powerful configuration in your server. The upstream directive in NGINX helps your application balance its load to increase the application performance. At the same time, the upstream directive makes your application scalable.

To configure your NGINX server for load balancing:

1. Create a new file inside the NGINX configuration folder (/etc/nginx/conf.d/) with your text editor, and name the file as load-balancer.conf.

sudo nano /etc/nginx/conf.d/load-balancer.conf

2. Next, add the configuration below to the load-balancer.conf file, save the changes and close the file.

You can see that the upstream directive defines either a web server cluster for load balancing or an app server cluster for routing/load balancing.

http {
   upstream your-domain.com {
        server backend1.your-domain.com:443;
        server backend2.your-domain.com:443;
   }

   server {
      listen 80; 

      location / {
         proxy_pass https://your-domain.com;
      }
   }
}

3. Run the below rm command, which doesn’t provide output, but removes the default symbolic link (symlink) from the sites-enabled directory.

sudo rm /etc/nginx/sites-enabled/default

4. Lastly, restart the NGINX service so new configurations can take effect.

sudo systemctl restart nginx

If you get an error in the configuration, open the load-balancer.conf file and double-check if you wrote the configuration correctly.

Verifying the web application works with load balancing
Verifying the web application works with load balancing

Conclusion

Throughout this tutorial, you’ve learned why and where reverse proxy servers are used with NGINX ProxyPass. You’ve touched on using a couple of directives and headers to handle requests and controlling your web application’s privacy.

Load balancing and hiding headers help your web application’s performance and security. But wouldn’t it be great to add another layer of security? Why not activate NGINX to redirect HTTP to HTTPS traffic?

Hate ads? Want to support the writer? Get many of our tutorials packaged as an ATA Guidebook.

Explore ATA Guidebooks

Looks like you're offline!