Paying $100 or more per year for a basic domain-validated SSL certificate has always felt like a tax on doing the web right. Let's Encrypt changed that in 2016 and today there is no legitimate reason to run a public website over plain HTTP. The nonprofit Certificate Authority issues free, browser-trusted 90-day certificates and the tooling around it — primarily Certbot — makes installation and automatic renewal something you can finish in under 15 minutes on most Linux servers. This guide covers the full process: obtaining the certificate, configuring your web server, setting up autorenewal, verifying everything works, and handling the most common errors people hit along the way.
How Let's Encrypt Works
Let's Encrypt uses the ACME protocol (RFC 8555) to automate the entire certificate lifecycle. When you run Certbot, it contacts the Let's Encrypt API, which then issues a challenge to prove you control the domain. There are two main challenge types:
- HTTP-01: Let's Encrypt makes an HTTP request to http://yourdomain.com/.well-known/acme-challenge/TOKEN. Your server must respond with the correct value. This is the default and works for most setups.
- DNS-01: You place a TXT record under _acme-challenge.yourdomain.com. This is required for wildcard certificates and works even when port 80 is blocked.
Once the challenge passes, Let's Encrypt signs your certificate and Certbot writes the key and cert files to /etc/letsencrypt/live/yourdomain.com/. The certificate is valid for 90 days, but Certbot's systemd timer or cron job renews it automatically when fewer than 30 days remain.
Prerequisites Before You Start
- A domain name with DNS A (and AAAA if using IPv6) records pointing to your server's public IP.
- Port 80 open in your firewall — Let's Encrypt must reach it for HTTP-01 challenges even if you plan to redirect everything to HTTPS afterward.
- Root or sudo access on the server.
- A supported OS: Ubuntu 20.04/22.04/24.04, Debian 10/11/12, CentOS/RHEL 8/9, or Rocky/AlmaLinux 8/9 are all well supported.
Installing Certbot
The official and recommended way to install Certbot on any modern Linux distribution is via Snap. This ensures you always get the latest version regardless of your distro's package repository age.
If Snap is not available (some minimal server images skip it), install it first:
Avoid installing Certbot from your distro's native package manager (apt/dnf) unless you are on a very recent release. Older repos ship outdated Certbot versions that can cause renewal failures.
Obtaining Your Certificate
Apache
Certbot's Apache plugin handles everything: it requests the certificate, edits your virtual host configuration to add the SSL directives, and sets up an HTTP-to-HTTPS redirect automatically.
Certbot will ask for an email address (for expiry notices) and ask you to agree to the Terms of Service. When prompted whether to redirect HTTP to HTTPS, choose option 2 (Redirect) unless you have a specific reason not to.
Nginx
The Nginx plugin edits your server blocks in place. Make sure your Nginx config already has a valid server_name directive matching the domains you are requesting, otherwise the plugin cannot locate the right block and will error out.
Standalone Mode (No Web Server Running)
If you are installing a certificate before setting up a web server, or the server is temporarily stopped, use standalone mode. Certbot spins up its own temporary HTTP server on port 80.
Wildcard Certificates via DNS-01
Wildcard certs (*.yourdomain.com) require the DNS-01 challenge. This means you must add a TXT record to your DNS zone each time you request or renew the certificate. Many DNS providers have Certbot plugins for full automation (Cloudflare, Route 53, DigitalOcean, etc.). For a manual one-time request:
Certbot will display the TXT record value you need to add at your DNS host. Add it, wait a minute or two for it to propagate, then press Enter. The wildcard cert covers every subdomain but does not cover the bare domain, which is why you should include both *.yourdomain.com and yourdomain.com in the request.
Where Your Certificate Files Live
After a successful issuance, Certbot creates symlinks under /etc/letsencrypt/live/yourdomain.com/:
- fullchain.pem — Your certificate plus the Let's Encrypt intermediate chain. This is what you point your web server's ssl_certificate (Nginx) or SSLCertificateFile (Apache) directive at.
- privkey.pem — Your private key. Point ssl_certificate_key or SSLCertificateKeyFile here. Never share this file.
- chain.pem — The intermediate certificate only (rarely needed directly).
- cert.pem — Your certificate only (without the chain). Do not use this alone; browsers need the full chain.
Verifying the Certificate is Working
Open your browser and navigate to https://yourdomain.com. Click the padlock and confirm the certificate issuer shows Let's Encrypt and the expiry is roughly 90 days out. For a command-line check:
You should see issuer= /C=US/O=Let's Encrypt/CN=R10 (or R11/E5/E6 depending on the current active intermediate) and a notAfter date 90 days from today.
Use the DNS Lookup tool to confirm your domain resolves correctly from multiple locations — a mismatch between your DNS A record and your server's actual IP is one of the top reasons Let's Encrypt challenges fail.
Setting Up Automatic Renewal
When installed via Snap, Certbot automatically creates a systemd timer that runs twice daily and renews any certificate expiring within 30 days. Confirm it is active:
To test the renewal process without actually renewing (a dry run):
If the dry run completes without errors, you are set. Certbot also reloads your web server after renewal so the new certificate is picked up without any downtime.
If you are on a system without systemd (older setups using cron), add a cron job manually:
Common Errors and How to Fix Them
Error: Connection Refused or Timeout During Challenge
Let's Encrypt could not reach port 80 on your server. Check your firewall:
Also check that your cloud provider's security group or network ACL allows inbound traffic on port 80. AWS Security Groups and GCP firewall rules are separate from the OS firewall and are a common blind spot.
Error: Too Many Certificates Already Issued for This Domain
Let's Encrypt enforces a limit of 5 duplicate certificates per week per registered domain. If you hit this, wait until the rate limit window resets (check https://crt.sh/?q=yourdomain.com to see recent issuances). During testing, always add the --staging flag to use Let's Encrypt's staging environment, which has much higher limits and issues certificates from an untrusted test CA:
Error: Nginx or Apache Plugin Cannot Find Server Block
The plugin searches your config for a server_name value that matches the domain. If your virtual host config is in a non-standard path or missing a server_name line, the plugin fails. Fix: ensure your vhost file under /etc/nginx/sites-enabled/ or /etc/apache2/sites-enabled/ contains the exact domain name you are requesting, then re-run Certbot.
Certificate Renewed but Browser Still Shows Old One
Your web server is still serving the old certificate from cache. Reload it:
Renewal Fails Because Port 80 is Blocked (Production Server)
If your organization blocks port 80 at the network edge, switch to the DNS-01 challenge for renewals. Install the appropriate DNS plugin for your provider (example for Cloudflare):
Security Best Practices After Installation
Getting the certificate installed is only half the job. Make sure your SSL configuration is actually strong:
- Disable TLS 1.0 and 1.1: Both are deprecated. In Nginx, set ssl_protocols TLSv1.2 TLSv1.3;. In Apache, use SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1.
- Use strong cipher suites: The Mozilla SSL Configuration Generator at ssl-config.mozilla.org provides copy-paste-ready configs for Apache, Nginx, and HAProxy at modern, intermediate, and old compatibility levels.
- Enable HSTS: Add Strict-Transport-Security: max-age=31536000; includeSubDomains to your response headers so browsers never attempt plain HTTP for your domain.
- Monitor expiry: Even with autorenewal configured, set up an external monitor. Many free services (UptimeRobot, for example) can alert you if a certificate is about to expire, catching edge cases where renewal silently fails.
Migrating from a Paid Certificate
If you are replacing a commercial certificate, the steps are the same as a fresh install. Certbot writes its own paths into your web server config. After Certbot succeeds, remove or comment out any old SSLCertificateFile / SSLCertificateKeyFile lines pointing to your old certificate and confirm the new Let's Encrypt paths are in place before reloading the web server. Keep the old private key file archived somewhere safe for 30 days in case you need to roll back.
Keeping Things Running Long Term
The 90-day certificate lifetime is intentional — it limits the damage from a compromised key and encourages automation. The renewal timer fires twice a day but only acts when a certificate has fewer than 30 days left, so you have a wide window before anything breaks. Check renewal health monthly with sudo certbot renew --dry-run and review /var/log/letsencrypt/letsencrypt.log if you suspect problems. With Snap-based Certbot and a properly configured web server, the entire process is genuinely hands-off once it is set up correctly.