Links on Super Easy may earn us a commission. Learn more.

How to Configure Nginx as an HTTPS Reverse Proxy (Easily)

1,858 Views

Nginx is hands down the most popular web server among beginners and professionals. With the handy proxy_pass directive, you can easily build a reverse proxy in a few lines of configuration.

In this step-by-step guide, we’ll show you how to set up a reserve proxy with Nginx.

Why do you need a reverse proxy

A reverse proxy acts as a portal between users and the real service, which is a common practice in deploying CDNs (Content delivery network). It’ll make your application scalable and resilient, as you can now control and monitor traffic with Nginx. And you can easily hide your backend API and avoid regional censorship with TLS.

Here’s some common use cases for reverse proxies:

  • Load balancing to route incoming requests
  • Monitor, redirect and log traffic
  • Expose/Protect your backend services (HTTPS to HTTP)
  • Accelerate web speed in other continents

And next we’ll show you how to set up a reverse proxy in just a few minutes.

How to set up an HTTPS reverse proxy with Nginx

Here’s an quick example of how to configure Nginx as an HTTPS reverse proxy. Although the tutorial targets Linux users, if you’re on Windows, you can just jump to the configuration part.

Prerequisites:

  • Access to a Linux server (Debian/Ubuntu/CentOS) with a sudo user (You can create a new server on Bluehost in just seconds)
  • A SSL certificate (Let’s Encrypt is free, but a business cert saves a lot of troubles and makes your site more credible)
  • A domain (Grab one from GoDaddy or Namecheap)

Step 1: Install Nginx

First, you need to have Nginx installed on your server. To make it quick, we’ll be installing from the official repository of your Linux distribution. You can also get the latest build from the Nginx repo, or build from source if you need enhanced features or third-party modules.

Debian 9 or later & Ubuntu 18.04 or later:

sudo apt-get update
sudo apt-get install nginx -y

CentOS 7:

sudo yum install epel-release -y 
sudo yum install nginx -y

CentOS 8:

sudo dnf install nginx -y

Step 2: Edit the configuration

Next you can create a new one configuration for your domain:

Debian & Ubuntu:

sudo nano /etc/nginx/sites-enabled/demo.conf

CentOS 7:

sudo vim /etc/nginx/sites-enabled/demo.conf

CentOS 8 :

sudo vim /etc/nginx/conf.d/demo.conf

Here’s a quick example of a working reverse proxy configuration. (Note that you should replace the domain and the location of certificate with the ones of your own.)

server {
   listen 80;
   server_name example.yourdomain.com;
   return 301 https://example.yourdomain.com$request_uri;
 }

server {
   listen 443 ssl;
   server_name example.yourdomain.com;
   ssl_certificate  /path/to/your/certificate;
   ssl_certificate_key  /path/to/your/certificate/key; 
   ssl_prefer_server_ciphers on;

   location / {
        proxy_pass http://localhost:8080;

        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;
}

In the example above, we assume you have a backend service running at the 8080 port. If you find this config doesn’t work for you, check if your backend service needs additional configurations.

Common pitfalls and solutions

If the reverse proxy doesn’t work as expected, you should first take a look at the error log:

less /var/log/nginx/error.log

But sometimes there’ll be no error at all. Maybe it’s the wrong configuration, or maybe it’s your backend. Either way, you can start troubleshooting by checking the common mistakes below.

1. 502 Bad Gateway caused by wrong upstreams

Wrong configuration:

upstream backend {
        server 111.111.111.111; # Use your own IP address
}
server {
...
location /{
  proxy_pass https://backend;
    }
}

Cause:

In this example, the configuration contains the proxy_pass directive and the upstream module. A 502 Bad Gateway error was raised due to the misconfiguration of server address in upstream.

Here’s the Nginx documentation for the server block:

Defines the address and other parameters of a server. The address can be specified as a domain name or IP address, with an optional port, or as a UNIX-domain socket path specified after the “unix:” prefix. If a port is not specified, the port 80 is used. A domain name that resolves to several IP addresses defines multiple servers at once.

Solution:

Specify the port number in the upstream block:

upstream backend {
        server 111.111.111.111:443; # User your own IP address
}
server {
...
location /{
  proxy_pass https://backend;
    }
}

Then reload the config with sudo nginx -s reload.

2. 502 Bad Gateway due to wrong certificates

If you’re hosting multiple domains on one IP address, you’ll need to configure SNI (Server Name Indication) manually. SNI is an extension to the TLS protocol that allows a server to have multiple certificates on the same IP address and TCP port number.

When a client establishes a connection to a server, it refers to a specific IP address. You don’t need SNI for HTTP sites, but since the TLS handshake doesn’t allow clients to indicate which domain they’re requesting, SNI then becomes necessary. (This is especially the case if you’re on CDN.)

Example 1: Configure SNI without the upstream directive

Wrong:

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

Correct:

server {
    ...
    location /{
        proxy_pass https://your-backend.com;
        proxy_ssl_server_name on;
        #proxy_ssl_name $proxy_host;   
    }
}

The proxy_ssl_server_name directive enables passing of the server name through TLS Server Name Indication extension (SNI). If there’s no upstream, setting proxy_pass as your-backend.com gives $proxy_host the same value. Enabling proxy_ssl_server_name passes your-backend.com to the upstream server. (proxy_ssl_name $proxy_host is the default setting.)

Example 2: Configure SNI with the upstream directive

Wrong:

upstream backend {
        server 111.111.111.111:443; # Use Your own IP address
}

server {
    ...
    location /{
        proxy_pass https://backend;
        proxy_ssl_server_name on;
    }
}

Correct:

upstream backend {
        server 111.111.111.111:443; # Use Your own IP address
}

server {
    ...
    location /{
        proxy_pass https://backend;
        proxy_ssl_server_name on;
        proxy_ssl_name your-domain.com;
        proxy_set_header Host $host;
    }
}
In case you don’t know what upstream is: the upstream directive defines a group of servers that can be referenced by the proxy_pass directive.

During a TLS handshake, you need to specify the domain with the proxy_ssl_name directive, whose value is now set to a variable named backend as upstream is defined. Additionally, for the upstream directive to work, you need to pass the $host variable to the proxied server with the proxy_set_header directive.

DirectiveDefault
proxy_set_headerHost $proxy_host;

3. 400 Bad Request

This usually happens when plain HTTP requests were sent to an HTTPS port. In that case, change the proxy_pass variable to an HTTPS address.

Wrong:

upstream backend {
        server 111.111.111.111:443; # Use your own IP address
}
server {
...
location /{
    proxy_pass http://backend;
    }
}

Correct:

upstream backend {
        server 111.111.111.111:443; # Use your own IP address
}
server {
...
location /{
    proxy_pass https://backend;
    }
}

By Marcus Liang

As a writer at supereasy.com, Marcus possesses a special insight about computer issues and life hacks. In the quest of personal fulfillment, he writes handy tutorials and shares fresh information to help improve people's lives. In his free time, he's obsessed with programming and web-developing.

×
Failed to load the Search bar. Please refresh the page and try again.
Click here to reload