Setting up an A+-grade nginx SSL server

By Atomstar on Sunday 27 January 2019 15:25 - Comments (7)
Categories: Linux, RaspberryPi, Security, Views: 3.718

Because I don't want to expose smarthome dashboards (like domoticz or grafana) directly to the internet, I've set up a separate server to publish data beyond my local network. For this I've chosen nginx using let's encrypt certificates renewed by certbot, enabling hsts and fixing the logjam vulnerability.

Rationale

Integrating a web server in a smarthome dashboard violates the Unix philosophy of doing one thing only and doing it well. It's unclear which web server domoticz/grafana uses, and why it's integrated in their codebase. If it's a custom web server, the chances that security is properly implemented is small. Additionally, setting up a separate web server allows me to choose what content I do and don't want to serve.

The reason I've chosen for nginx is that it's widely used (and thus hopefully well-tested) and faster than apache.

Setting up nginx

Install
Install the server as usual
sudo apt install nginx

Enable HTTPS in sites-enabled/default and nginx.conf - no need to make certificates yet.

Get SSL certificate
Get certbot-auto to automatically deploy certificates:
sudo /path/to/certbot-auto —nginx

First dry-run a renew
sudo /path/to/certbot-auto renew --dry-run
then add to crontab, using random delay to load balance for let's encrypt
0 0,12 * * * python -c 'import random; import time; time.sleep(random.random() * 3600)' && /path/to/certbot/certbot-auto renew


Harden security
Now enable HSTS to prevent MITM sslstrip attacks. Add the following to your sites-enabled/default config (source):
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

By default, nginx https is pretty secure, fixing many known vulnerabilities. The logjam attack however, is not mitigated. To fix, follow these instructions:
sudo su
cd /etc/ssl/private
openssl dhparam -out dhparams.pem 2048

in sites-enabled/default, add:
ssl_dhparam "/etc/ssl/private/dhparams.pem"


Redirect HTTP to HTTPS
To limit HTTP exposure to the web, one can redirect all HTTP traffic to HTTPS. However, since certbot only works over HTTP, an exception has to be made to have certificate renewal working.

I've followed these instructions here and here to implement this.

There are three ways certbot can renew certificates, unfortunately none allowing a HTTPS-only server.
  1. HTTP-01: Store a token on your webserver that is retrieved over HTTP
  2. DNS-01: Store a token in your DNS records
  3. TLS-SNI-01: Change the SSL certificate on the server - this method is deprecated

Verify setup
Finally, test your configuration which should give you an A+ grade:
SSL grade A+ test result

Volgende: Speeding up an nginx webserver 09-02 Speeding up an nginx webserver
Volgende: StrongSwan IKEv2 VPN on Raspberry pi 24-12 StrongSwan IKEv2 VPN on Raspberry pi

Comments



By Bas, Sunday 27 January 2019 22:35

Nice!, how would one obtain 100% score on all tests? or would that be a littlebit useless given this use case?

By Tweakers user Kek, Monday 28 January 2019 11:50

DNS-01 doesn't care about http or https, so this can be used to obtain a new certificate for a https only website afaik.

By Tweakers user P1nGu1n, Monday 28 January 2019 18:39

Bas wrote on Sunday 27 January 2019 @ 22:35:
Nice!, how would one obtain 100% score on all tests? or would that be a littlebit useless given this use case?
  • Support only TLS 1.2
  • Key or DH parameter strength >= 4096 bits
  • Support only ciphers with strength >= 256 bits
More info: SSL Server Rating Guide

[Comment edited on Monday 28 January 2019 18:41]


By Tweakers user Atomstar, Monday 28 January 2019 19:33

Kek wrote on Monday 28 January 2019 @ 11:50:
DNS-01 doesn't care about http or https, so this can be used to obtain a new certificate for a https only website afaik.
That's true, but that requires scriptable access to DNS records, which I don't have. Are there easy solutions to this?
P1nGu1n wrote on Monday 28 January 2019 @ 18:39:
[...]
  • Support only TLS 1.2
  • Key or DH parameter strength >= 4096 bits
  • Support only ciphers with strength >= 256 bits
More info: SSL Server Rating Guide
Thanks for the pointer! I thought about tweaking the list of ciphers, but in a discussion the author opted to keep the list simple as opposed to an extensive/complex cipher list. However, https://cipherli.st/ appears to server a simple solution for this as well. I'm OK with the current A+ grade for now ;)

By Tweakers user BIM, Tuesday 29 January 2019 13:14

Thanks for the blog. I've implemented it right away.

I noticed an error in your dhparams config though. The part SSLOpenSSLConfCmd DHParameters "/etc/ssl/private/dhparams.pem" is for Apache and not Nginx.

For Nginx it is ssl_dhparam "/etc/ssl/private/dhparams.pem
(probably a copy/paste error)

By Tweakers user Atomstar, Sunday 3 February 2019 01:01

BIM wrote on Tuesday 29 January 2019 @ 13:14:
Thanks for the blog. I've implemented it right away.

I noticed an error in your dhparams config though. The part SSLOpenSSLConfCmd DHParameters "/etc/ssl/private/dhparams.pem" is for Apache and not Nginx.

For Nginx it is ssl_dhparam "/etc/ssl/private/dhparams.pem
(probably a copy/paste error)
Thanks, that was indeed a typo. Fixed!

Comment form
(required)
(required, but will not be displayed)
(optional)