Setting up an Nginx Reverse Proxy

Updated 

5 min read

A reverse proxy is a service that takes a client request, sends the request to one or more proxied servers, fetches the response, and delivers the server’s response to the client.

Because of its performance and scalability, NGINX is often used as a reverse proxy for HTTP and non-HTTP servers. A typical reverse proxy configuration is to put Nginx in front of Node.js, Python, or Java applications.

Using Nginx as a reverse proxy gives you several additional benefits:

  • Load Balancing - Nginx can perform load balancing to distribute clients’ requests across proxied servers, which improve the performance, scalability, and reliability.
  • Caching - With Nginx as a reverse proxy, you can cache the pre-rendered versions of pages to speed up page load times. It works by caching the content received from the proxied servers’ responses and using it to respond to clients without having to contact the proxied server for the same content every time.
  • SSL Termination - Nginx can act as an SSL endpoint for connections with the clients. It will handle and decrypt incoming SSL connections and encrypt the proxied server's responses.
  • Compression - If the proxied server does not send compressed responses, you can configure Nginx to compress the responses before sending them to the clients.
  • Mitigating DDoS Attacks - You can limit the incoming requests and number of connections per single IP address to a value typical for regular users. Nginx also allows you to block or restrict access based on the client location, and the value of the request headers such as “User-Agent” and “Referer”.

This article outlines the steps required for configuring Nginx as a reverse proxy.

Prerequisites

We are assuming that you have Nginx installed on your Ubuntu, CentOS, or Debian server.

Using Nginx as a Reverse Proxy

To configure Nginx as a reverse proxy to an HTTP server, open the domain's server block configuration file and specify a location and a proxied server inside of it:

server {
    listen 80;
    server_name www.example.com example.com;

    location /app {
       proxy_pass http://127.0.0.1:8080;
    }
}

The proxied server URL is set using the proxy_pass directive and can use HTTP or HTTPS as protocol, domain name or IP address, and an optional port and URI as an address.

The configuration above tells Nginx to pass all requests to the /app location to the proxied server at http://127.0.0.1:8080.

On Ubuntu and Debian based distributions, server block files are stored in the /etc/nginx/sites-available directory, while on CentOS in /etc/nginx/conf.d directory.

To better illustrate how location and proxy_pass directives work, let's take the following example:

server {
    listen 80;
    server_name www.example.com example.com;

    location /blog {
       proxy_pass http://node1.com:8000/wordpress/;
    }
}

If a visitor access http://example.com/blog/my-post, Nginx will proxy this request to http://node1.com:8000/wordpress/my-post.

When the address of the proxied server contains a URI, (/wordpress/), the request URI that is passed to the proxied server is replaced by a URI specified in the directive. If the address of the proxied server is specified without a URI, the full request URI is passed to the proxied server.

Passing Request Headers

When Nginx proxies a request, it automatically defines two header fields in a proxied requests from the client, Host and Connection, and removes empty headers. Host is set to the $proxy_host variable, and Connection is set to close.

To adjust or set headers for proxied connections, use the proxy_set_header directive, followed by the header value. You can find a list of all available Request Headers and their allowed values here. If you want to prevent a header from being passed to the proxied server, set it to an empty string "".

In the following example, we are changing the value of the Host header field to $host and removing the Accept-Encoding header field by setting its value to an empty string.

location / {
    proxy_set_header Host $host;
    proxy_set_header Accept-Encoding "";
    proxy_pass http://localhost:3000;
}

Whenever you modify the configuration file, you have to restart the Nginx service for the changes to take effect.

Configuring Nginx as a Reverse Proxy to a non-HTTP proxied server

To configure Nginx as a reverse proxy to a non-HTTP proxied server, you can use the following directives:

  • fastcgi_pass - reverse proxy to a FastCGI server.
  • uwsgi_pass - reverse proxy to a uwsgi server.
  • scgi_pass - reverse proxy to an SCGI server.
  • memcached_pass - reverse proxy to a Memcached server.

One of the most common examples is to use Nginx as a reverse proxy to PHP-FPM:

server {

    # ... other directives

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php7.2-fpm.sock;
    }
}

Common Nginx Reverse Proxy Options

Serving content over HTTPS has become a standard nowadays. In this section, we will give you an example of HTTPS Nginx reverse proxy configuration including the recommended Nginx proxy parameters and headers.

  location/ {
    proxy_pass http://127.0.0.1:3000;
    proxy_http_version  1.1;
    proxy_cache_bypass  $http_upgrade;

    proxy_set_header Upgrade           $http_upgrade;
    proxy_set_header Connection        "upgrade";
    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_set_header X-Forwarded-Host  $host;
    proxy_set_header X-Forwarded-Port  $server_port;
  }
  • proxy_http_version 1.1 - Defines the HTTP protocol version for proxying, by default it it set to 1.0. For Websockets and keepalive connections you need to use the version 1.1.
  • proxy_cache_bypass $http_upgrade - Sets conditions under which the response will not be taken from a cache.
  • Upgrade $http_upgrade and Connection "upgrade" - These header fields are required if your application is using Websockets.
  • Host $host - The $host variable in the following order of precedence contains: hostname from the request line, or hostname from the Host request header field, or the server name matching a request.
  • X-Real-IP $remote_addr - Forwards the real visitor remote IP address to the proxied server.
  • X-Forwarded-For $proxy_add_x_forwarded_for - A list containing the IP addresses of every server the client has been proxied through.
  • X-Forwarded-Proto $scheme - When used inside an HTTPS server block, each HTTP response from the proxied server is rewritten to HTTPS.
  • X-Forwarded-Host $host - Defines the original host requested by the client.
  • X-Forwarded-Port $server_port - Defines the original port requested by the client.

If you don't have an existing SSL/TLS certificate, use certbot to obtain a free Let's Encrypt SSL certificate on your Ubuntu 18.04, CentOS 7, or Debian server.

Conclusion

You have learned how to use Nginx as a Reverse Proxy. We have also shown you how to pass additional parameters to the server and to modify and set different header fields in proxied requests.

If you have any questions or feedback, feel free to leave a comment.