SSL Certificates: Why They Expire and What to Do
The Night Elon Musk Blamed a Text File
In April 2023, Starlink went offline for several hours. Satellites still in orbit, ground equipment still running, but customers worldwide lost connectivity. Elon Musk posted on Twitter/X citing "an expired ground station certificate" as the cause -- and then called it "a single point vulnerability" that was "inexcusable."
He was right on both counts.
A TLS certificate is a text file, typically two to four kilobytes. And when it expires, it can take down an entire service. Starlink is not alone. Microsoft Teams went dark for hours in 2020 when an authentication certificate expired. The Bank of England's CHAPS payment system halted transactions in July 2024 -- twice within days -- due to certificate issues. Alaska Airlines had to issue a ground stop at Seattle in September 2024 because a certificate "impacted multiple systems." Spotify's podcast platform Megaphone stayed down for eight hours in 2022 because someone did not renew a cert.
This is not a story about advanced security failures. This is a story about a countdown timer that everyone forgot to watch.
What a Certificate Actually Is
When your browser connects to https://yourapp.com, it is doing more than loading a page. It is performing a handshake. The server presents a certificate that says: "I am who I claim to be, and here is a trusted third party vouching for that." The browser checks the voucher, and if everything looks good, the two parties negotiate an encrypted connection.
That certificate contains the domain name, a public key, the name of the issuing authority (a Certificate Authority, or CA), and two critical dates: "not before" and "not after." The "not after" date is the expiration.
Why does it expire at all? Because cryptographic keys decay in value over time. The longer a key is in use, the more opportunities an attacker has to compromise it. Expiration forces rotation. It is a deliberate design choice, not a flaw.
Currently, public TLS certificates are valid for up to 398 days. That is about to change drastically: in April 2025, the CA/Browser Forum voted unanimously to reduce maximum validity to 200 days by March 2026, 100 days by March 2027, and 47 days by March 2029. Let's Encrypt announced in December 2025 that it will move to 45-day certificates ahead of the industry mandate. If you are not already automating certificate renewal, that window is closing fast.
What Users See When It Goes Wrong
You have seen the browser warning. Chrome calls it "Your connection is not private" and shows a red lock with an X. Firefox says "Warning: Potential Security Risk Ahead." Safari presents a similar message.
Most users stop there. They do not click through. Your site might as well be unreachable.
For a consumer app, that means lost sessions and lost revenue. For a B2B SaaS product, it means enterprise customers see a security warning on your login page and send it to their InfoSec team. For an API endpoint, it means downstream services start throwing connection errors with cryptic messages that take hours to trace back to the actual cause.
A CSC research study published in July 2025 found that 40% of enterprises are at risk of unexpected outages from certificate issues. A 2025 study on TLS in healthcare found 17% of healthcare websites had certificates near expiry or incomplete certificate chains. These are not small operations. These are organizations with dedicated IT teams.
The Trust Chain You Rarely See
A certificate does not stand alone. It is part of a chain.
At the top is a root Certificate Authority -- organizations like DigiCert, Sectigo, or Let's Encrypt's ISRG Root. Browsers and operating systems ship with a pre-installed list of root CAs they trust. Below the root are intermediate CAs, which do the day-to-day work of issuing leaf certificates to websites.
Your certificate (the leaf) is signed by an intermediate, which is signed by a root. When a browser validates your certificate, it walks up this chain. If any link is missing or misconfigured, the whole thing fails -- even if your leaf certificate is valid.
This is why deploying only your certificate is not enough. You need to deploy the full chain. Many servers require you to concatenate your certificate with the intermediate certificate(s) into a single file. Get this wrong and you will see "certificate chain incomplete" errors that are infuriating to debug because the site works in some browsers (which cache intermediate certs) and fails in others (which do not).
Check your chain with:
openssl s_client -connect yourdomain.com:443 -showcerts
Look for the full chain in the output. You should see multiple certificates, ending with the root or a trusted intermediate.
How to Check Certificate Status
Browser padlock: Click the lock icon in the address bar. In Chrome, go to "Connection is secure" then "Certificate is valid." This shows issuer, expiration, and the domains covered.
OpenSSL from the terminal:
# Check expiration date
echo | openssl s_client -connect yourdomain.com:443 2>/dev/null \
| openssl x509 -noout -dates
# Full certificate details
echo | openssl s_client -connect yourdomain.com:443 2>/dev/null \
| openssl x509 -noout -text
SSL Labs: Run a free deep analysis at https://www.ssllabs.com/ssltest/. It grades your configuration, checks the full chain, identifies weak cipher suites, and flags mixed content. Run this on every production domain before you launch and after every server migration.
Check a certificate file directly (useful for certs you have downloaded or are about to deploy):
openssl x509 -in certificate.crt -noout -enddate
If You Are on Vercel, Relax (But Only Partly)
Vercel provisions a Let's Encrypt certificate automatically for every deployment and custom domain you add. It handles renewal transparently via the ACME protocol. You do not configure anything, you do not think about it, and it does not expire on you.
This is genuinely excellent and you should appreciate it.
Here is where you need to pay attention:
Custom domains with external DNS: Vercel can only auto-renew if it can complete domain validation. If you move your DNS provider and break the validation records, renewal will silently fail.
API subdomains hosted elsewhere: If you are running a backend on a DigitalOcean droplet or Railway and it has its own domain or subdomain, Vercel cannot help you there. That cert is your responsibility.
Self-hosted services: A database admin panel, a Grafana instance, an internal tool on a VM -- anything you run yourself needs its own certificate management.
Third-party integrations: If you are using an API provider that sends you a certificate for mTLS (mutual TLS), that certificate has an expiration date and it is not managed by anyone other than you.
The mental model: anything Vercel proxies and controls, Vercel handles. Anything else is yours.
Setting Up Monitoring
The right time to know a certificate is expiring is 30 days before it expires. The wrong time is when users start reporting errors.
If you are running your own infrastructure and have access to cron:
# check-cert.sh -- run from cron weekly
DOMAIN="yourdomain.com"
EXPIRY=$(echo | openssl s_client -connect ${DOMAIN}:443 2>/dev/null \
| openssl x509 -noout -enddate | cut -d= -f2)
EXPIRY_EPOCH=$(date -d "${EXPIRY}" +%s)
NOW_EPOCH=$(date +%s)
DAYS_LEFT=$(( (EXPIRY_EPOCH - NOW_EPOCH) / 86400 ))
if [ $DAYS_LEFT -lt 30 ]; then
echo "WARNING: ${DOMAIN} certificate expires in ${DAYS_LEFT} days" | \
mail -s "Certificate Expiry Warning" you@yourcompany.com
fi
For a more robust solution, UptimeRobot offers free SSL monitoring with email and Slack alerts. Better Uptime and Checkly offer more detailed checks including chain validation. If you run Prometheus, the Blackbox exporter provides the probe_ssl_earliest_cert_expiry metric which you can alert on directly.
Given that certificate lifetimes are heading toward 47 days by 2029, set your alerts at 30 days. That gives you enough runway to act without panicking -- and without hardcoding renewal intervals that will break when the validity periods shrink below your assumed schedule.
Mixed Content: The Hidden HTTPS Problem
Having a valid certificate does not mean your site is fully secure. Mixed content warnings happen when an HTTPS page loads resources -- images, scripts, fonts, stylesheets -- over plain HTTP.
Browsers block active mixed content (scripts, iframes) outright. Passive mixed content (images, audio) may load but triggers a warning. Both scenarios are problems.
Common causes: old database records storing http:// URLs for user-uploaded images, hardcoded HTTP links to a CDN that now supports HTTPS, or a third-party widget that has not been updated. Fix it by auditing pages with Chrome DevTools (the Console tab shows mixed content warnings) and ensuring any CDN or asset domain serves over HTTPS.
HSTS: Preventing the Downgrade
HSTS -- HTTP Strict Transport Security -- is a response header that tells browsers: "This site only works over HTTPS. Do not try HTTP. Cache this policy for this duration."
Strict-Transport-Security: max-age=31536000; includeSubDomains
Without HSTS, even after a user has visited your site over HTTPS, a network attacker could intercept the initial unencrypted request before your redirect to HTTPS fires. HSTS eliminates that window.
Once you set this header, browsers cache it. Set max-age=31536000 (one year) for production. Start with a shorter value like 86400 (one day) while testing, because once it is cached with a long max-age, you cannot easily undo it.
Certificate Pinning: Just Say No
Certificate pinning is a technique where an application hardcodes the expected certificate or its public key hash, and refuses connections presenting a different certificate. It was briefly fashionable as an extra security layer.
Do not do it for web apps. When your certificate rotates -- and it will, especially as lifetimes shrink toward 47 days -- any client that cached the old pin will break. You will cause your own outage, and fixing it requires users to update their software. The major browsers have abandoned pinning. For mobile apps, it is sometimes used, but only with careful key rotation planning and a backup pin in place.
For the vast majority of production apps, a properly configured TLS setup with automated renewal is far more reliable than pinning.
Action Checklist
- Audit every domain and subdomain in production. List the issuing CA and expiration date for each certificate.
- Confirm auto-renewal is working on all Vercel custom domains. Check for DNS validation issues if you recently migrated DNS providers.
- For any self-hosted service, verify that certbot or your ACME client is running on a schedule and that renewal logs show recent success.
- Update certbot if it is below version 4.1.0 (released June 2025), which added ACME Renewal Information support for automatic schedule adjustment to shorter certificate lifetimes.
- Set up monitoring alerts at 30 days before expiration for every non-Vercel certificate.
- Run SSL Labs on every production domain. Fix any chain issues and cipher suite warnings.
- Add the HSTS header to your production deployments.
- Audit pages for mixed content warnings using Chrome DevTools.
- Remove or avoid certificate pinning unless you have a specific mobile security requirement and a key rotation strategy.
- Review your renewal automation to ensure it does not use hardcoded intervals -- these will break when certificate lifetimes drop below your assumed renewal schedule.
Ask The Guild
What is your current approach to certificate management? Are you relying on Vercel's automatic handling for everything, or do you have services outside that umbrella that need attention? Drop your setup in the comments -- especially if you have found a monitoring tool or automation pattern that has saved you from an expiry surprise.