Updated on 24.5.2023

How to install Let’s Encrypt on Nginx

Improving your website security through encryption, even on the most basic servers, can increase your visitors’ trust in your site and your ability to run it. Setting up encryption on your web host has generally been complicated and expensive, which often deters administrators whose web applications might not depend on user input. Let’s Encrypt aims to change this by making implementing encryption on any website easier. They are an open and free project that allows obtaining and installing certificates through simple, automated, commands.

Let's Encrypt Project Logo

Let’s Encrypt is a new Certificate Authority capable of issuing certificates cross-signed by IdentTrust, which allows their end certificates to be accepted by all major browsers.  This guide outlines the steps for installing their Certbot client and how to use it to manage certificates on your CentOS 7 server running nginx.

Installing Let’s Encrypt client

Let’s Encrypt greatly simplifies server management by automating obtaining certificates and configuring web services to use them. The client is fully-featured and extensible for the Let’s Encrypt Certificate Authority or any other CA that supports the ACME protocol.

On CentOS, the client is available in the Extra Packages for Enterprise Linux (EPEL) which you will need to first install and update.

sudo yum install epel-release
sudo yum update

You will also need to have nginx installed and running. Of course, if you are adding certificates onto a previously configured web host this would already be installed.

sudo yum install nginx
sudo systemctl start nginx

Then install the certbot client itself with the following command.

sudo yum install certbot python2-certbot-nginx

Once installed, you can use the next command to see test the client is working correctly.

certbot --help

Given that the help command works, the client is good to go. Next, check that your firewall is configured correctly with the instructions below.

Allow HTTP/S at firewall

CentOS 7 has enabled by default relatively strict firewall rules which do not allow HTTP or HTTPS connections to the host. The Let’s Encrypt client requires access to authenticate the domain name and will fail with the default rules.

If you are installing the certificates on a previously configured web host, the required rules are probably already set. Confirm the firewall rules with the --list-services command and continue in the next section with obtaining the certificates.

Enable connections for HTTP and HTTPS services using the following command.

sudo firewall-cmd --permanent --add-service=http --add-service=https

Then reload the firewall rules to apply the changes.

sudo firewall-cmd --reload

You can check that the rules were added successfully with the command below.

sudo firewall-cmd --list-services
dhcpv6-client http ssh https

You should see at least the four services enabled as shown above. With the firewall configured, you can continue obtaining and installing certificates.

Obtaining a certificate

Let’s Encrypt validates the domain it is installed on similarly to a traditional CA process by identifying the server administrator via a public key. The client generates a new key pair when interacting with the Let’s Encrypt servers for the first time, and then aims to prove to the CA that the host has control over a particular domain by at least one of the two following ways:

  • Provisioning a DNS record under the domain in question
  • Provisioning an HTTP resource under a well-known URI on the domain

On top of one of the two challenges, the client also must sign a nonce with its private key to prove it controls that key pair.

To help the Let’s Encrypt client accomplish these tasks it supports a number of plugins that can be used to obtain and install certificates. Let’s Encrypt supports automated installation on nginx, the certificates can be easily obtained using the --nginx plugin together with other commands.

The --nginx plugin automates obtaining certificates from the CA when using Nginx web server software. To use this plugin on the command line use the example below. Replace the example domain in red with your own.

sudo certbot --nginx -d example.upcloud.com

The command starts an interactive configuration script that asks a couple of questions to help with managing certificates.

  1. On the first installation on any specific host, you’ll need to enter a contact email.
  2. Then go through the Let’s Encrypt Terms of Service and select Agree if you accept the terms and wish to use the service.
  3. Choose whether you wish to share your email address with the Electronic Frontier Foundation (EFF) for updates on their work.
  4. Lastly, enable redirection to HTTPS if you wish to fully secure your domain.

If the client was successful at obtaining a certificate you can find a confirmation and certificate expiration date at the end of the client output.

In case you are having problems with the client, make sure you are trying to register a domain or subdomain that currently resolves to your server. Check that you have the administrative privileges to run the commands and that your domain is pointing to the correct IP address.

