There are two main modes to run the Let's Encrypt client (called Certbot
):
- Standalone: replaces the webserver to respond to ACME challenges
- Webroot: needs your webserver to serve challenges from a known folder.
Webroot is better because it doesn't need to replace Nginx (to bind to port 80).
In the following, we're setting up mydomain.com
.
HTML is served from /var/www/mydomain
, and challenges are served from /var/www/letsencrypt
.
First we create two snippets (to avoid duplicating code in every virtual host configuration).
Create a file /etc/nginx/snippets/letsencrypt.conf
containing:
location ^~ /.well-known/acme-challenge/ {
default_type "text/plain";
root /var/www/letsencrypt;
}
Create a file /etc/nginx/snippets/ssl.conf
containing:
#### Session Tickets
# Session Cache doit avoir la même valeur sur tous les blocs "server".
ssl_session_cache shared:SSL:100m;
ssl_session_timeout 24h;
ssl_session_tickets on;
# [ATTENTION] il faudra générer le ticket de session.
ssl_session_ticket_key /etc/nginx/ssl/ticket.key;
# [ATTENTION] Les paramètres Diffie-Helman doivent être générés
ssl_dhparam /etc/nginx/ssl/dhparam4.pem;
### Headers
add_header Strict-Transport-Security "max-age=15768000; includeSubdomains; preload";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
#### ECDH Curve
ssl_ecdh_curve secp384r1;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK';
Create the folder for the challenges:
sudo mkdir -p /var/www/letsencrypt/.well-known/acme-challenge
Finally to generate the keys used for the sessions and the Diffie-Helman (be patient :)):
sudo mkdir -p /etc/nginx/ssl &&
sudo openssl rand 48 -out /etc/nginx/ssl/ticket.key &&
sudo openssl dhparam -out /etc/nginx/ssl/dhparam4.pem 4096
We don't have a certificate yet at this point, so the domain will be served only as HTTP.
Create a file /etc/nginx/sites-available/mydomain.conf
containing:
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
server_name mydomain.com www.mydomain.com;
include /etc/nginx/snippets/letsencrypt.conf;
root /var/www/mydomain;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
Enable the site:
rm /etc/nginx/sites-enabled/default
ln -s /etc/nginx/sites-available/mydomain.conf /etc/nginx/sites-enabled/mydomain.conf
And reload Nginx:
sudo systemctl reload nginx
Install the package:
sudo apt-get install software-properties-common
sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install certbot
Note: there is also a letsencrypt
package in APT, but it's a much older version of the client.
Request the certificate (don't forget to replace with your own email address):
certbot certonly --webroot --agree-tos --no-eff-email --email [email protected] -w /var/www/letsencrypt -d www.domain.com -d domain.com
It will save the files in /etc/letsencrypt/live/www.mydomain.com/
.
Note: The flag --no-eff-email
opts out of signing up for the EFF mailing list, remove the flag if you'd like to signup.
Now that you have a certificate for the domain, switch to HTTPS by editing the file /etc/nginx/sites-available/mydomain.conf
and replacing contents with:
## http://mydomain.com redirects to https://mydomain.com
server {
listen 80;
listen [::]:80;
server_name mydomain.com;
include /etc/nginx/snippets/letsencrypt.conf;
location / {
return 301 https://mydomain.com$request_uri;
}
}
## http://www.mydomain.com redirects to https://www.mydomain.com
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
server_name www.mydomain.com;
include /etc/nginx/snippets/letsencrypt.conf;
location / {
return 301 https://www.mydomain.com$request_uri;
}
}
## https://mydomain.com redirects to https://www.mydomain.com
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name mydomain.com;
ssl_certificate /etc/letsencrypt/live/www.mydomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/www.mydomain.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/www.mydomain.com/fullchain.pem;
include /etc/nginx/snippets/ssl.conf;
location / {
return 301 https://www.mydomain.com$request_uri;
}
}
## Serves https://www.mydomain.com
server {
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server ipv6only=on;
server_name www.mydomain.com;
#### SSL
ssl on;
ssl_certificate /etc/letsencrypt/live/www.mydomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/www.mydomain.com/privkey.pem;
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/www.mydomain.com/fullchain.pem;
# Google DNS, Open DNS, Dyn DNS
resolver 8.8.8.8 8.8.4.4 208.67.222.222 208.67.220.220 216.146.35.35 216.146.36.36 valid=300s;
resolver_timeout 3s;
include /etc/nginx/snippets/ssl.conf;
root /var/www/mydomain;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
Then reload Nginx:
sudo systemctl reload nginx
Note that http://mydomain.com
redirects to https://mydomain.com
(which redirects to https://www.mydomain.com
)
because redirecting to https://www.mydomain.com
directly would be incompatible with HSTS.
Certbot can renew all certificates that expire within 30 days, so let's make a cron for it. You can test it has the right config by launching a dry run:
certbot renew --dry-run
Create a file /root/letsencrypt.sh
:
#!/bin/bash
systemctl reload nginx
# If you have other services that use the certificates:
# systemctl restart mosquitto
Make it executable:
chmod +x /root/letsencrypt.sh
Edit cron:
sudo crontab -e
And add the line:
20 3 * * * certbot renew --noninteractive --renew-hook /root/letsencrypt.sh
Congratulations, you should now be able to see your website at https://www.mydomain.com
🙂
You can now also test that your domain has A+ SLL rating:
- https://www.ssllabs.com/ssltest/analyze.html?d=mydomain.com
- https://www.ssllabs.com/ssltest/analyze.html?d=www.mydomain.com
I would also recommend setting up content-specific features like Content Security Policy
and Subresource Integrity
:
- Mozilla Observatory: submit a domain to get content-specific advices
- Mozilla Security Guidelines
If Let's Encrypt is useful to you, consider donating to Let's Encrypt or donating to the EFF.