首页 > Technology > 正文

How to Set Up Let’s Encrypt SSL on Nginx

fenij 2026-08-04 5 Technology

A site still running on plain HTTP gets a “Not secure” label in every browser, and payment forms on it will scare people off. Let’s Encrypt solves that for free, and on a normal Nginx box the whole job takes about five minutes. Here is the exact sequence I run on Ubuntu and Debian servers.

Check three things first

  • The A record points at your server’s public IP. Verify with dig +short example.com.
  • Ports 80 and 443 are open. With UFW that’s ufw allow 'Nginx Full'.
  • Nginx already serves the domain over HTTP with the correct server_name.

Skip the DNS check and certbot will fail the challenge, which burns a rate-limit slot for nothing. Wait until dig returns the right IP.

Install certbot

apt update
apt install certbot python3-certbot-nginx -y

On Rocky or AlmaLinux it’s dnf install certbot python3-certbot-nginx. The snap build works too, but the distro package is fine for a single-site server.

Issue the certificate

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

Certbot asks for an email address (that’s where expiry warnings go), makes you accept the terms, then rewrites your server block in place — adding listen 443 ssl, the certificate paths, and an HTTP redirect if you say yes. Say yes.

Want to keep your own config untouched? Use webroot mode and wire it up manually:

certbot certonly --webroot -w /var/www/html -d example.com

Files land in /etc/letsencrypt/live/example.com/. Point ssl_certificate at fullchain.pem and ssl_certificate_key at privkey.pem. Never reference cert.pem alone — some clients will complain about a broken chain.

Prove that renewal works

These certificates last 90 days. The apt package drops in a systemd timer that renews around day 60, but check it rather than trusting it:

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

If the dry run ends with “all simulated renewals succeeded”, you can forget about the whole thing. When it fails, the cause is almost always a stale server block or a webroot path that no longer exists after a site migration.

Tighten the TLS settings

Certbot’s defaults are acceptable, not great. In your server block:

ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
add_header Strict-Transport-Security "max-age=31536000" always;
nginx -t && systemctl reload nginx

Add the HSTS header only after every image, script and stylesheet loads over HTTPS. Once a browser caches it, that domain won’t fall back to HTTP for a year. Test the result on ssllabs.com — an A rating is easy with the settings above.

FAQ

Certbot returns “Timeout during connect”. Why?
Port 80 is blocked somewhere between the internet and your server. Check the host firewall, then the cloud provider’s security group, then whether Cloudflare is proxying the record. Set it to DNS-only during issuance or switch to the DNS-01 challenge.

Can I get a wildcard certificate?
Yes, but only through DNS-01: certbot certonly --manual --preferred-challenges dns -d "*.example.com". With a DNS provider plugin installed, renewals stay automatic.

What if I hit the rate limit?
Let’s Encrypt allows 5 duplicate certificates per week for the same set of domains. While testing, always add --dry-run or --staging so failed attempts don’t count against you.

Stuck on a specific distro or control panel? Drop the certbot output in a comment on fenij.com and I’ll take a look.