Blog
3 min read

Certbot and Let's Encrypt: Free HTTPS for Nginx, Step by Step

Get a free HTTPS certificate from Let's Encrypt with Certbot and Nginx: install, issue for several domains, automatic renewal and how to test it, wildcard certificates with DNS challenges, rate limits, shorter certificate lifetimes, and fixing common Certbot errors.

Let's Encrypt issues free, trusted HTTPS certificates. Certbot is the official client that requests them, proves you control the domain, installs them into your web server, and renews them automatically. (How automatic SSL works, What is HTTPS?)

Before you start

  1. DNS points at your server — an A (and AAAA, if you use IPv6) record for each domain. (DNS records explained)
  2. Ports 80 and 443 are open in the server firewall and your provider's firewall. (UFW basics)
  3. Nginx has a server block with the right server_name. (Nginx reverse proxy config)

Install Certbot

The Certbot project recommends installing via snap on most Linux systems:

sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot

(Your distribution's package — sudo apt install certbot python3-certbot-nginx — also works, sometimes with an older version.)

Get a certificate

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

Certbot:

  1. asks Let's Encrypt for a certificate,
  2. proves you control the domains with an HTTP-01 challenge — Let's Encrypt fetches a temporary file from http://example.com/.well-known/acme-challenge/...,
  3. edits your Nginx config to use the certificate and (if you choose) redirect HTTP to HTTPS,
  4. reloads Nginx.

Prefer to edit the config yourself? Use certonly:

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

Certificates land in /etc/letsencrypt/live/example.com/ (fullchain.pem and privkey.pem).

Automatic renewal

Certbot installs a systemd timer (or cron job) that checks twice a day and renews certificates nearing expiry. Test it:

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

If the dry run passes, renewal will work. Renewing reloads Nginx via a deploy hook so the new certificate is picked up.

Certificate lifetimes are shrinking. Let's Encrypt certificates have been valid for 90 days, and the industry is moving to much shorter lifetimes — Let's Encrypt plans to make 45 days the default by 2028. Manual renewal is no longer realistic; automation must work. (Your connection is not private)

Wildcard certificates

A wildcard (*.example.com) covers all subdomains, but requires a DNS-01 challenge: proving control by creating a TXT record. Use a DNS plugin for your provider so it's automatic:

sudo snap install certbot-dns-cloudflare
sudo certbot certonly --dns-cloudflare \
  --dns-cloudflare-credentials ~/.secrets/cloudflare.ini \
  -d example.com -d '*.example.com'

Use a narrowly scoped DNS API token, and keep the credentials file chmod 600. Manual DNS challenges can't renew automatically — avoid them. (What is a DNS server?)

Rate limits

Let's Encrypt limits how many certificates you can issue — for example, per registered domain per week, and duplicate certificates for the same set of names. You'll only hit them by repeatedly requesting while debugging. Use the staging environment when experimenting:

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

Common errors

  • Timeout during connect (likely firewall problem) — port 80 is blocked, or DNS points elsewhere.
  • Invalid response from .../.well-known/acme-challenge/... 404 — Nginx isn't serving the challenge path; a redirect, app route or wrong root is intercepting it.
  • DNS problem: NXDOMAIN — the domain doesn't resolve yet. (DNS_PROBE_FINISHED_NXDOMAIN, DNS propagation)
  • Behind Cloudflare proxy — HTTP-01 usually still works; or use DNS-01, or a Cloudflare Origin Certificate with Full (strict). (Cloudflare 521/522/525)
  • Renewal fails months later — something changed (firewall, config). That's why monitoring certificate expiry is worth it. (Know when your app is down)

Useful commands

sudo certbot certificates            # list certificates and expiry dates
sudo certbot renew                   # renew anything due
sudo certbot delete --cert-name example.com

Simpler alternative

Caddy obtains and renews certificates automatically with no separate tool. (What is Caddy?)


EasySpawn issues and renews HTTPS certificates for every app automatically — no Certbot, no timers, no expiry surprises. See how it works or join the waitlist.

Related: How Automatic SSL Actually Works · Nginx Reverse Proxy Configuration · What Is HSTS? · What Is Caddy?

Keep reading