Let’s Encrypt is a free and open source certificate authority developed by Let’s Encrypt Internet Security Research Group(ISRG). Certificates issued by Let’s Encrypt are trusted by almost all browsers today.
In this tutorial, we will provide step by step instructions on how to secure your Nginx with Let’s Encrypt using certbot tool on CentOS 7.
precondition
Make sure you meet the following prerequisites before proceeding with this tutorial:
- You have a domain name that points to your public server’s IP address. In this tutorial we will use domains
example.com
. - Activate the EPEL repository and install Nginx by following the tutorial How to Install Nginx on CentOS 7.
Install Certbot
Certbot is a full-featured, easy-to-use tool that can automate the task of obtaining and renewing Let’s Encrypt SSL Certificates. Certbot will also manage all web server configurations so they can use the certificate directly.
To install the certbot package from the EPEL repository, run the following command:
sudo yum install certbot
Create a Dh key exchange certificate (Diffie-Hellman)
Diffie-Hellman (DH) key exchange is a method of exchanging secure cryptographic keys over an insecure communication channel. We will create a new 2048-bit DH parameter to enhance security:
sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048
If you are still paranoid, you can change the size up to 4096 bits, but in this case, the release may take more than 30 minutes depending on the processing capabilities of your system.
Obtained Let’s Encrypt SSL certificate
To get the SSL certificate for the domain we will use the Webroot plugin which works by creating a temporary file to validate the required domain in the directory ${webroot-path}/.well-known/acme-challenge
.
Let’s Encrypt server makes HTTP requests for temporary files to verify that the requested domain has completed data requests to the server where certbot is running.
To keep it simple, we will set all HTTP requests to .well-known/acme-challenge
to a single directory, /var/lib/letsencrypt
.
The following command will create a directory and make it writable by the Nginx server.
sudo mkdir -p /var/lib/letsencrypt/.well-known sudo chgrp nginx /var/lib/letsencrypt sudo chmod g+s /var/lib/letsencrypt
To avoid code duplication, create the following two snippets which we will include in all Nginx server block files.
Open your text editor and create an excerpt letsencrypt.conf
:
sudo mkdir /etc/nginx/snippets
location ^~ /.well-known/acme-challenge/ { allow all; root /var/lib/letsencrypt/; default_type "text/plain"; try_files $uri =404; }
Create the snippets ssl.conf
Which includes the Mozilla-recommended profiler, enables OCSP Stapling, HTTP Strict Transport Security (HSTS) and enforces some security-focused HTTP headers.
sudo nano /etc/nginx/snippets/ssl.conf
ssl_dhparam /etc/ssl/certs/dhparam.pem; ssl_session_timeout 1d; ssl_session_cache shared:SSL:50m; ssl_session_tickets off; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS'; ssl_prefer_server_ciphers on; ssl_stapling on; ssl_stapling_verify on; resolver 8.8.8.8 8.8.4.4 valid=300s; resolver_timeout 30s; add_header Strict-Transport-Security "max-age=15768000; includeSubdomains; preload"; add_header X-Frame-Options SAMEORIGIN; add_header X-Content-Type-Options nosniff;
Once the snippets are generated, go to the domain server block and include the snippets letsencrypt.conf
As shown below:
/etc/nginx/conf.d/example.com.conf
server { listen 80; server_name example.com www.example.com; include snippets/letsencrypt.conf; }
Restart the Nginx service for the changes to take effect:
sudo systemctl reload nginx
Now you can run Certbot using the webroot plugin and get the SSL certificate file by typing the command:
sudo certbot certonly --agree-tos --email [email protected] --webroot -w /var/lib/letsencrypt/ -d example.com -d www.example.com
If the SSL certificate was obtained successfully, certbot will print the following message:
IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at: /etc/letsencrypt/live/example.com/fullchain.pem Your key file has been saved at: /etc/letsencrypt/live/example.com/privkey.pem Your cert will expire on 2018-06-11. To obtain a new or tweaked version of this certificate in the future, simply run certbot again. To non-interactively renew *all* of your certificates, run "certbot renew" - If you like Certbot, please consider supporting our work by: Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate Donating to EFF: https://eff.org/donate-le
Now that you have the certificate file, you can edit your domain server block as follows:
server { listen 80; server_name www.example.com example.com; include snippets/letsencrypt.conf; return 301 https://$host$request_uri; } server { listen 443 ssl http2; server_name www.example.com; ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem; include snippets/ssl.conf; include snippets/letsencrypt.conf; return 301 https://example.com$request_uri; } server { listen 443 ssl http2; server_name example.com; ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem; include snippets/ssl.conf; include snippets/letsencrypt.conf; # . . . other code }
With the above configuration, we force the use of HTTPS and redirect from the www version to the non-www version.
Restart the Nginx service for the changes to take effect:
sudo systemctl reload nginx
How to auto-renew Let’s encrypt SSL certificates
Let’s Encrypt certificates are valid for 90 days. To automatically renew certificates before they expire, the certbot package creates a cronjob that runs twice a day and will automatically renew any certificate within 30 days before the certificate expires.
Run command crontab
To create a new cronjob:
sudo crontab -e
Copy and paste the following line:
0 */12 * * * root test -x /usr/bin/certbot -a \! -d /run/systemd/system && perl -e 'sleep int(rand(3600))' && certbot -q renew --renew-hook "systemctl reload nginx"
Save and close the file.
To test the update process, you can use the certbot command followed by a statement --dry-run
:
sudo certbot renew --dry-run
If there are no errors, the test update was successful.
conclusion
In this tutorial, you can use the Let’s Encrypt client, certbot, to download an SSL certificate for your domain. I also created Nginx snippets to avoid code duplication and set Nginx to use certificates. At the end of the tutorial, I set up a cronjob to automatically renew the certificate.