How to secure your site running behind Nginx.
In the past securing a webpage meant spending money and buying a certificate. There was always the self signed alternative but that was not viable for public projects because of the invalid certificate warning.
Today this is not really a issue anymore because there are some alternatives that provide you with free signed certificates for personal and non-profit use.
So there is nothing holding you back from securing your website.
Before we can continue we will have to get a certificate to use with your website. In the past I have used starSSL which has since fallen from grace with the browser vendors, now I am at letsenrypt.org.
The nice thing about letsenrypt.org is that they provide you brilliant way of getting and renewing the certificates. If you have shell access to the server.
A way of doing it without shell access is also described, but I have not tried it.
Lets assume that you got certbot running and have retrieved a certificate for testdomain.com, using the default settings.
You should find the following files in the /etc/letsencrype/live/testdomain.com
Congratulation you have just acquired the needed certificates for your website.
Now we delve “deep” into the Nginx configuration files. If your installation of the server is remotely standard you should have a directory /etc/nginx/sites-available where all available sites are listed. In this folder find the configuration for testdomain.com and open with your editor of choice.
Update the server configuration following the steps:
- Change the listening port from 80 to 443
- Add the ssl flag to the listen directive
- Add a ssl directive with th on flag
- Add a ssl_certificate directive that points to you fully chained certificate
- Add a ssl_certificate_key directive that points to your certificate key file
In the end you should have something like the following:
This is basically all you need to make your website use HTTPS to communicate with the world.
At this point our communication with the user is mostly secure. If we want that A+ rating we will have to do some additional things.
By default all TLS versions are active. Because TLSv1.0 is now considered insecure it should be removed from the list of available TLS versions.
Disabling TLSv1.0 will prevent older clients from connecting to your website
A good starting point for this is the blog post from PCI security standards.
Honestly I do not fully understand what is happening here but i get the concepts and reason for doing it.
Diffie Hellman is a method to exchange cryptographic keys over an unsecured channel. More on this can be found in this wikipedia article about Diffie–Hellman key exchange.
After trying to understand all that I just defaulted to longer D-H parameters are better but there has to be an upper bound! Currently the recommended D-H parameter length is 2048 so after reading these to blogs:
I would suggest and personally use the 4096 bit variant. In combination with the ssl_session_cache all negative impact of the longer parameters should be negated.
So how do we generate them?
Using openssl this is just a question of time.
This command will let you enjoy this screen for quite some time:
After 45 minutes I just left it to itself and went to sleep. So expect to spend some time with this.
There are alternatives.
Sites like https://2ton.com.au/dhtool/ provide you with pre-calculated D-H parameters.
The easiest way to lighten the load is to reuse all of that math being done. This is luckily easily done with the ssl_session_cache directive.
This will create a shared cache of 10Mb. According to the internet 1Mb should be good for 4K sessions.
What exactly this means is beautifully described at https://vincent.bernat.im/en/blog/2011-ssl-session-reuse-rfc5077
And a benchmark can be found at https://www.peterbe.com/plog/ssl_session_cache-ab
The benchmark is also the source of the configuration sample :)
To not cause confusion, here is the complete server configuration for testdomain.com
Now you have a nice little HTTPS configuration going. It gets an A+ ratting but you still have to get your traffic from the unsecured “channel” to the secured one.
I suggest to do that with a 301 Moved Permanently so that each browser only makes the mistake once :)
Here is the server configuration for testdomain.com