In a previous article we configured a Nginx reverse proxy to work behind a single public IP on a Proxmox node.
We are now able to send requests from Nginx to our internal network, the focus in this guide is on how to get SSL termination on the Nginx reverse proxy in order to serve HTTPS content. The configuration of SSL will only take place in Nginx as our backend server, Apache, will reply in HTTP over the private network back to Nginx which will then send the request to the client over HTTPS.
We will use two tricks to make this work in our reverse proxy setup.
1 – We will add the .well-known location described in RFC-5785 in our Nginx configuration which sets up a webroot on the Nginx server instead of proxying it to the backend server. This folder will allow us to validate the SSL certificate using the Automatic Certificate Management Environment with Certbot.
2 – The Apache module mod_rpaf will help setting our HTTP headers to the right values to fetch our visitors information instead of the proxy’s and allow our SSL certs to work with any websites on apache without further configuration.
Installing Certbot
Certbot is an automated python script to set up letsencrypt certificates on your website. These SSL certificates are recognized by every major browsers, which means you will get the green lock on your website once installed. These certificates have a validity of 3 months and must be renewed every so often, thankfully Certbot can automate the process for us.
Let’s start by installing Certbot, this is straightforward on Ubuntu 16.04 which I will be using in this guide. Check Certbot website for directions on your own distribution.
apt-get update
apt-get install certbot
And you’re done, now we will continue with Nginx configuration.
Setting up Nginx .well-known folder
If you followed my previous guide to setup your Nginx reverse proxy, your /etc/nginx/sites-available/default
config file must look something like this.
listen 80;
listen [::]:80;
server_name website1.mydomain.com;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
location / {
include proxy.conf;
proxy_pass http://192.168.0.4:80/;
}
}
As we can see here we are redirecting everything to 192.168.0.4:80.
We want to add the .well-known location to this configuration, in order to do this we need to create this folder first. You can create it wherever you want on your Nginx server.
echo "WEBSITE1 SSL TEST" > /var/www/ssl/website1/.well-known/test.html
Next we are adding it to our Nginx configuration. Note that we are still using HTTP as this point.
listen 80;
listen [::]:80;
server_name website1.mydomain.com;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
location /.well-known {
root /var/www/ssl/website1/;
}
location / {
include proxy.conf;
proxy_pass http://192.168.0.4:80/;
}
}
Reload Nginx configuration service nginx reload
and you should now be able to access your URL, in my case, http://website1.mydomain.com/.well-known/test.html.
Using Certbot to generate an SSL certificate for your domain
Start with the following command to launch Certbot automated certificate generation.
You will first be prompted for the authentication method to use with the ACME CA. Select 1: Place files in webroot directory (webroot).
Next you are asked to enter your domain name, in my case website1.mydomain.com. And finally you are asked for the webroot for your domain. Here type /var/www/ssl/website1/
or your own folder created previously.
If you did all the previous steps correctly you should now have been issued a letsencrypt SSL certificate directly installed on your server. We’ll now see how to configure it in Nginx and secure it enough to get a ‘A’ grade on SSL testers.
Setting up Nginx for SSL termination
Back in /etc/nginx/sites-available/default
we are going to add a block to handle HTTPS connections and redirect all HTTP to the HTTPS version of our website. Replace your previous configuration with this one.
listen 80;
listen [::]:80;
server_name website1.mydomain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name website1.mydomain.com;
ssl on;
ssl_certificate /etc/letsencrypt/live/website1.mydomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/website1.mydomain.com/privkey.pem;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
location /.well-known {
root /var/www/ssl/website1/;
}
location / {
include proxy.conf;
proxy_pass http://192.168.0.4:80/;
}
}
In order to get the ‘A’ grade for your SSL configuration there is a few tweaks to do, I won’t go through all of them here, but I recommend reading about setting up strong SSL encryption here.
If you used the Nginx configuration described in my previous guide you should already have part of the configuration required for the ‘A’ grade, you will just need to add one thing for your domain.
Using openSSL, generate a new 2048 bits Diffie-Hellman group, replace with your own path.
Then add it in your /etc/nginx/sites-available/default
configuration.
listen 80;
listen [::]:80;
server_name website1.mydomain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name website1.mydomain.com;
ssl on;
ssl_certificate /etc/letsencrypt/live/website1.mydomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/website1.mydomain.com/privkey.pem;
ssl_dhparam /etc/letsencrypt/live/website1.mydomain.com/dhparams.pem;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
location /.well-known {
root /var/www/ssl/website1/;
}
location / {
include proxy.conf;
proxy_pass http://192.168.0.4:80/;
}
}
Finally service nginx reload
and check your server’s grade at SSLlabs. This is not an extensive SSL configuration guide and I would strongly recommend that you read more on the subject, use the links provided in this article as a starting point to get better security.
Configuring Apache mod_rpaf
Back on your apache server on 192.168.0.4.
wget https://github.com/gnif/mod_rpaf/archive/stable.zip
unzip stable.zip
cd mod_rpaf-stable
make
make install
Create a file in/etc/apache2/mods-available
to load the rpaf module.
Add the following line in the file rpaf.load.
Create the module configuration file.
Add the following lines inside rpaf.conf
RPAF_Header X-Real-Ip
RPAF_ProxyIPs 192.168.0.2
RPAF_SetHostName On
RPAF_SetHTTPS On
RPAF_SetPort On
Activate the module with a2enmod rpaf
and reload apache configuration with service apache restart
.
Now any website you add on Apache behind Nginx will use SSL without further configuration.
Conclusion
This guide allowed us to create a full web platform that can be very easily saved and restored to others servers. Using Proxmox built-in backup and restore system you are now able to replicate your platform from one Proxmox server to another as well as your SSL certificates which will still work if moved. In the next guide we will see how to install Piwik to provide analytics in this kind of environment.
thanks a lot, great tutorials
And the file proxy.conf, what contains?
This is detailed in the previous article regarding Nginx configuration: https://www.guyatic.net/2017/04/10/configuring-proxmox-ovh-kimsufi-server-single-public-ip/
Followed the directions with the only exception is the site name and directory. Certbot returns with the error:
The client lacks sufficient authorization
Invalid response from MY_HOST…
404 Not Found
The webroot works – I can hit it using the test.html file in .known_hosts.
nginx is proxying an internal, separate server.
Suggestions?
Are you running these commands as root? Try sudo? Otherwise check the permissions on the well-known folder and files, make sure it is set to 755? Hope this helps.
Reading through this article I realised that the only thing stopping certbot is that it cant catch requests to the .well-known folder when a reverse proxy is configured, so I just commented out the three lines for reverse proxy, ran `certbot` (no params), and everything was installed & configured correctly. After un-commenting the reverse proxy lines again everything works as expected, and SSL report gives me an ‘A’ rating with a stock nginx install on debian 9.