SSL/TLS certificates: a complete guide
What this is
A working understanding of TLS certificates for someone running their own server: what a certificate actually proves, where to get one for free (there are five current sources, not one), how validation challenges differ and which to prefer, what a wildcard does and doesn't cover, and the configuration and reliability practices that separate a setup that survives years from one that fails on day 91. The hosting guide has the two-command quick start; this page is the full picture behind it.
What a certificate actually is
A TLS certificate binds a domain name to a public key, signed by a certificate authority (CA) whose root certificate browsers and operating systems already trust. The standard web certificate is domain-validated (DV): the CA verified, at issuance time, that whoever requested it controls the domain. That is the entire claim. Encryption strength has nothing to do with what you paid; a free DV certificate and a $200 one produce byte-identical TLS.
Paid tiers exist, OV and EV embed a verified organization name, but browsers stopped displaying any special UI for them years ago, and for a typical website they buy nothing visible. The defensible reasons to pay for a certificate today are narrow compliance requirements, not security.
ACME is the protocol that made all of this automatic: your client proves domain control (a "challenge"), the CA issues, and the same client renews on a timer without you. Every CA and tool on this page speaks it.
Why automation is the whole game
Free certificates are short-lived on purpose: 90 days is the norm, and the industry has formally committed to much shorter. Under the CA/Browser Forum's adopted schedule, the maximum certificate lifetime drops to 200 days in 2026, 100 days in 2027, and 47 days by 2029, for every CA, paid or free. The era of installing a certificate by hand once a year is ending by design.
The practical doctrine follows directly: a certificate setup is correct only if it renews unattended and you've watched it do so (every client has a dry-run or staging mode for exactly this). Anything manual is a scheduled future outage.
The free ACME certificate authorities
All of these issue browser-trusted DV certificates over standard ACME, so the same client works with any of them. The differences are registration friction and small policy details.
One entry for the obituary column first: Buypass, long the standard "Let's Encrypt alternative" in tutorials, stopped issuing in October 2025 and shut down its ACME service in April 2026. If a guide recommends Buypass Go SSL, it's out of date.
Let's Encrypt
The default, and its structural advantage is real: no account, no sign-up, no EAB credentials, every ACME client works with it out of the box, it runs a staging environment for safe testing, and it has the longest operational track record. Certificates are 90 days, wildcards supported via DNS-01.
# certbot (installs the cert into nginx and sets up renewal)
certbot --nginx -d example.com -d www.example.com
# acme.sh
acme.sh --issue --server letsencrypt -d example.com -w /var/www/html
ZeroSSL
Free 90-day certificates, unlimited, wildcards included, over ACME. Requires EAB (External Account Binding) credentials from a free account, which is less friction than it sounds: ZeroSSL is acme.sh's default CA, and acme.sh obtains the EAB for you from just an email address:
acme.sh --register-account -m [email protected]
acme.sh --issue -d example.com -w /var/www/html
With certbot, generate EAB credentials in the ZeroSSL dashboard (Developer section), then:
certbot --server https://acme.zerossl.com/v2/DV90 \
--eab-kid YOUR_KID --eab-hmac-key YOUR_KEY \
--nginx -d example.com
Google Trust Services
Free ACME issuance on Google's roots, whose selling point is very broad device trust, including old Android versions that distrust some other chains. EAB keys come from a Google Cloud account:
gcloud publicca external-account-keys create
Then use the returned key ID and HMAC with any client against https://dv.acme-v02.api.pki.goog/directory (certbot's --eab-kid/--eab-hmac-key as above; acme.sh has a built-in --server google shortcut).
SSL.com
A commercial CA with a free 90-day DV tier over ACME. Create a free account; the dashboard shows your ACME credentials, and acme.sh has a built-in --server sslcom shortcut.
Actalis
An Italian CA offering a free ACME plan with unlimited issuance, the notable choice if you specifically want a European CA. Register at actalis.com, generate EAB credentials in their portal, and point any ACME client at the directory URL they provide.
Clients: pick by your stack, not by fashion
- Caddy or Traefik: you're done, ACME is built in, certificates appear and renew with zero configuration, and Caddy even falls back to a second CA automatically (Let's Encrypt, then ZeroSSL) if issuance fails. This is the strongest reliability story on the page, for free.
- nginx or Apache: pick one of the two standalone clients. certbot is the distro-packaged, most-documented choice. acme.sh is a lighter shell script with more CA shortcuts, automatic EAB handling, and TLS-ALPN support, which certbot lacks. Both install renewal timers.
- Go/infrastructure tooling: lego is the library-grade client the above ecosystems build on.
- Windows/IIS: win-acme does the same job as a scheduled task.
Challenge types: prove control the right way
The challenge is how the CA verifies you control the domain, and the choice matters more than most guides admit.
- DNS-01 proves control by publishing a TXT record. Nothing inbound touches your server at all: no open port required, it works behind CDNs, proxies, and closed firewalls, and it is the only challenge that can issue wildcards. The cost is automation: your ACME client needs API access to your DNS (both certbot and acme.sh have plugins for all the major providers). Where it's available, this is the strongest option.
- TLS-ALPN-01 proves control during a TLS handshake on port 443 only. No port 80, no HTTP involved. Caddy and Traefik do it natively (it's how they renew without any HTTP plumbing), and acme.sh supports it (
--alpn); certbot does not support it at all. With a standalone client it needs to answer on 443 itself, so it fits best where the web server is the ACME client, or on hosts without one. - HTTP-01 proves control by serving a file at
http://yourdomain/.well-known/acme-challenge/, which is why it demands port 80 open to the world and a carve-out from your HTTPS redirect. It's the ubiquitous default and there's nothing wrong with it when port 80 is open anyway to redirect visitors to HTTPS. What it should never be is the reason port 80 stays open: if your service is HTTPS-only, don't keep an extra listening port and a redirect exemption alive purely so a renewal can happen over plaintext HTTP, use DNS-01 (or TLS-ALPN-01 where your stack supports it) and close 80 entirely.
The decision in one breath: Caddy/Traefik → TLS-ALPN, already done. Wildcard or HTTPS-only or behind a CDN → DNS-01. Port 80 open anyway for redirects → HTTP-01 is fine.
Wildcards, understood properly
A wildcard certificate (*.example.com) is the most misunderstood object in this topic, and the rules are exact:
- It covers one label, one level deep.
*.example.commatchesapp.example.comandmail.example.com. It does not matcha.b.example.com(two levels), which needs*.b.example.com. - It does not cover the apex.
example.comitself is not matched by*.example.com. This is why the standard wildcard certificate carries both names: the apex and the wildcard, in one cert. - It requires DNS-01. All CAs require the DNS challenge for wildcards, deliberately: a certificate valid for every present and future subdomain warrants proof of DNS-level control, not just control of one web server.
Issuance, both names together:
# acme.sh with, e.g., Cloudflare-hosted DNS
export CF_Token="your-scoped-api-token"
acme.sh --issue --dns dns_cf -d example.com -d '*.example.com'
# certbot with the matching DNS plugin
certbot certonly --dns-cloudflare \
--dns-cloudflare-credentials /root/.secrets/cloudflare.ini \
-d example.com -d '*.example.com'
Every DNS provider with an API has an equivalent plugin; use a scoped token (zone-edit for the one zone, not a global account key), because that credential lives on the server for renewals.
And the counterweight: if you have three known subdomains, a plain multi-SAN certificate (-d example.com -d www.example.com -d api.example.com) is simpler, requires no DNS API on the server, and exposes less if the host is compromised. Wildcards earn their place when subdomains are numerous or created dynamically.
Protocols and ciphers: strong by configuration, not by luck
The certificate is only half of TLS; the server's protocol and cipher configuration is the other half, and defaults on older distros can be poor.
- Enable TLS 1.2 and 1.3 only. TLS 1.0 and 1.1 have been formally deprecated for years, and nothing legitimate still needs them. In nginx:
ssl_protocols TLSv1.2 TLSv1.3; - Don't hand-roll cipher lists, and especially don't paste one from a 2015 blog post. Generate the configuration from the Mozilla SSL Configuration Generator: pick your server and version, take the Intermediate profile (the right default; "Modern" only if you can drop older clients), and use it verbatim. TLS 1.3's cipher suites aren't configurable through the classic directives anyway, leave them alone.
- Prefer ECDSA keys. Modern clients negotiate them universally, handshakes are faster, and keys are smaller; certbot and acme.sh both issue ECDSA by default now. Add an RSA fallback only if you must serve genuinely ancient clients.
- HSTS, once everything works.
Strict-Transport-Securitytells browsers to refuse plain HTTP for your domain, an excellent hardening step and a commitment: turn it on only after HTTPS is fully working everywhere, start with a modestmax-age, and treat thepreloadflag as close to irreversible. - Caddy note: its TLS defaults already match current best practice; the tuning above is for nginx and Apache, whose shipped defaults trail behind.
Then measure instead of assuming: run SSL Labs' server test, the industry-standard report card for exactly this, certificate, chain, protocols, ciphers, known weaknesses, graded A+ to F with each finding explained. An A is the pass mark; the Mozilla intermediate profile plus a valid chain gets you there. For the same audit from a terminal (or for servers you'd rather not submit to a public tool), testssl.sh performs the equivalent checks locally.
High availability: certificates that survive bad days
The failure mode to design against isn't a bad certificate, it's issuance being unavailable the week you need it: a CA outage, a rate limit, a broken renewal nobody noticed.
- Don't depend on a single CA. Everything on this page speaks the same protocol, so a second CA is a configuration line, not a migration. Caddy does the fallback automatically; with acme.sh it's one command when needed (
acme.sh --set-default-ca --server zerossl, or--serverper issue); with certbot, keep the ZeroSSL EAB pattern from above in your notes. This is also the answer to Let's Encrypt rate limits, which are the usual self-inflicted emergency: a looping misconfiguration burns the duplicate-certificate allowance, and the fastest way out is issuing the same names from a different CA while the loop gets fixed. - Test against staging, not production. Let's Encrypt's staging endpoint exists so experiments don't consume rate limits:
certbot --test-cert/acme.sh --staging, andcertbot renew --dry-runfor verifying renewal health any time. - Let the timers do the timing. Clients renew at roughly a third of lifetime remaining (certbot at 30 days before expiry) with daily checks; the practice worth adding is watching it: after setup, confirm the timer exists (
systemctl list-timers) and the dry run passes. - Monitor expiry from outside the server. The server whose renewal is broken is the wrong place to run the alert. Any uptime monitor with certificate checks (Uptime Kuma if you self-host one) watching for "expires in under 14 days" turns every possible renewal failure, whatever the cause, into an email two weeks ahead instead of a red padlock at 3 AM. crt.sh complements this with the public issuance log: every certificate ever issued for your domain, useful both to confirm a renewal happened and to spot certificates you didn't request.
- CAA records, with the fallback in mind. A
CAADNS record whitelists which CAs may issue for your domain, cheap hardening. Just remember it must list every CA you use, including your fallback, or the fallback fails precisely when you reach for it.
When something breaks
Browser errors, expired certificates, name mismatches, chain problems, and the Cloudflare SSL modes each have a specific fix, all collected in Fixing SSL certificate errors. If your site sits behind Cloudflare's proxy, the certificate visitors see is Cloudflare's edge certificate, and the origin-side rules are in Cloudflare best practices.
Still need help?
You can open a support ticket. So we can help on the first reply, it's worth mentioning:
- the domain, and which CA and client you're using,
- the challenge type (HTTP-01, DNS-01, or TLS-ALPN-01),
- the exact error from the client's log or dry run.
Related questions
- "Where can I get a free SSL certificate besides Let's Encrypt?"
- "Do paid SSL certificates encrypt better than free ones?"
- "What's the difference between HTTP-01, DNS-01, and TLS-ALPN-01 challenges?"
- "Can I renew certificates without keeping port 80 open?"
- "How do wildcard certificates work, and why do they need a DNS challenge?"
- "Does *.example.com cover example.com or sub.sub.example.com?"
- "What happens when I hit Let's Encrypt's rate limit?"
- "Which TLS versions and ciphers should my server allow?"
- "How do I test my SSL configuration strength?"
- "How short are certificate lifetimes going to get?"