Install Let's Encrypt and Secure Nginx with SSL/TLS in Debian 9

This tutorial will show you how to install and secure a Nginx web server on Debian 9 with a TLS certificate issued for free by the Let’s Encrypt Certificate Authority. Furthermore, we will configure automatic renewal of Lets’ Encrypt TLS certificates using a cron job before the certificates expire.

TLS, also known as Transport Layer Security, is a network protocol that uses SSL certificates to encrypt the network traffic which flows between a server and a client, or between a web server, such as Nginx server, and a browser. All data exchanged in between these two entities is secured and the connection cannot be decrypted even if it is intercepted using a technique such as by a man in the middle attack or packet sniffing. The certbot package software is the official client utility provided by Let’s Encrypt CA that can be used in the process of generating and downloading free Let’s Encrypt certificates in Debian.


  • Install LEMP Stack in Debian 9.
  • A public registered domain name with proper DNS records ( A records or CNAME records for subdomains).
  • Direct access to server’s console or remote SSH access to server.
  • A user account with root privileges or direct access to root account.

Install Certbot Client Utility

In order to install Let’s Encrypt cerbot client utility in Debian 9 from Debian official repositories, open a terminal and issue the following command with root privileges, as illustrated in the following screenshot.

apt-get install certbot

Install Certbot on Debian 9

The Debian apt utility, which is the command line interface of the Debian main Package Manager, will ask you, after some preliminary checks, whether if you agree to continue with installing the certbot package and all its required dependencies.  To accept the process of installing the software answer with yes (y) in server’s console prompt.

Get Let’s Encrypt Certificate

To generate and download Let’s Encrypt certificates for a domain, first make sure Nginx web server is up and running and at least port 80 is accessible from the internet. To verify if Nginx is running execute the following commands with root privileges.

sudo systemctl status nginx

If the server is not running already, start Nginx daemon with the below command.

sudo systemctl start nginx

In case you have a common firewall installed in Debian, such as UFW firewall, which blocks all incoming connections on port 80 and 443, issue the below commands to open HTTP amd HTTPS port in the system.

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

In order to obtain certificates for your domain, execute the cerbot command in console with the following parameters and flags as explained below. Run the command with root privileges and supply your domain name and all other subdomains you want to obtain certificates for by using the –d flag. Also, supply the --standalone option in order for certbot to not interfere with Nginx configuration files. The Nginx server must be stopped while issuing certificates using this option.

The cerbot command syntax:

sudo certbot certonly --standalone –d –d

When you first run certbot command and obtain the certificate you will be prompted to add your email address and to agree with Let’s Encrypt terms of service.  Write ‘a’ to agree to the service terms ‘no’ to not share your email address with Let’s Encrypt partners. Finally, after you’ve obtained the certificate for your domain, read the footer notes to locate certificates system path and the date they will expire.

Alternative way to get a Let's encrypt SSL certificate

To obtain a Let’s Encrypt certificate via the "webroot" plugin use the below syntax. Add Nginx web root directory, which by default is located in /var/www/html/ system path, while issuing certbot command with the --webroot and –w flags. Also, make sure that Nginx has full write permissions to web root directory in order to create the /.well-known directory.

The --webrot option for cerbot will also ask you add your email address for certificate renewal and security notices. Certbot client has built-in code that can detect a fake email address. You must provide a public accessible e-mail address in order to continue obtaining a certificate.

certbot certonly --webroot –w /var/www/html/ -d –d


Saving debug log to /var/log/letsencrypt/letsencrypt.log
Enter email address (used for urgent renewal and security notices) (Enter 'c' to
cancel):[email protected]  #A fake email address will be detected
There seem to be problems with that address. Enter email address (used for
urgent renewal and security notices)  If you really want to skip this, you can
run the client with --register-unsafely-without-email but make sure you then
backup your account key from /etc/letsencrypt/accounts   (Enter 'c' to cancel):[email protected]
Please read the Terms of Service at You must agree
in order to register with the ACME server at
(A)gree/(C)ancel: a
Would you be willing to share your email address with the Electronic Frontier
Foundation, a founding partner of the Let's Encrypt project and the non-profit
organization that develops Certbot? We'd like to send you email about EFF and
our work to encrypt the web, protect its users and defend digital rights.
(Y)es/(N)o: n
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for
Using the webroot path /var/www/html/  for all unmatched domains.
Waiting for verification...
Cleaning up challenges
 - Congratulations! Your certificate and chain have been saved at
    /etc/letsencrypt/live/ Your
   cert will expire on 2017-12-28. 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
 - Your account credentials have been saved in your Certbot
   configuration directory at /etc/letsencrypt. You should
   make a secure backup of this folder now. This configuration
   directory will also contain certificates and private keys obtained
   by Certbot so making regular backups of this folder is ideal.
 - If you like Certbot, please consider supporting our work by:
   Donating to ISRG / Let's Encrypt:
   Donating to EFF:          


Get a SSL Certificate with Certbot

Configure Nginx for TLS (SSL)

