Contents

Nginx Reverse Proxy and SSL Termination

Have you ever been stuck with the realization that you need to expose many different web services to the internet but only have one public IP on your firewall? As IPv4 space becomes more scarce, this is a problem that is coming up more often than not. One solution is to use a webserver such as Apache that supports virtual hosting. You can store as many websites on this server as it will handle, just need to map the public 80/443 through the firewall to your webhost. This solution works great for a catchall webhost however it falls apart when you have front-end GUIs for services running on multiple servers. At this point, you either need to call your datacenter/ISP account rep and beg for a larger block of IP space, or build a reverse proxy! or deploy ipv6

Reverse Proxy Basics

A reverse proxy is a service that accepts incoming connections and forwards them to the correct server needed to handle the request. The proxy works much like virtual hosts in Apache. When a web request is sent to the proxy server, it takes the URL and finds a matching directive in the config. This directive will tell the proxy server where to send the traffic upstream. The second part of this article will talk about SSL termination at the proxy. Because the reverse proxy will be behind a firewall, you can terminate the encryption and forward plain text on to a web server. I will show this using everyone’s favorite certificate authority, Let’s Encrypt!

Pro’s / Cons

Positives

  • The ability to, behind a single port 80/443, host as many web services on as many web servers as your proxy server can handle.
  • The ability to easily administer SSL certificates on a single machine
  • The ability to scale the server to best deal with the overhead required when handling many SSL connections.

Negatives

  • Despite being behind a firewall, and dependent on the sensitivity of the traffic you pass, you might not want to allow plan text between the proxy and the web server as a compromised host on the same LAN could possibly intercept traffic. As always, security comes in layers and a firewall does not protect against all threats.
  • If the reverse proxy fails, it will take down access to all sites that it handles. (this can be addressed by Nginx high availability however that is beyond the scope of this article)
Note about SSL Support
SSL connections are troublesome because the requested URL is encrypted with the packet and not visible until decryption. To overcome this, SNI (Server Name Indication), was build as an extension to TLS that adds the URL in the TLS handshake so the matching directive can be applied and the traffic sent to the correct server. To check that SNI is built into Nginx, run the following on your Nginx server nginx -v You should see “TLS SNI support enabled” in the output.

Nginx Configuration

I am going to configure the server on CentOS7 however the principals outlined in this article can be used with minor modification on other linux distributions.

Install Software

yum install epel-release
yum install nginx

Enable service and configure firewall

systemctl enable nginx
firewall-ctl --permanent --add-service http
firewall-ctl --permanent --add-service https
firewall-ctl --reload

Nginx Config File

Configuration for Nginx is found under /etc/nginx. We will be creating a unique configuration block for each web server our reverse proxy will handle. These configurations live under /etc/nginx/conf.d. In order to keep things organized, I typically use the domain name for the configuration file name.

server {
# The IP that you forwarded in your router (nginx proxy)
 listen 192.168.240.39:80;
# Make site accessible from http://localhost/
 server_name web.bananatrunkingprotocol.com;
# The internal IP of the VM that hosts your Apache config
 set $upstream 192.168.240.45;

 location / {

 proxy_pass_header Authorization;
 proxy_pass http://$upstream;
 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_http_version 1.1;
 proxy_set_header Connection "";
 proxy_buffering off;
 client_max_body_size 0;
 proxy_read_timeout 36000s;
 proxy_redirect off;

 }
}

This configuration tells Nginx to inspect incoming traffic on port 80 looking for the URL of web.bananatrunkingprotocol.com. When a match is found, that traffic is directed to the upstream at 192.168.240.45
Before we test the following is assumed:

  • The web server at the upstream of 192.168.240.45 is correctly configured and is presenting a webpage.
  • The firewall in front of your reverse proxy has the correct port forward in place to direct public traffic to the proxy.
  • DNS is set so the A record of web.bananatrunkingprotocol.com lists the public IP of your network.

To test, start Nginx and point your browser to the public IP of your network. If all is configured correctly, you should see the webpage configured on 192.168.240.45


SSL Configuration

Certbot Setup

Now that the reverse proxy is working, we need to set up SSL encryption.
First we will install the Let’s Encrypt certificate management utility called certbot.

yum install certbot-nginx

Obtaining a Certificate

To run certbot:

certbot --nginx -d web.bananatrunkingprotocol.com

If this is your first time running the certbot utility on your server, you will be prompted to provide your email address and accept terms. Assuming everything is configured correctly, you should have a shinny new certificate for your website

If certbot fails, check the following:

  • You have the needed port forward and access rules for 80/443 setup in your firewall
  • You have the correct A record in your DNS zone for web.bananatrunkingprotocol.com (should be the public IP of your firewall/router)
  • The firewall on the reverse proxy is open on 80/443

The final step is to restart the service to pickup the new config changes inserted by certbot

systemctl restart nginx

If this restart fails, read through your nginx logs and take a look at the changes certbot made to your config.

Behind the Scenes

The certbot utility works as a certificate broker to the Let’s Encrypt servers. When run, it will do all the hard work.
Basic Nginx certbot process (automated through certbot):

  • Take the domain specified on the command line and compare it to server_name directives found in the Nginx config
  • Setup a challenge to verify that you control the domain you’re requesting a certificate for. (HTTP-01 challenge by default)
  • If the challenge passes, certbot will install the certificate and edit your Nginx config to add in the needed SSL directives.

Further Reading