Renewing a certificate

At the end of the certificate obtaining script, the output shows the certificate’s expiration date which is usually 3 months from the day it was issued. Renewing a certificate is just as easy as obtaining one.

The client will only renew certificates close to their expiry date, but you can test that the renewal works using the --dry-run parameter to simulate the process.

sudo certbot renew --dry-run

To actually renew certificates, simply leave out the simulation parameter.

sudo certbot renew

Once the renewal is complete, reload your web service to update the configuration to include the new certificates using the following command.

sudo nginx -s reload

Your certificate is now again valid for another 3 months.

Considering the duration of the certificates, you might wish to automate the renewal with a short script like the example below and make it executable.

sudo vi /etc/cron.daily/letsencrypt-renew
#!/bin/sh
if certbot renew > /var/log/letsencrypt/renew.log 2>&1 ; then
   nginx -s reload
fi
exit
sudo chmod +x /etc/cron.daily/letsencrypt-renew

The example script runs the renewal while directing the output to a log file and then reloads nginx if the process was successful to complete the renewal.

You can then automate the script using Crontab. Open the root user crontab for edit with the command underneath.

sudo crontab -e

Include a line similar to the example below in the crontab file, then save and exit.

01 02,14 * * * /etc/cron.daily/letsencrypt-renew

Let’s Encrypt recommends setting the automated renewal script to run twice a day on a random minute within the hour. The above example runs on 02:01 and 14:01 but you can select any time slot you wish.

Revoking a certificate

If you wish to remove a certificate from your server it can be revoked using the subcommand with the client. The command below can be used to revoke a particular certificate. Replace the domain_name with the domain which certificate you wish to revoke.

sudo certbot revoke --cert-path /etc/letsencrypt/live/domain_name/cert.pem

The process does not give a confirmation upon completion, but if you perform it again you will get a message that the certificate has already been revoked.

Enhancing security

Once you have the certificate and chain saved on the server, you can check the Nginx configuration to further tune the HTTPS connection using the new certificates.

Only use secure protocols

As technologies develop, old versions are disused and the same applies to security protocols. The old insecure SSLv2 and SSLv3 should be disabled and never used on modern web servers. This is due to the inherent insecurities in these protocols which is why they have been replaced by the TLS protocols. The example below enables the two most secure TLS versions 1.1 and 1.2.

ssl_protocols TLSv1.1 TLSv1.2;

Note that, TLS v1.0 is also already a legacy protocol and should be avoided. However, it might still be needed to allow older web browsers to work. Enable it only if absolutely necessary.

Enable HTTP Strict Transport Security (HSTS)

The Strict Transport Security safeguards TLS by not allowing any insecure communication with the websites that use it. It was designed to ensure security even in the case of configuration problems and implementation errors. HSTS automatically converting all plaintext links to a secure version. It also disables click-through certificate warnings which are an indicator of an active MITM attack and prevents users from circumventing the warning.

Enable HSTS by using the option shown below.

add_header Strict-Transport-Security "max-age=31536000; includeSubdomains";

Enhance cypher suites

The cypher suites enable security between your web server and visitors clients by defining how secure communication takes place. The example configuration below is designed for both RSA and ECDSA keys and works as a great starting point for improved security.

ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256;

By using SSL protocols of SSLv3 or newer, the client tells the web server which cypher suites it supports and the servers chooses one option from that list. The important part of this functionality is that the cyphers on the server are listed in the prefered order from the strongest to the weakest and the cypher order is honoured. This feature can be enforced by adding the following line in your configuration file.

ssl_prefer_server_ciphers on;

Diffie-Hellman Ephemeral algorithm

The Diffie-Hellman algorithm is a way of generating a shared secret between two parties in such a way that the secret cannot be seen by observing the communication. It is a useful technique to create an encryption key between a server and a client, that then uses the shared key to encrypt their traffic. Ephemeral Diffie-Hellman (DHE) differs from the static Diffie-Hellman by generating a temporary key for every connection and never using the same key twice. This enables Forward Secrecy which means that even if the server’s long-term private key gets leaked, previous communication remains secure.

