Checking TLS and your SSL certificate: chain, expiry, protocols, ciphers
The padlock in the browser says little about how well a connection is actually protected. Behind it sit a certificate that identifies the server and the TLS protocol that encrypts the data, and either can be wrong in ways nobody notices for months.
Updated: 05 November 2026
The certificate chain
Before a browser loads a page, it checks the server's certificate. That certificate was almost never signed directly by the root of a certificate authority (CA). An intermediate certificate sits in between, signed by the root, and it in turn signs yours. Browsers ship with the roots. The intermediate has to come from your server.
Let's Encrypt puts your certificate on its own in cert.pem and the version with the intermediate in fullchain.pem. A web server pointed at the wrong file serves an incomplete chain, and you usually won't notice. Desktop Chrome and Edge fetch the missing piece from the address embedded in the certificate (Authority Information Access, AIA), and Firefox keeps a preloaded copy of the known intermediates. Apps, older Android devices, curl and many API clients do neither and fail. ZwoWebCheck therefore rates an incomplete chain as high and a self-signed or untrusted certificate as critical.
Names and wildcards
A certificate is valid only for the names in its Subject Alternative Name (SAN) field. One issued for www.example.com does not cover example.com. Put both names in, even if one of them only redirects, because visitors see the warning before the redirect happens.
A wildcard certificate for *.example.com covers exactly one level. shop.example.com is included. test.shop.example.com is not, and neither is example.com itself.
Expiry and renewal
Behind almost every expired certificate is a renewal someone meant to do by hand. With ACME, the protocol Let's Encrypt uses, a client such as certbot or acme.sh takes care of it. Many hosting providers and web servers like Caddy handle it out of the box.
Manual renewal is on its way out anyway. Under ballot SC-081, the CA/Browser Forum is cutting the maximum lifetime of public certificates in steps:
| issued from | maximum |
|---|---|
| 15 March 2026 | 200 days |
| 15 March 2027 | 100 days |
| 15 March 2029 | 47 days |
Let's Encrypt is moving faster and will shorten its certificates from 90 to 45 days by 2028. With today's 90-day certificates, certbot renews about 30 days before expiry. We report fewer than three weeks remaining as medium and less than one week as high, since by then the automation has most likely stopped. ACME clients renew shorter certificates later, typically when a third of the lifetime is left. For those our limits shrink accordingly: medium below a quarter of the lifetime, high below a twelfth.
Key and signature
RSA keys need at least 2,048 bits; anything shorter is critical. ECDSA on the P-256 curve gets by with a much shorter key, offers roughly the strength of 3,072-bit RSA and makes the handshake faster. For a new certificate, ECDSA is the better choice. Browsers have rejected certificates signed with SHA-1 or MD5 for years.
Several servers behind one name
When your name resolves to several IP addresses, there are often two servers or a load balancer with its own certificate behind it. At renewal time one of them tends to get forgotten, and only some visitors see a warning. ZwoWebCheck compares certificate and TLS version on the first two IPv4 addresses for exactly this reason.
TLS versions
TLS 1.3 (RFC 8446) is the current version. Its handshake needs one round trip fewer. The insecure options have been removed from the standard, and forward secrecy is built in. TLS 1.2 is still secure with the right cipher suites, and older clients need it. We nevertheless rate a server that offers nothing newer than TLS 1.2 as medium, because with a current OpenSSL enabling TLS 1.3 is a one-line change.
The IETF deprecated TLS 1.0 and 1.1 in RFC 8996 in March 2021, after the major browsers had already switched them off in 2020. SSLv3 has been broken since the POODLE attack in 2014 (RFC 7568). A server that still accepts any of them has usually gone untouched for years. We rate TLS 1.0 and 1.1 as high and SSLv3 as critical.
Cipher suites and forward secrecy
A cipher suite determines how client and server agree on a key and which algorithm encrypts the data. Every TLS 1.3 suite is fine; with TLS 1.2 it depends on the list. You want ECDHE key exchange combined with AEAD encryption, meaning AES-GCM or ChaCha20-Poly1305.
ECDHE provides forward secrecy. If someone records your traffic today and steals the server's private key next year, the recorded sessions stay unreadable. Suites with plain RSA key exchange lack this property. RC4, 3DES (vulnerable to SWEET32) and anything with NULL or EXPORT in its name have no place in a current configuration.
Browsers negotiate HTTP/2 during the TLS handshake via ALPN. It sends many files in parallel over one connection, which makes pages faster but has no bearing on security. In nginx 1.25.1 and later, http2 on; is all it takes.
A sound configuration
There is little point in assembling cipher lists yourself. The former Mozilla SSL Configuration Generator is now the TLSRef Configurator (configurator.tlsref.org), and the old address ssl-config.mozilla.org points there. For an ordinary website the "Intermediate" profile is the right one. It allows TLS 1.2 and 1.3 with ECDHE and AEAD suites only. The core of it in nginx:
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
ssl_prefer_server_ciphers off;
nginx does not set the TLS 1.3 suites through ssl_ciphers; OpenSSL's defaults are fine there. Run nginx -t before reloading. Once everything works, HSTS is the next step, and CAA lets you restrict which CAs may issue certificates for your domain at all.
Common mistakes
cert.peminstead offullchain.pemin the web server. Your own browser hides it, your customer's app does not.- certbot renews on schedule, but nobody reloads the web server, so it keeps serving the old certificate. A deploy hook such as
--deploy-hook "systemctl reload nginx"fixes that. - The new certificate is on the web server while the load balancer in front still presents the old one.
- A cipher list copied from a 2015 tutorial that still contains 3DES or RC4.
Checking TLS and your certificate
ZwoWebCheck opens one ordinary TLS connection to your address and then sends a few short connection attempts that offer only old protocol versions or weak suites; your server sees nothing else from us. The report covers chain, name, expiry date, key, protocol versions and cipher suites, each with a traffic light and a recommendation.