Skip to content

Cookie settings

Choose which kinds of cookies you allow. You can change your choice at any time via Cookie settings at the bottom of every page. Privacy statement

Necessary

Always on

Needed to log in, keep your cart and remember your choices. These are always on.

Which cookies?
  • weboke_sessie, weboke_klant, weboke_remember: your session and staying logged in
  • weboke_basket: your cart
  • wkBtwIncl: showing prices with or without VAT
  • wok_cookies: your cookie choice, 12 months

Measures which ad leads to a visit or order, so we do not pay for ads that do nothing.

Which cookies?
  • Google Ads via Google Tag Manager (_gcl_au, _gcl_aw), up to 90 days
  • OpenAI Ads, ads in ChatGPT
  • wok_aff: which partner referred you to us (affiliate programme), 60 days

4.6

Country and language

Each country has its own site, with prices and VAT for that country.

View

Module 7 · 7.3

https with Let's Encrypt

Module 7: Domain, web server and https · Reading time: 12 minutes

Learning objective: After this lesson you can use certbot to request a free certificate from Let's Encrypt for nginx, redirect http to https, check automatic renewal and fix the most common errors in a request.

Key concepts: certificate, certificate authority (CA), ACME, Let's Encrypt, domain validation, HTTP-01, DNS-01, TLS-ALPN-01, certbot, renewal, certbot renew --dry-run, lifetime, ARI, rate limits, staging, CAA, redirecting to https

Why https, and what a certificate proves

Without https, everything between browser and server travels across the network unencrypted: passwords, forms, cookies. Anyone along the way (a public wifi network, a hacked router) can read along or change something. That is why browsers mark http sites as "not secure", and some features only work over https. For a vault such as Vaultwarden (lesson 9.4), https is even required.

https uses TLS, and for that your server needs a certificate: proof, signed by a certificate authority (CA) that browsers trust, that this key belongs to this name. An ordinary certificate only proves that the applicant controls the domain name (domain validation). It says nothing about who you are or whether you can be trusted.

Let's Encrypt is a free CA that only issues domain-validated certificates, fully automatically via the ACME protocol. A program on your server (the ACME client) requests the certificate, proves that it controls the name, installs it and renews it in time. This lesson uses certbot, the client from the EFF. Caddy (lesson 7.4) has an ACME client built in.

How do you prove that you control the name?

Let's Encrypt has three kinds of challenges:

ChallengeHowPortWildcard (*.example.com)
HTTP-01place a file under http://<naam>/.well-known/acme-challenge/80no
DNS-01set a TXT record _acme-challenge.<naam>noneyes
TLS-ALPN-01present a special certificate during the TLS handshake443no

For an ordinary VPS with a website, HTTP-01 is the simplest. For it to work:

  • the name must point to your server with A (and AAAA) records (lesson 7.1);
  • port 80 must be open to the whole world, even if your site otherwise only uses https. Let's Encrypt validates only via port 80 and from several places on the internet; you cannot add those addresses to your firewall;
  • your server must give the same answer over IPv4 and IPv6. If the name has an AAAA record, Let's Encrypt tries IPv6 first. Only if IPv6 gives no connection at all does it fall back to IPv4.

You need DNS-01 for a wildcard certificate, or if the server cannot be reached from outside. The ACME client then has to be able to change your DNS, usually via an API key from your DNS provider. That key can change your entire DNS: keep it as carefully as a password.

Installing certbot

The makers of certbot recommend the snap, because it always has the latest version. On Debian and Ubuntu you can also simply install it from the package repository:

anna@web1:~$ sudo apt install certbot python3-certbot-nginx

The version from the distribution is older but receives security updates via apt (lessons 4.1 and 4.2), and that fits the rest of this course. Choose one of the two, not both: two installations get in each other's way when renewing.

Requesting a certificate

With the site from lesson 7.2 already working on port 80:

anna@web1:~$ sudo certbot --nginx -d example.com -d www.example.com
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Enter email address or hit Enter to skip.
 (Enter 'c' to cancel):
...
Requesting a certificate for example.com and www.example.com

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/example.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/example.com/privkey.pem
This certificate expires on 2027-02-07.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.

Deploying certificate
Successfully deployed certificate for example.com to /etc/nginx/sites-enabled/example.com
Successfully deployed certificate for www.example.com to /etc/nginx/sites-enabled/example.com
Congratulations! You have successfully enabled HTTPS on https://example.com and https://www.example.com

(The date and details are an example.) The --nginx plugin does three things: it temporarily sets up the challenge, fetches the certificate, and adjusts your server block with a listen 443 ssl block and a redirect from http to https. If you would rather do that yourself, use certbot certonly --nginx and add the lines to your configuration yourself.

A few things to watch out for:

  • Request all names that belong to the site in one go (-d per name). Every name must point to the server, otherwise the whole request fails.
  • The private key (privkey.pem) is stored in /etc/letsencrypt/live/ and is readable only by root. Do not copy it to other places and never put it in a backup that others can read.
  • The email address is optional. Since June 2025, Let's Encrypt no longer sends emails when a certificate is about to expire. So you have to monitor yourself that renewal succeeds (lesson 8.3).

Redirecting http to https

