Securing your site with HTTPS used to be a paid hassle. Now? It's free, automated, and (mostly) painless once you know the moving parts. This guide walks you through how to install a Let's Encrypt SSL certificate on a Linux server, whether you're running Nginx or Apache, and shows you how to keep it renewing on autopilot so it never expires on you at 2 a.m.

I'll keep things practical. Real commands, real file paths, and the troubleshooting steps I actually use when something breaks during validation.

Dark editorial illustration of Certbot terminal commands connecting to a secure HTTPS browser bar with padlock.
Dark editorial illustration of Certbot terminal commands connecting to a secure HTTPS browser bar with padlock.

Quick Answer: Installing a Let's Encrypt SSL Certificate

To install a Let's Encrypt SSL certificate, point your domain to your server, install Certbot, and run Certbot with your web server plugin either certbot --nginx or certbot --apache. Then enable HTTPS redirection, test the certificate in a browser, and confirm automatic renewal works with certbot renew --dry-run.

  1. Point your domain's A record to the server IP.
  2. Open ports 80 and 443 in the firewall.
  3. Install Certbot and the matching plugin (python3-certbot-nginx or python3-certbot-apache).
  4. Run Certbot, choose redirect, and let it edit your config.
  5. Verify with a browser and certbot renew --dry-run.

What a Let's Encrypt SSL Certificate Does for HTTPS Security

Let's Encrypt is a free, automated certificate authority. It issues domain-validated TLS certificates that browsers trust the same way they trust any paid certificate. The catch? Each cert is valid for only 90 days. That's intentional β€” short lifetimes force automation, and automation prevents the "oh god, the cert expired again" Slack message.

When a visitor hits your HTTPS site, the certificate proves your server actually controls the domain, and traffic between browser and server gets encrypted. No more "Not Secure" warnings. No more browser shaming.

Dark network diagram of browser to origin server over encrypted TLS port 443 with Let's Encrypt badge.
Dark network diagram of browser to origin server over encrypted TLS port 443 with Let's Encrypt badge.

How Let's Encrypt Differs from Paid SSL Certificates

For most websites, the practical difference is zero. Browsers treat them identically. The real distinctions:

  • Cost: Let's Encrypt is free. Paid certs run anywhere from $10 to several hundred per year.
  • Validation type: Let's Encrypt only does Domain Validation (DV). If you need Organization (OV) or Extended Validation (EV), you'll need a paid CA.
  • Lifetime: 90 days vs. 1+ year for paid certs.
  • Automation: Built around the ACME protocol. Issuance and renewal are designed to be hands-off.

If you want a deeper foundation, our explainer on what is ssl covers the basics without the marketing fluff.

How Certbot Automates Certificate Issuance and Renewal

Certbot is the official ACME client maintained by the EFF. It talks to Let's Encrypt's servers, proves you own the domain, downloads the certificate, and (if you let it) edits your Nginx or Apache config to use it. It also installs a systemd timer or cron job that renews everything automatically. That last bit is the part most tutorials gloss over β€” and it's the part that matters most long-term.

Prerequisites to Install Let's Encrypt on a Linux Server

Skip these checks and you'll spend an hour fighting Certbot for no reason. I've watched it happen too many times. Run through this list before you touch a single command.

Requirement How to Check Why It Matters
Domain points to server IP dig +short example.com Validation fails if DNS doesn't match
Port 80 open sudo ufw status or ss -tlnp HTTP-01 challenge uses port 80
Port 443 open Same as above HTTPS traffic flows here once installed
Web server installed and serving the domain Visit http://example.com Certbot needs a working vhost/server block
sudo or root access sudo -v Certbot writes to /etc/letsencrypt and reloads services
Email address Anything you check Used for expiry notices and account recovery
No CDN proxying during install Cloudflare orange cloud β†’ grey, temporarily Proxy can intercept the ACME challenge

Check That Your Domain Points to the Correct Server IP

Open a terminal and run:

dig +short example.com

dig +short www.example.com

Both should return your server's public IP. If they don't, fix DNS first and wait for propagation. Trying to issue a certificate before DNS resolves is the #1 reason people get stuck.

One more thing β€” if you've got an AAAA record for IPv6, make sure your server is actually serving traffic on that address too. A broken AAAA record is a surprisingly common silent killer. Either fix it or remove it before requesting the cert.

Open Ports 80 and 443 Before Running Certbot

The HTTP-01 challenge needs to reach your server on port 80. Even if your site already runs on HTTPS-only via another method, you still need 80 open for validation.

sudo ufw allow 80/tcp

sudo ufw allow 443/tcp

sudo ufw reload

If you're on a cloud provider, check the security group or network firewall too. The OS firewall isn't the only one in play.

Confirm Whether Your Site Uses Nginx or Apache

Quick check:

