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)
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.