An Nginx full default TLS configuration file for a domain should look like in the below file excerpt.

/etc/nginx/sites-enabled/default-ssl file sample:


    server {
                    listen 443 ssl default_server;
                    listen [::]:443 ssl default_server;
                #server_name _;
                root /var/www/html;
                access_log /var/log/nginx/access.log;
                error_log /var/log/nginx/error.log;
               #SSL Certificates
                ssl_certificate "/etc/letsencrypt/live/";
                ssl_certificate_key "/etc/letsencrypt/live/www.";
                ssl_dhparam /etc/nginx/dhparam.pem;
                ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
                #ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
                ssl_session_cache shared:SSL:1m;
               ssl_session_timeout 10m;
                ssl_ciphers HIGH:!aNULL:!MD5;
                ssl_prefer_server_ciphers  on;
                add_header Strict-Transport-Security "max-age=31536000;
    #includeSubDomains" always;
                location / {
        index index.php index.html index.htm;
                    try_files $uri $uri/ /index.php?$args $uri/ =404;
                set $cache_uri $request_uri;
                location ~ /.well-known {
                allow all;
                #             # With php-fpm (or other unix sockets):
                                fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
                #             # With php-cgi (or other tcp sockets):
                #             fastcgi_pass;

               # deny access to .htaccess files, if Apache's document root
                # concurs with nginx's one
                #location ~ /\.ht {
                #             deny all;

The code lines for processing PHP scripts via FastCGI Process Manager can also be found in this excerpt and is represented by the following lines.

location ~ \.php$ {
                                include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;

Install Let’s Encrypt Certificates in Nginx

Let’s Encrypt certificates and keys are stored in /etc/letsencrypt/live/ directory in Debian. The ls command against the above directory will reveal all certificate components, such as the chain file, the fullchain file, the private key and the certificate file.

ls /etc/letsencrypt/live/

To install the Let’s Encrypt certificate in Nginx web server TLS configuration file, open Nginx default-ssl file and update the below lines to reflect Let’s Encrypt certificate file paths for your domain, as shown in the below excerpt.

nano /etc/nginx/sites-enabled/default-ssl

Change the following lines as below:

                ssl_certificate "/etc/letsencrypt/live/ ";
                ssl_certificate_key "/etc/letsencrypt/live/ /privkey.pem";

 Set Lets encrypt certificate paths

Also, if the ssl_dhparam statement is present in Nginx SSL configuration, you must generate a new 2048 bit Diffie–Hellman key by issuing the following command. The Diffie–Hellman key parameters generation should take a while depending on your system randomness or entropy.

openssl dhparam –out /etc/nginx/dhparam.pem 2048

Finally, before activating Nginx TLS configuration by restarting the Nginx daemon to reflect changes, first check Nginx configurations for potential syntax errors. Afterwards, if Nginx configuration file test is successful, restart Nginx daemon to load the new configuration alongside Let’s Encrypt certificates, by issuing the below commands.

nginx -t
service nginx restart

Restart Nginx

In order to verify if nginx service owns an opened socket in listening state on port 443, execute netstat command as shown in the below excerpt.

netstat –tulpn | grep -e 443 -e LISTEN

You should also open a browser and navigate to your domain name via HTTPS protocol. If Let’s Encrypt certificates are successfully applied in Nginx, the SSL handshake should work smoothly without throwing up any errors.

Force web traffic to HTTPS

To force your domain visitors to browse your website only via HTTPS protocol, open Nginx sites-enabled default configuration file and add the following line, which forces all requests that hit port 80 to be redirected with a 301 status code (permanently moved) to port 443.

nano /etc/nginx/sites-enabled/default

Redirect statement should look like presented in the below excerpt.

return         301 https://$server_name$request_uri;


Subsequently, restart Nginx daemon to apply the change, by issuing the below command.

service nginx restart

Final Checks

To further investigate the certificates generated by Let’s Encrypt CA, you can use a modern web browser, such as Chrome. Visit your domain from Chrome browser and press F12 function key to open Developer Tools. Navigate to Security tab and hit on View certificate button in order to open the certificate, as shown in the following screenshots.

Verify SSL certificate

SSL Certificate details shown in chrome browser

Another useful utility in investigating SSL certificates proves to be the openssl command line utility. In order to show extra information for an Let’s Encrypt CA certificate, execute the below command in a Linux console.

openssl s_client –connect

 Check SSL cert with OpenSSL command

Auto Renew Let’s Encrypt Certificate

In order to automatically renew a certificate issued by Let’s Encrypt CA before the expiration date, schedule a crontab job to run once a day at 2:00 AM, by issuing the following command. The output of the executed cron job will be directed to a log file, stored in /var/log/letsencrypt.log

crontab –e

Cron job to renew the certificate.

0 2 * * * certbot renew >> /var/log/letsencrypt.log

That’s all! For other more advanced configurations concerning Let’s Encrypt certificates and utility visit official documentation at the following internet address

Share this page:

9 Comment(s)