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 home.domain.co.uk
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 prefix.domain.co.uk, 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. *.domain.co.uk) which will allow me to use just one certificate, rather than the 5 I have now!
Hello,
I am doing the same as you. Searching the internet I found this article of yours.
I would like to know if you can help me.
On a VM mounted on virtualbox, I have FreeNAS installed which is a FreeBSD based operating system.
This VM has a bridge configuration to take internet from my home network.
I have created a jail, there I am configuring a reverse proxy to attend to all incoming requests to my freeNAS.
My idea is to install a SSL Lets encrypt wilcard certificate over the jail with nginx. As investigated in:
https://letsencrypt.org/es/docs/challenge-types/
To be able to do it, lets encrypt says that I have to do the validation by DNS and I have to create some TXT records and the DNS zone has to be accessible via API. They display a list of supported DNS services:
In my case I consider 2 options: DuckDNS or Cloudflare.
My # 1 question is:
The proxy must be assigned a public IP so that it can resolve the DNS, but the jail has a local IP configured. In the jail I have a VNET + NAT configured without DHCP (fixed local IP).
Should I use a Dynamic DNS service to be able to link my dynamic IP (from the ISP) with the local IP of the jail and then do a port forwarding on my router? What is the best option: Cloudflare or Duck DNS.
My # 2 question is:
In the jail where I have the r-proxy, how can I link my domain? What steps should I take?
My # 3 question is:
My FreeNAS private IP is 192.168.0.105 (NAT)
My Jail’s private IP (r-proxy) is 172.6.0.2 (NAT)
If I ping the jail, I cannot access. How can I make the IP of the jail (r-proxy) accessible from my local network? I need this to work so that I can configure port forwarding on my router.
You can help?
Cheers
Hello, Alejandro. You’d be best asking for some help on the appropriate web forum, as I’m pretty sure my limited networking knowledge isn’t going to be of much help! That, said, my thoughts on your comment above:
– FreeNAS really isn’t designed to be run in a VM, and certainly not VirtualBox.
– I can’t help around the dynamic external IP address either, as mine is static. I’m sure there are services that will handle this, but I don’t use one. I have A records on my domain hosting service that point to my static IP address
– I also use individual letsencrypt certificates for each service (named using subdomains) as these can be validated by the reverse proxy and don’t require any validation at the domain level. I’m pretty sure you can’t do this with a wildcard, which will require some configuration in the domain hosting Cpanel
– Finally, I’m a little confused as to why your jails are in a different IP range to your FreeNAS. Mine are all in the same IP range with the same subnet, gateway and DNS settings.
Good luck with everything though!