sudo systemctl status nginx

sudo systemctl status apache2

Whichever one is active determines which Certbot plugin you need. If neither is running, install one before continuing.

Warning: Don't request a certificate until DNS fully points to your server. Failed attempts count toward Let's Encrypt's rate limits, and you can get locked out for hours.

How to Install Certbot on Ubuntu and Debian

Ubuntu and Debian both ship Certbot in their default repos. That's the path I recommend β€” it's clean, integrates with apt, and gets security updates with the rest of your system.

Stylised Ubuntu terminal illustration showing apt update and Certbot install commands for Nginx and Apache.
Stylised Ubuntu terminal illustration showing apt update and Certbot install commands for Nginx and Apache.

Update Package Indexes Before Installing Certbot

sudo apt update

sudo apt upgrade -y

Always update first. Stale package lists lead to mismatched dependencies, and you don't want that during an SSL install.

Install Certbot for Nginx

sudo apt install certbot python3-certbot-nginx -y

That installs Certbot itself plus the Nginx plugin, which is what lets Certbot read and rewrite your Nginx config automatically.

Install Certbot for Apache

sudo apt install certbot python3-certbot-apache -y

Same idea, different plugin. Don't install both unless you're actually running both web servers β€” you'll just confuse yourself later.

Verify That Certbot Is Installed Correctly

certbot --version

You should see something like certbot 2.x.x. If you get "command not found," your PATH is off or the install didn't complete re-run apt install and watch for errors.

Install Let's Encrypt SSL on Nginx with Certbot

This is where it gets satisfying. One command, a couple of prompts, and your site is live on HTTPS.

Run Certbot for Your Nginx Server Block

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

Replace example.com with your actual domain. The -d flag stacks β€” list every hostname you want covered. Always include both the apex (example.com) and the www variant unless you have a strong reason not to.

Certbot will:

  1. Ask for your email (used for expiry warnings).
  2. Make you accept the Let's Encrypt Terms of Service.
  3. Detect your Nginx server blocks and ask which one to secure.
  4. Run the HTTP-01 challenge.
  5. Ask whether to redirect HTTP to HTTPS β€” pick option 2 (redirect) unless you have a specific reason not to.
Stylised dark terminal illustration of Certbot Nginx prompts with option 2 Redirect selected.
Stylised dark terminal illustration of Certbot Nginx prompts with option 2 Redirect selected.

Choose the HTTPS Redirect Option Safely

When Certbot offers to redirect, it modifies your server block to issue a 301 from HTTP to HTTPS. This is what you want. The only time I'd skip it is if you have an unusual setup like a reverse proxy already handling redirects upstream and even then, I'd usually still pick redirect.