Generate a strong DHE parameter using the command below.

sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

The process takes but a moment with a 2048-bit key length. You can also use a 4096-bit length for higher security but generating a longer parameter will be considerably slower.

ssl_dhparam /etc/ssl/certs/dhparam.pem;

Afterwards, the output can be used in the Nginx configuration using the above example.

Redirect unencrypted connections

Optionally you can add a redirection from your HTTP connections to the encrypted HTTPS. By creating the HTTP server segment as shown in the example below, you can tell your web server to listen for regular HTTP traffic and upgrade these connections to a secure one. Again replace the domain_name with your web server’s domain. The rest of that segment can remain as is.

server {
   listen 80;
   server_name domain_name;
   return 301 https://$server_name$request_uri;
}

This will redirect all connections to the encryption-enabled https:// part of your site even with links pointing to the http://domain_name address.

Adding it all to the configuration

With CentOS or other Red Hat variants, the Certbot save the Nginx configuration file to /etc/letsencrypt/options-ssl-nginx.conf but editing it directly will prevent Certbot from updating the file later on. Instead, create a new configuration file with the command below.

sudo vi /etc/nginx/conf.d/domain_name.conf

This example configuration sets up a single site listening for HTTPS connections with the added security features as explained above. Replace domain_name in the example underneath with your own domain.

# HTTPS server
server {
   listen 443 ssl;
   server_name domain_name;
   ssl_certificate /etc/letsencrypt/live/domain_name/fullchain.pem;
   ssl_certificate_key /etc/letsencrypt/live/domain_name/privkey.pem;
   ssl_session_cache shared:SSL:10m;
   ssl_session_timeout 5m;
   ssl_protocols TLSv1.1 TLSv1.2;
   ssl_prefer_server_ciphers on;
   ssl_dhparam /etc/ssl/certs/dhparam.pem;
   ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256;
   add_header Strict-Transport-Security "max-age=31536000; includeSubdomains";
   location / {
      root /usr/share/nginx/html;
      index index.html index.htm;
   }
}

# HTTP redirect
server {
   listen 80;
   server_name domain_name;
   return 301 https://$server_name$request_uri;
}

Then save the file and exit the editor.

To have the changes take effect, you will need to restart nginx.

sudo systemctl restart nginx

Now open your domain in a web browser using https://domain_name, when it loads you will know the installation is working properly.

You can evaluate the server encryption performance with Qualys SSL Labs test site. Enter your domain name into the text field and click the Submit button. The test will take a moment, but when completed it provides some useful information on different areas of your server encryption security as well as an overall rating.

Qualys SSL Labs nginx test

Note that Let’s Encrypt is still in development and might include certain rate limits for issuing certificates to protect the service against both accidental and intentional abuse. You can check further details at the Let’s Encrypt documentation.

Other plugins

In most cases simply installing and renewing your certificates as instructed above are enough, but the Let’s Encrypt client also supports some additional plugins for managing your certificates. For example, if you do not have a web service configured yet while obtaining a new certificate you can use the --standalone plugin with certonly subcommand.

This guide focuses on installing the certificate on nginx using the --nginx plugin, though Let’s Encrypt also works just as well with other web servers software. Let’s Encrypt also has built-in support to issue and install certificates automatically for servers running Apache. Check out our guide for How to install Let’s Encrypt on Apache2 to learn more. You can also find out about other supported options in the documentation for Let’s Encrypt.

Janne Ruostemaa

Editor-in-Chief

  1. https://letsencrypt.org/docs/faq/

    Letsencrypt recommend automatically renewing your certificates every 60 days. (not twice every day)

  2. Janne Ruostemaa

    Hi Jen, thanks for the comment. You are right in that the certificate should be renewed every 60 days. However, the approach of having the renew attempted every day is a feature of the Certbot client. The renew command only attempts to complete the process once the certificate is going to expire in 30 days or less. Since the client only attempts to renew certificates that are near expiry it can be run as frequently as you want – since it will usually take no action. You can read more about automating renewal at Certbot documentation https://certbot.eff.org/docs/using.html#renewal

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top