← All posts

Getting a Free SSL/TLS Certificate from Let's Encrypt and Configuring Nginx

Today I’ll explain how to get a free SSL/TLS certificate from Let’s Encrypt for your sites running on Nginx using the ACME client certbot (a program for obtaining and renewing certificates from Let’s Encrypt).

The Let’s Encrypt project was created so that most websites could switch to encrypted connections (HTTPS). Unlike commercial certificate authorities, this project does not require payment… continue reading on Wikipedia

Installing Dependencies

Let’s install certbot and the Nginx plugin so it can configure the necessary hosts in Nginx itself:

apt install certbot python3-certbot-nginx

Getting a Certificate for a Single Domain

Run certbot and pass it the information needed to generate the certificate:

certbot --nginx -n --agree-tos -m <Ваш Email> -d <Ваше Доменное Имя>

where:

  • --nginx - Makes the Nginx plugin reconfigure hosts in the Nginx configuration files (specifies the paths to the certificates; if there are no SSL sections, it will create them for the specified domain)
  • -n - Non-interactive mode, most often used in deployment scripts
  • --agree-tos - Agreement to the ACME server’s Subscriber Agreement (ToS - Terms of Service)
  • -m - Your email address
  • -d - Your domain name

Example:

certbot --nginx -n --agree-tos -m example@example.org -d example.com
certbot --nginx -n --agree-tos -m example@example.org -d or.sub.domain.example.com

Verifying Domain Ownership

Now you need to verify ownership of the specified domain name. To do this, you can create a location in the Nginx configuration:

server { server_name <Ваше Доменное Имя>; location ~* ^/\.well-known/acme-challenge/<AUTH TOKEN BY CERTBOT>/$ { return 200; } }

Or create a TXT record for the domain, which is more convenient:

_acme-challenge.<Ваше Доменное Имя>.  IN TXT "<AUTH TOKEN BY CERTBOT>"

Example:

_acme-challenge.example.org.   IN TXT "4sV67H271Eil3VHA-9TuXjANP6cP_uXmyJoTInalPaY"

You can find some details on ServerFault

Getting a Wildcard Certificate

If you have many subdomains, it’s easier to get a wildcard certificate (covering all subdomains). Let’s Encrypt introduced this option in spring 2018.

certbot certonly --preferred-challenges=dns --agree-tos -m <Ваш Email> -d *.<Ваше Доменное Имя> -d <Ваше Доменное Имя> --manual --server https://acme-v02.api.letsencrypt.org/directory

where:

  • certonly - Obtain only the certificate (without installing/applying it)
  • --preferred-challenges - It is more convenient to verify domain ownership through DNS
  • --agree-tos - Agreement to the ACME server’s Subscriber Agreement (ToS - Terms of Service)
  • -m - Your email address
  • -d - Your domain name with the prefix “*.”
  • -d - Immediately afterward, specify the canonical domain name if you use it
  • --manual - Obtain the certificate manually (without the help of the nginx plugin)
  • --server - For a wildcard certificate, you need to specify an endpoint (you can see the available ones here)

Example:

certbot certonly --preferred-challenges=dns --agree-tos -m example@example.org -d *.example.org -d example.org --manual --server https://acme-v02.api.letsencrypt.org/directory

While running this command, add two TXT records to your domain when prompted, for example:

_acme-challenge.example.org. 60  IN TXT "4RMgK51t1OMNHPJVmOsIPIIkBnad5oUxk_WK6FTmo1w"
_acme-challenge.example.org. 60  IN TXT "M5QE7dXdS0RDEZ2uAno-PEfkc_6x5HftXtNJpEd87mI"

After adding the keys specified by certbot, use it to verify that they are correct. If everything is correct, it will save your certificates in its directory.

Viewing the List of Obtained Certificates

After entering the command:

certbot certificates

you can view the list of obtained certificates and their expiration dates

Checking a Domain’s Certificates

openssl s_client -connect example.org:443 -servername example.org

If you get the following response:

no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 5 bytes and written 0 bytes
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : 0000
    Session-ID:
    Session-ID-ctx:
    Master-Key:
    Start Time: 1630349404
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)

Then adding ssl to the listen directive may help:

server {
    listen              443 ssl;
    server_name         example.org;
    ssl_certificate     fullchain.pem;
    ssl_certificate_key privkey.pem;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers         HIGH:!aNULL:!MD5;
    ...
}

Comments are closed. Read the original discussion in Russian →