Key Takeaway: Certbot can edit Nginx config automatically, but always test with nginx -t before reload. A typo in the config file (yours or Certbot's) will take the site offline on reload.

sudo nginx -t

sudo systemctl reload nginx

Where Nginx Let's Encrypt Certificate Files Are Stored

Certbot drops everything into /etc/letsencrypt/live/yourdomain/. Inside, you'll find:

  • fullchain.pem β€” your certificate plus the intermediate chain (this is what Nginx serves)
  • privkey.pem β€” the private key (keep this locked down)
  • cert.pem β€” just your domain's certificate
  • chain.pem β€” just the intermediate chain

These are symlinks to the actual files in /etc/letsencrypt/archive/. Don't move them β€” Certbot expects them where they are. If you want to dig deeper into web server tuning, our piece on configuring SSL with Nginx covers cipher suites and HTTP/2.

Install Let's Encrypt SSL on Apache with Certbot

Apache works the same way conceptually, but the plugin reads VirtualHosts instead of server blocks.

Run Certbot for Your Apache VirtualHost

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

Same prompt flow as Nginx. Certbot scans your /etc/apache2/sites-enabled/ directory, finds the VirtualHost matching your domain, and either modifies it directly or creates an SSL-enabled copy.

Stylised terminal showing certbot Apache redirect prompt and HTTPS success for example.com
Stylised terminal showing certbot Apache redirect prompt and HTTPS success for example.com

If you get an error about mod_ssl not being enabled, fix it with:

sudo a2enmod ssl

sudo systemctl restart apache2

Then re-run Certbot.

Enable HTTPS Redirect in Apache

Pick the redirect option when Certbot prompts. It adds a rewrite rule to your HTTP VirtualHost that pushes traffic to HTTPS. Test the config before reloading:

sudo apachectl configtest

sudo systemctl reload apache2

If apachectl configtest reports "Syntax OK," you're good. If not, read the error carefully it usually points to the exact line.

Key Takeaway: Apache VirtualHosts must already match your domain for Certbot to detect and configure them cleanly. If you've got a placeholder default vhost responding to your domain, fix that first.

Where Apache Let's Encrypt Certificate Files Are Stored

Same place as Nginx: /etc/letsencrypt/live/yourdomain/. Apache references fullchain.pem and privkey.pem in the SSL VirtualHost β€” Certbot adds those directives for you.

Verify SSL Installation and Force HTTPS Correctly

Don't just trust that it worked. Verify. Five minutes of checking now saves a week of "why won't this load on Safari" debugging later.

Check the Certificate in a Browser

Open https://example.com in your browser. Click the padlock. Confirm:

  • Issuer is "Let's Encrypt" (or "R3" / "E1" / similar Let's Encrypt intermediate)
  • Expiry is roughly 90 days out
  • The domain matches what you requested
Stylised browser certificate panel showing Let's Encrypt issuer, 90-day expiry, and example.com domain.
Stylised browser certificate panel showing Let's Encrypt issuer, 90-day expiry, and example.com domain.

Test HTTPS from the Command Line

curl -I http://example.com

curl -I https://example.com

The first should return a 301 redirect to HTTPS. The second should return 200 (or whatever your app returns). If the first doesn't redirect, the redirect step didn't take β€” re-run Certbot or check your config.

For deeper inspection of the cert chain:

openssl s_client -connect example.com:443 -servername example.com

Look for "Verify return code: 0 (ok)" near the bottom. That confirms the full certificate chain is valid.

Confirm the Full Certificate Chain Is Valid

If the padlock doesn't show, but the cert is valid, you've probably got mixed content β€” HTTP-loaded images, scripts, or stylesheets on an HTTPS page. Open the browser console and look for warnings. Fix the URLs in your app's templates or database.

Auto-Renew Let's Encrypt Certificates with Certbot Renew

Here's the part that keeps your site secure six months from now. Let's Encrypt certs expire every 90 days. Certbot tries to renew them when there are 30 days left. If you've installed via apt, the systemd timer or cron job is already set up but you should verify it.

Check the Systemd Timer or Cron Job

systemctl list-timers | grep certbot

You should see something like certbot.timer with a "next run" timestamp. If nothing shows up, check for a cron entry instead:

cat /etc/cron.d/certbot

One of those should exist. If neither does, something went sideways during install.

Stylised terminal showing certbot.timer and next activation time for Certbot auto-renewal.
Stylised terminal showing certbot.timer and next activation time for Certbot auto-renewal.

Test Renewal with a Dry Run

This is the single most important command in this entire guide:

sudo certbot renew --dry-run

It simulates a full renewal against Let's Encrypt's staging server without actually replacing your cert. If the dry run succeeds, real renewals will succeed. If it fails, you'll get the exact error message and can fix it now β€” not at 3 a.m. when the cert actually expires.

Pro Tip: A successful certbot renew --dry-run is the fastest way to confirm your setup won't expire unexpectedly. Run it once a month if you're paranoid (I am).

Reload Nginx or Apache After Renewal If Needed

Certbot's Nginx and Apache plugins handle reload automatically. If you've installed the cert via webroot or another method, you may need a deploy hook:

sudo certbot renew --deploy-hook "systemctl reload nginx"

Or for Apache:

sudo certbot renew --deploy-hook "systemctl reload apache2"

Check renewal logs at /var/log/letsencrypt/letsencrypt.log if anything looks off.

Let's Encrypt Wildcard Certificate and DNS Challenge Options

Standard Let's Encrypt certs use the HTTP-01 challenge Certbot drops a file in your webroot, Let's Encrypt fetches it, and you're validated. But HTTP-01 can't issue wildcard certificates. For that, you need DNS-01.

Feature HTTP-01 (Standard) DNS-01 (Wildcard-capable)
Validation method File on web server TXT record in DNS
Wildcard support No Yes (*.example.com)
Setup difficulty Easy Moderate (DNS API needed for automation)
Best for Single sites and known subdomains Many subdomains or dynamic subdomain creation

When to Use DNS-01 Instead of HTTP-01

DNS-01 makes sense if you're running dozens of subdomains, can't expose port 80 publicly, or specifically need a wildcard. To automate it, your DNS provider needs an API and a matching Certbot plugin (Cloudflare, Route53, DigitalOcean, and others have official plugins).

Wildcard Certificate Limitations Beginners Should Know

A wildcard sounds appealing, but it's not always the right call. Wildcards only cover one level β€” *.example.com covers blog.example.com but not api.staging.example.com. They also concentrate risk: if the private key leaks, every subdomain is compromised. For a typical website with a handful of subdomains, just list them with -d flags.

Common Let's Encrypt SSL Errors and Troubleshooting Fixes

Let's get into the failure modes. Most are quick fixes once you know what to look for.

Dark troubleshooting flowchart for Let's Encrypt validation failures with DNS, firewall, vhost, and rate limit fixes.
Dark troubleshooting flowchart for Let's Encrypt validation failures with DNS, firewall, vhost, and rate limit fixes.
Error / Symptom Likely Cause Fix
"DNS problem: NXDOMAIN looking up A" Domain not pointing to server Add or fix A record, wait for propagation
"Connection refused" or timeout on port 80 Firewall blocking port 80 Open 80 in UFW and cloud security group
"Invalid response from /.well-known/acme-challenge/..." Web server misconfigured or wrong vhost serving Check server block hostname; ensure default vhost doesn't intercept
"Fetching ... 522 / 521" via Cloudflare CDN proxy blocking origin or origin down Set Cloudflare to DNS-only (grey cloud) during install
"Too many failed authorizations recently" Hit Let's Encrypt rate limit Wait 1 hour; fix issue before retrying; use --staging for testing
"DNS problem: SERVFAIL looking up AAAA" Broken IPv6 record Remove AAAA record or fix IPv6 binding
Browser shows "Not Secure" after install Mixed content or wrong cert served Fix HTTP asset URLs; check vhost order
"NET::ERR_CERT_AUTHORITY_INVALID" in browser Missing intermediate chain Use fullchain.pem, not cert.pem
Renewal silently failing Web server change or port blocked Run certbot renew --dry-run, check /var/log/letsencrypt/
Wrong certificate served Multiple vhosts, no SNI default Specify default_server in Nginx or set ServerName/ServerAlias correctly in Apache

Domain Validation Failed Because DNS Is Incorrect

Easily the most common issue. Run dig +short example.com from outside your server (use a tool like dnschecker.org if you can't). If the result doesn't match your server IP, that's your problem. Wait for propagation β€” sometimes it's instant, sometimes it takes hours depending on TTL.

Firewall, Reverse Proxy, or CDN Blocks the Challenge

If you're behind Cloudflare with the orange cloud on, the ACME challenge can fail because Cloudflare proxies the request and your origin returns something unexpected. Either turn the proxy off temporarily, or use the DNS-01 challenge with the Cloudflare plugin. Same logic applies to other CDN proxies.

Warning: Cloud proxies and CDN orange-cloud settings can interfere with validation if origin traffic is misconfigured. When in doubt, disable proxying during the initial issuance.

Too Many Requests and Let's Encrypt Rate Limits

Let's Encrypt enforces strict rate limits β€” 50 certs per registered domain per week, 5 duplicate certs per week, and 5 failed validations per account per hostname per hour. If you're testing, always use --staging first:

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

Staging certs aren't trusted by browsers, but they don't count against rate limits. Once your staging run succeeds, drop the flag and re-run for the real cert.

Browser Still Shows SSL or Certificate Authority Errors

If the cert installs fine but browsers complain, the usual culprits are: serving cert.pem instead of fullchain.pem (chain missing), system clock badly out of sync, or an old cached cert. Force-refresh, try incognito, and double-check your config references fullchain.pem.

Best VPS Hosting Environment for Let's Encrypt and Website Security

SSL setup goes smoother on infrastructure where you actually control DNS, firewall, and package management. Shared hosting often hides these knobs behind a control panel, which means when something breaks, you're stuck waiting on support.

Side-by-side comparison of Self-Managed Linux VPS and Managed VPS for SSL setup.
Side-by-side comparison of Self-Managed Linux VPS and Managed VPS for SSL setup.

When a Self-Managed Linux VPS Makes Sense

If you want root access, custom Nginx tuning, multiple domains, or wildcard certs with DNS-01 automation β€” a self-managed Linux VPS is the cleanest fit. You install whatever Certbot plugin you want, edit configs directly, and there's no panel fighting your changes.

When Managed VPS Is Better for Hands-Off SSL Maintenance

If you'd rather not deal with renewals, firewall rules, or web server upgrades, managed VPS hosting handles that side for you while still giving you a real server (not shared). Good middle ground for teams that want VPS-grade performance without dedicating a sysadmin.

Final Checklist

  • Domain A record points to server IP
  • Ports 80 and 443 are open in OS firewall and cloud security group
  • Web server (Nginx or Apache) is installed and serving the domain
  • Certbot and matching plugin installed via apt
  • Certificate issued via certbot --nginx or certbot --apache
  • HTTPS redirect enabled
  • Browser shows valid Let's Encrypt cert and padlock
  • curl -I http://example.com returns 301 to HTTPS
  • certbot renew --dry-run succeeds
  • Systemd timer or cron job for renewal verified active

Hit all ten and you're done. Properly done not "works for now and will probably break in 89 days" done.

That's the complete workflow. If you're still picking infrastructure, choose something with clean DNS control, easy firewall management, and apt-based package installs that combination is what makes Certbot feel effortless. A Linux VPS gives you the full root access needed to run through this entire guide from top to bottom.