Reverse Proxy:

Reverse Proxy:

Have you ever wondered when developers use this buzz word, "Reverse Proxy"? Lets check it out what it is and why we need reverse proxies like Nginx in the projects.

Lets understand what is reverse proxy first. It is simply a server which sits in between the client and the web server serving as a gate keeper. It handles request from client, processes it if needed and passes it to the server, vise versa, takes the response from the server, processes it if needed and sends it back to client. It has super powers to protect the application against hackers and does cool job of offloading server functionalities like Load Balancing, caching, SSL termination, Centralized Authentication and Authorization to name a few, so that web server only focuses on business logic to serve client requests.

Following are few popular reverse proxies:

  • Nginx
  • Apache HTTP Server
  • HAProxy
  • Traefik
  • Caddy

Though we have a built-in cluster module to make our node application as a load balancer, it is not advisable to use it in enterprise applications where we may encounter at least more than 500 user requests per minute. Reverse proxies does a very good job in such scenarios to name a few.

In this post we will be looking at how Nginx can act as a reverse proxy for nodejs applications. It is always a good idea that web server focuses on the business logic to serve the client request while offloading load-balancing, sslEncription, cashing, gzip static content, buffering to proxy servers.

Key benefits of nginx server include as follows:

  1. SSL Encryption
  2. Buffering
  3. caching
  4. Enterprise Routing
  5. GZip static content
  6. Recovery


Lets look how we configure Nginx to handle above functionality through a configuration file.

# nginx.conf

user nginx;
worker_processes auto;

error_log /var/log/nginx/error.log;

events {
    worker_connections 1024;
}

