HTTPS Certificates in Practice — From Let's Encrypt Issuance to Auto-Renewal (certbot, ACME, managed)
HTTPS certificates were once a tedious chore: pay every year, issue one manually, and copy it onto the server. Now free certificates and automation tools are the standard, and once you set it up properly, there’s almost nothing left for a person to touch. In this post I’ll walk through actually issuing a certificate, installing it on a server or in the cloud, and tying it up so it renews automatically, step by step. If you’re new to what a certificate vouches for and what a certificate authority and trust chain are, I recommend reading What Is an SSL Certificate, and Why Do You Need One? first.
The basic flow of issuance: ACME and domain ownership validation #
The heart of automatic issuance is a protocol called ACME. A certificate authority like Let’s Encrypt uses ACME to automatically confirm “are you really the owner of this domain?” and then issues the certificate. Two validation methods are common.
- HTTP-01: the CA asks for a specific value at the path
http://domain/.well-known/acme-challenge/..., and ownership is proven when your server responds with that value. Port 80 must be open from the outside. - DNS-01: ownership is proven when you put the value the CA asks for into the domain’s TXT record (
_acme-challenge). It doesn’t need port 80, and you must use this method to issue a wildcard certificate.
Issuing Let’s Encrypt on a Linux server #
This is based on the most common setup, Linux + Nginx. certbot handles everything from issuance to editing the Nginx config in one go.
# Install (e.g., Ubuntu/Debian)
sudo apt install certbot python3-certbot-nginx
# Issue + apply to Nginx config automatically (HTTP-01)
sudo certbot --nginx -d schoolofweb.net -d www.schoolofweb.netOnce issued, the certificate files appear at the following location. Knowing each file’s role makes errors easy to diagnose.
/etc/letsencrypt/live/schoolofweb.net/
├── privkey.pem # private key. never expose externally
├── cert.pem # the site certificate alone
├── chain.pem # the intermediate certificate
└── fullchain.pem # cert + chain. usually point Nginx at thisIf you point to them directly in Nginx, use fullchain.pem and privkey.pem. If you install only the site certificate and leave out the intermediate (chain), the trust chain breaks in some environments and errors out. That’s why using fullchain.pem rather than cert.pem is the safe choice.
server {
listen 443 ssl;
server_name schoolofweb.net www.schoolofweb.net;
ssl_certificate /etc/letsencrypt/live/schoolofweb.net/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/schoolofweb.net/privkey.pem;
# ...
}Auto-renewal: why 90 days is the default #
A Let’s Encrypt certificate is valid for 90 days. That looks short, but it’s short precisely because it’s designed around auto-renewal. Install certbot as a package and a renewal timer is usually registered alongside it.
# Check that the auto-renewal timer is registered
systemctl list-timers | grep certbot
# Simulate a real renewal to check it runs cleanly (doesn't actually renew)
sudo certbot renew --dry-runrenew actually renews only certificates close to expiry. Finally, also confirm that a renewal hook runs systemctl reload nginx so Nginx re-reads the new certificate. Even now that auto-renewal is standard, most incidents come from “the timer was stopped” or “renewal happened but the server didn’t reload.”
Wildcard certificates #
A certificate that covers all subdomains in one sheet, like *.schoolofweb.net, is called a wildcard certificate. Wildcards can’t be issued with HTTP-01; you must use DNS-01.
sudo certbot certonly --manual --preferred-challenges dns \
-d "schoolofweb.net" -d "*.schoolofweb.net"Doing it manually (--manual) means entering the TXT record yourself, which doesn’t fit auto-renewal. In practice, the standard is to use a plugin for your DNS service (e.g., certbot-dns-cloudflare, certbot-dns-route53) to automate registering the TXT record too.
Managed cloud: choosing not to manage it yourself #
Instead of running certbot on the server, you can let the platform manage the certificate for you. This approach is more common these days.
- AWS Certificate Manager (ACM): issues and auto-renews certificates for free, and you attach them to an ALB or CloudFront. Validation is usually handled automatically via Route 53 DNS records. You never touch certificate files on a server.
- Cloudflare: turn on the proxy (orange cloud) and Cloudflare automatically issues and renews the certificate for the segment between visitors and itself. It also provides a separate Origin certificate for the segment to your origin server.
Managed options are convenient because you don’t handle key files directly, but you do have to separately think about how to protect the segment between where the certificate terminates (the load balancer or CDN) and the origin server.
Certificate types at a glance #
- DV (domain validation): confirms only domain ownership. Let’s Encrypt is this, and it’s enough for most sites.
- OV/EV (organization / extended validation): the issuer also verifies the organization’s real existence. Issuance is slow and costs money, and it’s required in some financial and enterprise environments.
- SAN (multi-domain): holds several domains in one certificate. The example above with multiple
-doptions is a SAN certificate. - Wildcard: covers all subdomains in one sheet.
Diagnosing common errors #
When something goes wrong, don’t just look at the browser warning — check the chain directly with tools.
# Check the certificate chain and expiry the server hands down
echo | openssl s_client -connect schoolofweb.net:443 -servername schoolofweb.net 2>/dev/null \
| openssl x509 -noout -dates -subject -issuer
# Headers and certificate state at a glance
curl -vI https://schoolofweb.netFrequently encountered causes:
- Missing intermediate certificate: you installed only
cert.pem. Switch tofullchain.pem. It can show up as fine in the browser but failing only on some clients. - Name mismatch: the domain in the certificate differs from the domain you’re actually visiting. Check whether
wwwis included and whether a domain is missing from the SAN. - Expiration: the auto-renewal timer stopped, or a reload was missing after renewal. Check with
certbot renew --dry-run. - HTTP-01 failure: port 80 is blocked, or a firewall or security group is blocking the CA’s access. If the port can’t be opened, switch to DNS-01.
- Mixed content: the page is HTTPS but it loads images or scripts over
http://. This isn’t a certificate problem; you fix the links inside the page tohttps://.
Wrapping up #
HTTPS certificates in practice come down to three things: validate domain ownership with ACME and issue the certificate, install it on the server or platform without breaking the trust chain, and tie it up so it renews automatically before expiry. Now that automation is standard, the key is to “set it up properly once, and occasionally check that renewal is actually running.”
For a certificate to work, the domain in front of it has to be connected correctly. If the domain isn’t connected yet, see DNS Records Setup in Practice; and if you’re curious about the principle of encryption and the padlock, read What the Padlock in Your Address Bar Protects alongside.