Reverse Proxy Diagram

I’ve written a few blogs about this subject too (most recently here), so after several attempts which worked, but were a little messy, I’ve done a bit more research.  That’s led me to create a single jail to work as a both a reverse proxy with SSL.  I’ll be using all the same tools as before, so NGINX for the reverse-proxy and Certbot to create (and hopefully automatically renew) the LetsEncrypt certificates.

Configure the Jail

My first job was to create the jail and install all the required components.  In the past, I’ve taken the easy option and installed everything using the package route, but it was suggested that installing from the ports tree with some specific settings would result in a more secure installation and avoid the CVE-2016-2107 vulnerability (which affects the package version because it’s built against the base version of OpenSSL in FreeBSD 10.3).  So here are the commands:

# pkg update
# pkg upgrade
# pkg install nano (my preferred editor, and no package dependencies)
# portsnap fetch
# portsnap extract
# nano /etc/make.conf (add the line: DEFAULT_VERSIONS+=ssl=openssl)
# cd /usr/ports/security/openssl/ && make install clean
# cd /usr/ports/www/nginx/ && make install clean
# cd /usr
/ports/lang/python/ && make install clean
# cd /usr/ports/security/py-certbot/ && make install clean
# nano /etc/rc.conf (add the line: nginx_enable=”YES”)

I installed everything with the default options, so after lots of ‘returns’ and a restart of the jail, I checked the NGINX was running before getting into the configuration.  I also took a snapshot at this point, so if I screw anything up, I can roll-back to a clean jail with everything installed.

Create the Certificates

So first things first – the SSL certificates.  Before I can run the certbot command though, I need to change the port forwarding on my router to direct traffic on port 80 and 443 to this new jail, which will bring down everything else for a short time.  Once I’d done that I ran:

# certbot certonly webroot w /usr/local/www/ d

After following the on-screen prompts, this created an error, as I’d forgotten to change the root location in the nginx.conf file.  I changed this to /usr/local/www and certbot then generated the certificate into the /usr/local/etc/letsencrypt folder.

I then reran this for all of the domains I needed certificates for.  It would have been possible to do this as a single command each with -d, but I wanted to see each one created successfully.

Set-up NGINX

My existing reverse proxy jail works fine, so I took the easy option and simply copied across all the nginx configuration files.  I’ve got this setup using sites-enabled, so each web service that is being proxied has its own service.conf file, rather than trying to combine everything into one.  This might be a little overkill given I’m managing everything, but it seems to be ‘best practice’ and should keep things simpler once everything is configured.  This was simply a case of copying over the nginx.conf file and sites-available folder and then create symbolic links to the ‘available’ files in the ‘enabled’ folder I created.

# cp /mnt/pool/jails/nginx-proxy/usr/local/etc/nginx/files /mnt/pool/jails/ssl_proxy/usr/local/etc/nginx/files
# ln -s ./sites-available/*.* ./sites-enabled

I then needed to edit the SSL locations in the service.conf files, and remembered that I also need to recreate the Diffie-Hellman (DH) Key, which is pretty straightforward but takes a little time.

# cd /usr/local/etc/ssl
# openssl dhparam -out dhparam.pem 4096

Once this was done, I restarted the nginx service and crossed my fingers!   After a few minor tweaks to the nginx.conf files where I’d not typed the changes correctly, everything is working as expected.  Whoo Hoo!!!

Test Renewal

As the last test, I thought I’d simulate renewing the certificates, so I know everything should work in 3 months time.  This is So now at least I have my SSL certificates created inside my reverse proxy jail.

# certbot renew –dry-run

It would have all been a bit too easy if this had worked, but it didn’t take too long to find my problem.  The service.conf files only had locations from the reverse proxy, and for the certbot renewal to work it needs access to the /.well-known folder.  Only adding a location at the bottom of the server block resolved this, and the dry run worked fine.

# location /.well-known {
#    root /usr/local/www;
# }

Hopefully, when I come to renew in 3 months they will all update, and everything will be a lot simpler to manage moving forward.  Maybe by then, Letencrypt will offer wildcard certificates (e.g. * which will allow me to use just one certificate, rather than the 5 I have now!