Let’s Encrypt on Nginx and SSL Grade A+

Posted on October 28, 2016 at 6:38 pm

A few steps to install Let’s Encrypt on Debian with Nginx and score a A+ grade on SSL Labs. We will install Certbot to simplify the creation and renew of SSL certificates with Let’s Encrypt. Simple tutorial that can help you setup Let’s Encrypt with Nginx in just a few minutes.

Login via SSH on your server as root.

Install Certbot via apt-get using -t buster-backports on Debian 10 Buster:

apt-get update
apt-get install certbot -t buster-backports

*** Make sure to enable Debian backports on APT sources.list.

Or install the latest version with git:

apt install -y git
cd /opt
git clone https://github.com/certbot/certbot
cd certbot
./certbot-auto -h

Or install the latest compiled binary version:

cd /usr/bin/
wget https://dl.eff.org/certbot-auto
chmod a+x certbot-auto
mv certbot-auto certbot

Generate DH (Diffie-Hellman) param:

openssl dhparam -out /etc/letsencrypt/dhparams.pem 2048

Let’s Encrypt will try to validate your domain name with an HTTP GET request on a special folder that is automatically created by certbot on your website root path, example:

"GET /.well-known/acme-challenge/%RANDOM_STRING% HTTP/1.1"

Make sure Nginx does not block access to “/.well-known/” folder:

# Deny access to .htaccess-like files
location ~ /\. {
    deny all;
# Allow access to .well-known directory (Let's Encrypt)
location ^~ /.well-known/ {
    allow all;

Generate the certificate for example.com (and www.example.com);

certbot certonly --webroot -w /var/www/vhosts/example.com/public -d www.example.com -d example.com --non-interactive --agree-tos --email your@email.com

You should see a new folder named “www.example.com” on:


Edit the Nginx vhost config file as this:

*** Updated to 2020 – enabled TLSv1.3 and stronger ciphers ***

# Redirect HTTP traffic to HTTPS
server {
        listen 80;
        server_name example.com www.example.com;
        access_log off;
        error_log off;
        return 301 https://www.example.com$request_uri;
# Handle https://www.example.com
server {
        listen 443 ssl http2;
        server_name example.com www.example.com;
        ssl_session_timeout 1d;
        ssl_session_cache shared:MozSSL:10m; # About 40000 sessions
        ssl_session_tickets off;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_prefer_server_ciphers off;
        ssl_certificate /etc/letsencrypt/live/www.example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/www.example.com/privkey.pem;
        ssl_trusted_certificate /etc/letsencrypt/live/www.example.com/chain.pem;
        ssl_dhparam /etc/letsencrypt/dhparams.pem; # Generated by running "openssl dhparam -out /etc/letsencrypt/dhparams.pem 2048" as root user
        ssl_buffer_size 8k; # This is optional, default is 16k
        add_header Strict-Transport-Security "max-age=63072000" always;
        add_header X-Frame-Options SAMEORIGIN;
        add_header X-Content-Type-Options nosniff;
        add_header X-XSS-Protection "1; mode=block"; 
        resolver valid=300s;
        resolver_timeout 5s;
        access_log /var/www/vhosts/example.com/logs/access.log main;
        error_log /var/www/vhosts/example.com/logs/error.log warn;
	root /var/www/vhosts/example.com/public;
	index index.html index.htm index.php;
	# Redirect non-www to https://www.
    	if ($host !~ ^www\.) {
    	    rewrite ^ https://www.$host$request_uri permanent;

Some online tools that can help you configure Nginx for HTTPS:

Mozilla SSL Configuration Generator
Security/Server Side TLS – MozillaWiki

Restart Nginx service:

/etc/init.d/nginx restart

Now test your website on SSL Labs and you should get A+ grade:

The SSL certificate created by Let’s Encrypt is valid for 90 days.

To renew the certificate before it is expired, you can use this command that is used to renew all SSL certificates present in the /etc/letsencrypt/renew/ directory:

certbot renew --webroot --noninteractive --post-hook "service nginx reload"

Example output:

Processing /etc/letsencrypt/renewal/www.example.com.conf
Processing /etc/letsencrypt/renewal/www.test.com.conf
The following certs are not due for renewal yet:
  /etc/letsencrypt/live/www.example.com/fullchain.pem (skipped)
  /etc/letsencrypt/live/www.test.com/fullchain.pem (skipped)
No renewals were attempted.

For automatic renewals you may add this line of code in /etc/crontab file:

0 */12 * * * root certbot renew --webroot --noninteractive --post-hook "service nginx reload"

* But make sure to delete /etc/cron.d/certbot if you use /etc/crontab!

You should read this:

Lets Encrypt certificate failed to renew
Renew an expired Lets Encrypt / Certbot certificate

Another way to auto-renew the certificates is by editing this file (recommended):


By adding the “–post-hook” code to reload the web server:

# /etc/cron.d/certbot: crontab entries for the certbot package
# Upstream recommends attempting renewal twice a day
# Eventually, this will be an opportunity to validate certificates
# haven't been revoked, etc.  Renewal will only occur if expiration
# is within 30 days.
0 */12 * * * root test -x /usr/bin/certbot -a \! -d /run/systemd/system && perl -e 'sleep int(rand(3600))' && certbot -q renew --post-hook "service nginx reload"

And here is my favorite way to auto-renew the certificates (what I use):

Automatically Renew Let’s Encrypt certificate (Nginx)

References and useful links:

How to Correctly Backup and Restore /etc/letsencrypt
Let’s Encrypt – Free SSL/TLS Certificates
SSL Server Test (Powered by Qualys SSL Labs)
Mozilla SSL Configuration Generator
‘certbot -renewal’ is not renewing the certificate
Check your HTTP Security Headers

Updated on May 6, 2020 at 4:41 pm

Receive updates via email

Other Posts

Updated Posts