http {
    server {
        listen 80;
        server_name my_domain.com www.my_domain.com;
        return 301 https://$host$request_uri;
    }

    server {
        listen 443 ssl;
        server_name your_domain.com www.your_domain.com;

        ssl_certificate /path/to/your/ssl_certificate.crt;
        ssl_certificate_key /path/to/your/ssl_private_key.key;

        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384';

        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout 10m;

        ssl_stapling on;
        ssl_stapling_verify on;

        ssl_trusted_certificate /path/to/your/trusted_certificate_authority.crt;

        root /path/to/your/web/root;

        proxy_buffering on;
        proxy_buffer_size 8k;
        proxy_buffers 2048 8k;
        proxy_busy_buffers_size 16k;

        upstream backend_servers {
            server backend_server1_ip:port;
            server backend_server2_ip:port;
            # Add more backend servers as needed
            # server backend_server3_ip:port;
        }

        location / {
            proxy_pass https://backend_servers;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;

            proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
            proxy_redirect off;

            error_page 500 502 503 504 /error.html;
            location = /error.html {
                root /path/to/your/error/pages;
                internal;
            }
        }

        # Define caching rules for static images
        location ~* \.(jpg|jpeg|png|gif|ico)$ {
            expires 30d;  # Adjust the caching duration as needed
            add_header Cache-Control "public, max-age=2592000";
        }

        gzip on;
        gzip_types text/plain text/css application/javascript image/*;

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

        # ... Additional configuration ...

    }
}        

Wooo! what the hell is this file and what does it do? Don't worry! Lets breakdown and understand what it does in detail.

 server {
        listen 80;
        server_name my_domain.com www.my_domain.com;
        return 301 https://$host$request_uri;
    }        

As you see in the above code nginx handles every request that comes to www.my_domain.com on port 80 and redirects to https://$host$request_uri which is defined in the below server object. In the above snippet 301 denotes redirection.

 server {
        listen 443 ssl;
        server_name your_domain.com www.your_domain.com;
        ....        

SSL Encryption:

When ever a web server communicates to the external world, it is recommended to use https. To set up HTTPS (SSL/TLS) for a reverse proxy, we need to obtain an SSL certificate and configure reverse proxy server (such as Nginx) to use it. Below code snippet illustrates how to configure nginx to achieve this functionality

        ssl_certificate /path/to/your/ssl_certificate.crt;
        ssl_certificate_key /path/to/your/ssl_private_key.key;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384';

        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout 10m;

        ssl_stapling on;
        ssl_stapling_verify on;

        ssl_trusted_certificate /path/to/your/trusted_certificate_authority.crt;
        

Buffering:

It is a way of breaking the response into multiple chucks. When a server responds to the client request with huge data (for example 8megaBytes). There arises a problem if the client has slow internet connection/ bad connection. Till the request is served client may be waiting for nginx server to respond which may lead to the latency and delayed response. In such scenarios hackers may attack with hundreds of slow requests which may result in server break down or server crash. Such attack is referred to as slowloris. To avoid this issue we can configure Nginx to respond in chunks instead of sending the entire huge response from web server. This process of dividing the response into multiple buffer sizes is called buffering. This can be archived using following configuration

 proxy_buffering on;
        proxy_buffer_size 8k;
        proxy_buffers 2048 8k;
        proxy_busy_buffers_size 16k;        

Recovery:

What do we do whenever one of the servers is down or user requests a page that does not exists. We redirect the user to other servers in case of server downtime, respond to the error message by retrieving the resource that was configured in nginx. We can define custom error code for every step of it. Below code snippet takes care of it

 proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
            proxy_redirect off;

            error_page 500 502 503 504 /error.html;
            location = /error.html {
                root /path/to/your/error/pages;
                internal;
            }        


Load Balancing:

Wait a second! we have a cluster module for load balancing in node, why do we need it? When we have enterprises applications that handles at-least 500 requests/minute, there would be some pressure on load balancer. Load balancing with Nginx would be a best option. We enable it by adding below code snippet. We define different servers and ports and the nigx would take care of redirecting the request to these servers using algorithms such as round robin, random assignment, least cpu usage.

 upstream backend_servers {
            server backend_server1_ip:port;
            server backend_server2_ip:port;
            # Add more backend servers as needed
            # server backend_server3_ip:port;
        }        

Enterprise Route:

Let us say we have a scenario where we would like to redirect the requests coming to certain endpoint for example /api/v1/products to server_x only. We want this behavior because we may be getting fair amount of requests to this endpoint in the application. Handling specific service request by specific server. It can be done gracefully by reverse proxy.

GZip Compression:

Most of the websites have Gzip compression. We can achieve using following snipped. It is not recommended to compress image/svg files as they are already compressed. Recommended files to compress are text, javascript, css.

        gzip on;
        gzip_types text/plain text/css application/javascript image/*;
        

Caching static content:

Ngnix is very good at cashing static content. Let us say we have some static content that needs to be served by node js server. We can have nginx configured such that when a client request for such resource nginx responds directly without reaching out to the node server. We can do it using following example code snippet.

# Define caching rules for static images
        location ~* \.(jpg|jpeg|png|gif|ico)$ {
            expires 30d;  # Adjust the caching duration as needed
            add_header Cache-Control "public, max-age=2592000";
        }        

Conclusion:

We have learnt why Reverse proxies are a fantastic tool to offload some functionalities from the web server such as buffering, Caching the static content, load balancing, SSL Encryption, Enterprise Routing, Recovery, GZip compressiion, etc.


要查看或添加评论,请登录

Santosh Kesireddy的更多文章

  • Core Components of API Response:

    Core Components of API Response:

    There are potentially four components to the HTTP Response. Status Code HTTP version Response header Response body…

  • Concurrency in NodeJS

    Concurrency in NodeJS

    I will try my best to demystify Concurrency, that confuses most of developers to my best. Concurrency is splitting the…

  • Javascript Callback Hell

    Javascript Callback Hell

    What the hell is call back hell!!!!!! Lets check it out! It may be overwhelming for some developers to get there heads…

  • Cluster Module:

    Cluster Module:

    It gives the ability for a nodejs application to handle large number of client requests by spawning multiple worker…

社区洞察

其他会员也浏览了