After certbot, your configuration looks roughly like this (tidied up; certbot adds its own comments # managed by Certbot and sometimes if lines):

server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name example.com www.example.com;
    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    root /var/www/example.com;
    ...
}

The first block redirects everything over http to the same name and the same path over https, with a permanent redirect (301). The challenge file for renewal still works: Let's Encrypt follows that redirect. The second block is the real site. If you also want to send www to the bare name (or the other way round), do that in a separate block, so visitors see one fixed name.

Renewal: automatic, and checked

A certificate from Let's Encrypt is currently valid for 90 days. That is getting shorter: Let's Encrypt has announced that its default profile will issue 64-day certificates from 10 February 2027 and 45-day certificates from 16 February 2028. Renewing by hand is therefore not an option; it has to be automatic.

During installation, certbot sets up a systemd timer (or a cron entry) that checks twice a day whether a certificate needs renewing. Check that it is there, and test renewal with a trial request:

anna@web1:~$ systemctl list-timers 'certbot*'
NEXT                        LEFT    LAST PASSED UNIT          ACTIVATES
Mon 2026-11-09 22:41:00 CET 9h left -    -      certbot.timer certbot.service
anna@web1:~$ sudo certbot renew --dry-run
...
Congratulations, all simulated renewals succeeded:
  /etc/letsencrypt/live/example.com/fullchain.pem (success)

After renewal, nginx also has to load the new certificate. With the nginx plugin, certbot handles that itself; if you use certonly, set up a deploy hook that reloads nginx, for example an executable script in /etc/letsencrypt/renewal-hooks/deploy/ containing systemctl reload nginx.

Good ACME clients use ARI (ACME Renewal Information): Let's Encrypt then tells the client itself when a certificate should be renewed, for example earlier if something is wrong with a batch of certificates. So keep your client up to date.

If a request fails

Message (shortened)CauseSolution
Timeout during connect (likely firewall problem)port 80 closed, or the name points to a different addressfirewall (lesson 5.2), A/AAAA (lesson 7.1)
Invalid response from http://.../.well-known/acme-challenge/...: 404a different server or server block answers, often via IPv6listen [::]:80, check the AAAA record
CAA record for example.com prevents issuancea CAA record only allows a different authorityadjust CAA (lesson 7.1)
too many certificates already issueda rate limitwait; test with staging

Let's Encrypt has rate limits to prevent abuse. The most important ones: at most 50 new certificates per registered domain per 7 days, at most 5 certificates for exactly the same set of names per 7 days, and at most 5 failed validations per name per hour. If you are experimenting and keep requesting again and again, you will soon run into them. So test with the staging environment, which has much more generous limits but issues certificates that browsers do not trust:

anna@web1:~$ sudo certbot certonly --nginx --staging -d test.example.com

Once it works there, request the real certificate.

On AlmaLinux and Rocky Linux

There, certbot comes from EPEL (dnf install certbot python3-certbot-nginx) or as a snap. The plugin and the commands are the same. Remember firewalld (--add-service=http --add-service=https) and SELinux if certificates are stored in an unusual location.

In practice

With a hosting package, the control panel takes care of the certificate for you (at WebOké and at other hosting companies with DirectAdmin, cPanel or Plesk). On a VPS you do it yourself, with certbot, Caddy or the ACME client that comes with your software. That applies with every provider.

Summary

  • A certificate from Let's Encrypt proves that you control the name; certbot requests, installs and renews it via ACME.
  • HTTP-01 needs port 80 open, to everyone, and the same answer over IPv4 and IPv6; DNS-01 is for wildcards.
  • certbot --nginx -d ... -d ... takes care of the certificate and the redirect to https; request all names of a site in one go.
  • Certificates are now valid for 90 days and are getting shorter; check the timer and certbot renew --dry-run, and monitor the expiry date yourself.
  • Test with --staging to avoid rate limits; watch out for CAA.

Quiz

1. Your site should only be reachable over https. Can you close port 80 in the firewall if you use HTTP-01?



2. You want a certificate for *.example.com. Which challenge do you need?



3. The request fails with a 404 on the challenge file, while curl http://example.com/ shows your site over IPv4. What is the most likely cause?



4. Why is automatic renewal more important than ever?



5. You are experimenting and have already requested the same certificate four times today. What do you do for the next attempt?



Exercise

Exercise Z7.3: https with a valid certificate. Request a certificate for your site (with certbot or Caddy), redirect http to https and test renewal with certbot renew --dry-run (with Caddy: check in the logs that the certificate was fetched). Enter the name of your site. The program makes a TLS connection to port 443 and checks whether the certificate is valid, is signed by a trusted authority and covers your name, and then requests http://<naam>/ to see whether you redirect to https. You also fill in when your certificate expires and how renewal is set up on your server.

Exercise Z7.3: https with a valid certificate

Only for registered students. We open https://<naam>/ and http://<naam>/ like a browser would, from our web server.




What you enter and what we find isn't stored. Your browser remembers your answers and whether you've passed the exercise. If you're signed in, we only save that you got the exercise (almost) right in My courses; you can delete that there too.

Further reading

One moment…

Set up your domains

For each domain, arrange the nameservers, the link to your hosting and who becomes the owner.

Loading your domains…