How to get a free SSL certificate with Let’s Encrypt

Issue a trusted HTTPS certificate in one command with Certbot, redirect HTTP to HTTPS, and make sure it renews by itself.

3–4 minutes
Hands typing on a laptop keyboard

Let’s Encrypt issues free, trusted certificates that browsers accept everywhere. Certbot is the tool that requests them and configures your web server. Certificates last 90 days and renew automatically.

Before you start: your domain must already point to this server, and port 80 must be open. Let’s Encrypt checks both.

1. Install Certbot

On Ubuntu and Debian with Nginx:

sudo apt install certbot python3-certbot-nginx

On AlmaLinux, Rocky Linux and other RHEL-based systems, enable EPEL first:

sudo dnf install epel-release
sudo dnf install certbot python3-certbot-nginx

For Apache, install python3-certbot-apache instead and use --apache below.

2. Request the certificate

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

Certbot asks for an email address for account notices, then proves you control the domain, installs the certificate and updates your Nginx configuration. When it asks, choose to redirect HTTP to HTTPS.

3. Check renewal

Certbot installs a timer that renews certificates before they expire. Confirm it works:

sudo certbot renew --dry-run
systemctl list-timers | grep certbot

4. Check the result

Visit https://example.com. Then check the details:

curl -sI https://example.com | head -1
sudo certbot certificates

What Certbot changed

With --nginx, Certbot edits your server block. Afterwards it contains lines like these, marked # managed by Certbot:

listen 443 ssl;
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;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

It also adds a second server block that redirects HTTP to HTTPS. You can edit around these lines freely; leave the paths as they are, because renewals update the files they point to.

Renewal, in more detail

Certificates last 90 days, and Certbot renews any that have less than 30 days left. The timer runs twice a day, so a renewal that fails once is retried long before expiry.

For Nginx and Apache installs, Certbot reloads the web server after renewing. If you use the certificate elsewhere, such as a mail server, add a deploy hook so it reloads too:

sudo certbot renew --deploy-hook "systemctl reload postfix dovecot"

Let’s Encrypt no longer emails expiry reminders, so monitor certificates yourself. An uptime monitor that checks certificate expiry, or a weekly look at sudo certbot certificates, catches a renewal that has been quietly failing.

Other ways to prove control

MethodCommandUse when
Nginx or Apache plugin--nginx or --apacheThe normal case
Webrootcertonly --webroot -w /var/www/example.com/public -d example.comAnother web server, or you do not want Certbot editing the configuration
Standalonecertonly --standalone -d example.comNo web server running yet; Certbot briefly runs its own on port 80
DNS challengecertonly --manual --preferred-challenges dns -d example.comPort 80 cannot be opened, behind a CDN, or for wildcard certificates

The DNS challenge asks you to add a TXT record named _acme-challenge. Done by hand, it cannot renew automatically. For automatic DNS renewals, use the Certbot plugin for your DNS provider, such as python3-certbot-dns-cloudflare.

Wildcard certificates

A wildcard certificate covers every subdomain, such as *.example.com. It needs the DNS challenge:

sudo certbot certonly --dns-cloudflare --dns-cloudflare-credentials ~/.secrets/cloudflare.ini -d example.com -d "*.example.com"

A wildcard covers one level only: a.example.com, but not a.b.example.com or example.com itself, which is why the bare domain is listed separately.

When it fails

Error mentionsUsual cause
DNS problem: NXDOMAINThe domain does not exist in DNS, or has a typo
Timeout during connectPort 80 is blocked by a firewall
Invalid response / 404The domain points to a different server
too many certificates already issuedRate limit hit; wait or use --dry-run while testing

Let’s Encrypt limits how many certificates you can request: 50 per registered domain each week, and 5 identical certificates each week. While testing, add --dry-run or --staging, which use a test system without those limits.

Behind a proxy or CDN, or when port 80 cannot be opened, use a DNS challenge instead, which proves ownership with a TXT record.

Something out of date? Software changes. If a step no longer works, tell us and we will check it and update the page.