Setting up a reverse proxy server using Nginx

Introduction

Do you have two or more web servers in your home network and you wish to expose them to the network? Reverse proxy is all you need! It solves the problem of handling requests for different servers going to one public IP of your network.

Nginx (read as “engine X”) is a popular open source web server used to serve web pages (static or dynamic) over HTTP/HTTPS and handle SSL/TLS encryption, but can be used additionally for reverse proxying and load balancing. It was written to be very efficient in order to handle the C10K problem. Initially released in 2004, Nginx gained popularity with 33.9% of all websites using it, as of December 2023. For full Nginx documentations, visit their official website.

Setting up a reverse proxy server

Prerequisites

Make sure that you have your internal web servers up and running. For HTTP, you need to forward port 80 on yout router to the computer which will act as a reverse proxy. For HTTPS, forward port 443.

Configuring Nginx

  1. Create a new Nginx configuration file at /etc/nginx/sites-available directory. You can name it reverse-proxy for example, but any name will do.

  2. Create a server configuration block. Let’s say you own the domain example.com and you wish your web server to be accessible under a subdomain www. Full URL of your website will be www.example.com. Your HTTP configuration should look something like this:

server {
  listen 80;
  #listen [::]:80;
  server_name www.example.com;

  location / {
    proxy_pass http://INTERNAL_SERVER_IP:INTERNAL_SERVER_PORT;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
  }
}

If you use HTTPS, you’d need to also specify SSL paths and tell Nginx to listen for HTTPS requests.

server {
  listen 443;
  #listen [::]:443;
  server_name www.example.com;

  ssl on;
  ssl_certificate PATH_TO_fullchain.pem_FILE;
  ssl_certificate_key PATH_TO_privkey.pem_FILE;
  ssl_trusted_certificate PATH_TO_chain.pem_FILE;

  location / {
    proxy_pass http://INTERNAL_SERVER_IP:INTERNAL_SERVER_PORT;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
  }
}

Replace example.com with your domain name or IP address, and INTERNAL_SERVER_IP and INTERNAL_SERVER_PORT with the IP address and port of your backend server. www should also be replaced to match your subdomain name. If you have IPv6, you should also tell Nginx to listen for requests coming from IPv6 addresses. That will be achieved by removing comment from listen [::]:80; and listen [::]:443; lines. Additionally, you can add more lines under your server block to control different aspects of your webserver, like enabling or disabling certain TLS versions, controlling ciphers used to encrypt your HTTPS requests (and disabling low security ciphers), enabling gzip compression etc.

  1. Create a symbolic link of your reverse-proxy file from /etc/nginx/sites-available to /etc/nginx/sites-enabled directory. In Linux, this is achieved with:
sudo ln -s /etc/nginx/sites-available/reverse-proxy /etc/nginx/sites-enabled/
  1. Restart the Nginx service to apply the changes. The command may vary depending on your operating system, but in Linux it is typically:
sudo service nginx restart

or

sudo systemctl restart nginx
  1. Open a web browser and enter your domain name or IP address. Nginx should now forward the requests to your backend server.

Conclusion

If all works well, your request should be routed to the web servers you set up in the configuration file. Having server config reside in server-available directory and linking it to the server-enabled allows for easier management. Be sure to update the reverse-proxy file in the sites-available directory whenever you add or remove backend servers.

Remember that this is the basic configuration for simple web servers, and should be modified for other applications.