Let's Encrypt is a new, free, automated, and open Certificate Authority.
Find out more out Let's Encrypt, and how you can use in the Let's Encrypt documentation.
This file will guide you through the minimum things you need to set up Let's Encrypt on your nginx webserver.
Before we get started we need to install the letsencrypt/certbot CLI tool. You can follow the installation instruction over at Certbot.
Before we configure our vhosts we want to set up some default configurations. Start out creating a temporary webroot:
$ mkdir -p /usr/local/etc/nginx/letsencrypt
Next up we need to create this common router for our domains. This will point to the /.well-known/acme-challenge/
folder in our webroot to confirm the domains. Let's create the file /usr/local/etc/nginx/acmechallenge.conf
:
# letsencrypt acme challenge for domain verification
location '/.well-known/acme-challenge/' {
root /usr/local/etc/nginx/letsencrypt;
}
# redirect all traffic to http -> https
location / {
return 301 https://$server_name$request_uri?;
}
Create a confirugation file for your vhost/domain in the nginx.conf (or a sepparate file you include):
server {
listen 80;
listen [::]:80;
server_name mydomain.com www.mydomain.com;
include /usr/local/etc/ningx/acmechallenge.conf; # the config created in the step above
}
... then reload nginx:
$ service nginx reload
Now your server will redirect you to the https
version every time you vists modomain.com.
This can be done in the CLI, but we're using a config file instead. Check out the documentation for more information on how to set up the configuration file.
Let's create mydomain.ini:
rsa-key-size = 4096
email = [email protected]
domains = mydomain.com, www.mydomain.com
text = True
authenticator = webroot
webroot-path = /tmp/letsencrypt/
Run certbot to obtain the certificates:
$ certbot certonly -c mydomain.ini
(on some systems the tool would be named letsencrypt. I.e. FreeBSD).
Now we need to add a new server section to our vhost configuration who listen to port 443 (https):
server {
listen 80;
listen [::]:80;
server_name mydomain.com www.mydomain.com;
include /usr/local/etc/ningx/acmechallenge.conf;
}
server {
listen 443;
listen [::]:443;
server_name mydomain.com, www.mydomain.com;
ssl on;
ssl_stapling on;
ssl_stapling_verify on;
## These files are the certificates we just requested
ssl_certificate /usr/local/etc/letsencrypt/live/mydomain.com/fullchain.pem;
ssl_certificate_key /usr/local/etc/letsencrypt/live/mydomain.com/privkey.pem;
ssl_trusted_certificate /usr/local/etc/letsencrypt/live/mydomain.com/chain.pem;
location / {
root /usr/local/var/www/;
}
}
Reload nginx:
$ service nginx reload
and you're good to go!
Your Let's Encrypt certificates will expire after 3 month. It's recommended to renew them every 2 month. To do this we set up crontab to run the renew
command every 2 month:
0 0 1 1,3,5,7,9,11 1 /path/to/certbot renew --quiet
5 0 1 1,3,5,7,9,11 1 service nginx reload
To further increase security, you should generate a strong Diffie-Hellman group. This command will generate a 4096-bit group:
$ openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096
To allow only the most secure SSL protocols and ciphers, and use the strong Diffie-Hellman group we generated, add the following lines to the server block:
add_header Strict-Transport-Security 'max-age=15552000; preload';
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
gzip off;
ssl_dhparam /etc/ssl/certs/dhparam.pem; ## the diffie hellman group we generated
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
ssl_prefer_server_ciphers on;
ssl_session_timeout 10m;
ssl_session_cache shared:SSL:10m;
ssl_stapling on;
ssl_stapling_verify on;
Compression over SSL will open up some bad stuff. gzip
is therefore deactivated.
Deactivating TLSv1 and TLSv1.1 will give best security. But will leave out a lot of users whom still using older software.
See the nginx ssl documentation for https support.
The recommended cipher suite is*:
ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
The recommended suite for backward compatibility(WinXP) is:
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:ECDHE-RSA-AES128-GCM-SHA256:AES256+EECDH:DHE-RSA-AES128-GCM-SHA256:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
Run the command openssl ciphers
to see the full list of ciphers.
You can simulate the handshake at SSL Labs.
Check out these posts for an overview on nginx' security:
As I can see, there is one problem with your crontab. What if there are issues with the Let's Encrypt servers or your own server on this specific day? Shouldn't you fire this command every day?
certbot renew
only attempts to renew any previously-obtained certificates that expire in less than 30 days (https://certbot.eff.org/docs/using.html#renewal).