SSL certificates used to be a real purchase — $50 to $200 per year for the privilege of https://. In 2026 that is a scam in almost every indie context. Let’s Encrypt and Cloudflare hand out free certificates that browsers trust identically. Below is the model, the commands to verify your cert, and the self-host configs if you’re not on a platform.
Background
An SSL (technically TLS) certificate is a cryptographic file that proves the domain you are connecting to is the domain the certificate was issued for. Browsers trust certificates issued by Certificate Authorities (CAs). Let’s Encrypt is a free, automated, browser-trusted CA. Most modern hosts auto-provision certificates from it on your behalf.
How to tell
- Your site loads with
https://and a padlock — you already have working SSL. - Your registrar emailed you about a “limited time SSL discount” — sales, not necessity.
- Your host dashboard says “certificate active” or “SSL provisioned” — done.
- Your browser shows a “not secure” warning — likely a config issue, not a missing-cert-purchase issue.
openssl s_client -connect yourdomain.com:443returns a valid chain.
Quick verdict
Do not buy an SSL certificate as an indie. Use the free one your host (Vercel, Firebase, Netlify, Cloudflare Pages, Cloudflare for non-hosted sites) provides. Only consider paid certificates for enterprise EV (extended validation) needs — which almost no indie site has.
Before you start
- Domain points at your host correctly (DNS resolves).
- Host’s “Add domain” flow completed.
curlandopensslinstalled for verification.
Step by step
-
Most hosts auto-provision. Vercel, Netlify, Firebase, Cloudflare Pages, Render, Fly — add the domain, wait for “SSL provisioned” (usually < 1 hour after DNS is correct).
-
Verify with
curl:
curl -vI https://yourdomain.com 2>&1 | grep -E 'subject:|issuer:|HTTP|Verify return code'
# subject: CN=yourdomain.com
# issuer: C=US, O=Let's Encrypt, CN=R3
# HTTP/2 200
# Verify return code: 0 (ok)
- Or with
openssl:
echo | openssl s_client -showcerts -servername yourdomain.com -connect yourdomain.com:443 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates
# subject= /CN=yourdomain.com
# issuer= /C=US/O=Let's Encrypt/CN=R3
# notBefore=May 1 00:00:00 2026 GMT
# notAfter=Jul 30 00:00:00 2026 GMT ← 90 days for Let's Encrypt
- Self-host on a VPS — use Caddy (zero-config Let’s Encrypt):
# /etc/caddy/Caddyfile
yourdomain.com {
root * /var/www/yoursite
file_server
encode gzip
}
www.yourdomain.com {
redir https://yourdomain.com{uri} permanent
}
Restart: sudo systemctl reload caddy. Caddy auto-renews indefinitely.
- Self-host with Nginx — use Certbot:
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
# follow prompts, agrees to terms, configures Nginx, sets auto-renew
sudo systemctl list-timers | grep certbot
# certbot.timer ... (auto-renew twice daily)
Verify renewal works without actually renewing:
sudo certbot renew --dry-run
-
Cloudflare-fronted sites — set “Full (strict)” SSL mode. Dashboard → SSL/TLS → “Full (strict)”. This requires a valid cert on your origin (Let’s Encrypt or self-signed). “Flexible” sends HTTP between Cloudflare and your origin and is unsafe.
-
Force HTTPS redirect: Most hosts do this automatically. If you self-host, in Caddy it’s built-in; in Nginx:
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
return 301 https://$host$request_uri;
}
- Set monitoring for expiration. Cheap: a cron that pings once a week:
# scripts/cert-expiry-check.sh
DAYS=$(echo | openssl s_client -servername "$DOMAIN" -connect "$DOMAIN:443" 2>/dev/null \
| openssl x509 -noout -enddate | sed 's/notAfter=//' \
| xargs -I{} date -d "{}" +%s)
NOW=$(date +%s)
REMAINING=$(( (DAYS - NOW) / 86400 ))
[ "$REMAINING" -lt 14 ] && echo "WARN: $DOMAIN cert expires in $REMAINING days"
Implementation checklist
curl -vIreturns a valid cert with the expected CN.openssl x509 -noout -datesshows a future expiration.- Auto-renew confirmed via
certbot renew --dry-runor platform docs. - Cloudflare SSL mode is “Full (strict)” if applicable.
- HTTP automatically redirects to HTTPS.
After-launch verification
- Browser padlock with no warnings.
- SSL Labs (https://www.ssllabs.com/ssltest/) score is at least A.
- Mixed-content warnings are zero (DevTools → Console).
Common pitfalls
- Paying your registrar $50/year for an SSL certificate they will install — pure profit margin for them.
- Buying an EV (extended validation) certificate for an indie blog — browsers no longer show special UI for EV. It is essentially the same as DV for end users.
- Disabling auto-renew on Let’s Encrypt and forgetting until visitors get a cert error in 90 days.
- Using “Flexible” SSL on Cloudflare — it means HTTP between Cloudflare and your origin, which is unsafe and breaks some flows. Always “Full (strict)”.
- Pinning a specific certificate in code/headers when you do not control renewal — auto-renewal will break and you will not notice until users complain.
FAQ
- Are free certificates as secure as paid ones?: Yes. They use the same cryptographic algorithms, the same root CAs, and are trusted identically by all major browsers.
- How often do Let’s Encrypt certs renew?: Every 90 days. Automation does it — you should never have to think about it.
- What is the difference between SSL and TLS?: TLS is the modern protocol name; SSL is the older name still used colloquially. “SSL certificate” today means a TLS certificate.
- Do I need a wildcard certificate?: Only if you have many subdomains under one cert. Let’s Encrypt offers wildcards via DNS challenge. Most hosts handle it for you.
- What about HSTS preload?:
.devand.appare preloaded — browsers reject HTTP. For other TLDs you can opt in by adding theStrict-Transport-Securityheader.