Skip to content
ssldays

Guide

Nginx SSL certificate expired

Fix nginx ssl certificate expired errors—confirm live TLS, renew PEMs, align ssl_certificate paths, nginx -t and reload, and verify serial from outside the cluster.

Updated May 23, 2026 801 words

nginx ssl certificate expired means workers still present a leaf past notAfter on port 443 or your stream listener—renew files on disk, reload nginx, and prove the new serial on the public hostname.

Nginx and OpenResty terminate TLS for static sites, API gateways, Kubernetes ingress controllers, and TCP proxies. nginx ssl certificate expired hits mobile apps, curl pipelines, and browsers with certificate has expired while on-call engineers sometimes only notice when Grafana SSL probes fail.

Teams often renew certbot lineages successfully but skip nginx -s reload, leaving mmap’d certificates in worker processes. Others edit ssl_certificate paths in the wrong server block so only the default_server cert refreshed while customer hostnames remain stale.

This guide follows confirm on the wire, renew, align configuration paths, test and reload, and external validation. See Nginx certificate paths when multiple fullchain locations confuse triage, and Certbot renew failed when timers fail before expiry week.

What to check

Validate the hostname users type, including apex versus www and regional subdomains. CDNs and ingress controllers may front nginx—openssl should target the same DNS name clients resolve.

For nginx ssl certificate expired, compare serial from openssl s_client against the PEM referenced in the active server or stream block. nginx -T dumps effective config; do not trust an old nginx.conf snippet in a wiki.

Distinguish HTTP TLS server blocks from stream proxy_pass TLS on non-443 ports. Renewing HTTP fullchain does not update stream certificates.

Check whether Kubernetes ingress owns the public cert while nginx inside the cluster serves plain HTTP—fix the correct tier.

Step-by-step

Live expiry probe

HOST=api.example.com
echo | openssl s_client -connect "${HOST}:443" -servername "${HOST}" 2>/dev/null \
  | openssl x509 -noout -dates -serial -issuer -subject

Dump effective ssl_certificate paths

nginx -T 2>/dev/null | grep -E "server_name|ssl_certificate"

Match server_name entries to the failing HOST before editing files.

Inspect referenced PEM

openssl x509 -in /etc/letsencrypt/live/HOST/fullchain.pem -noout -dates -serial

Use the path nginx -T reported, not a default guess.

Renew

certbot renew --dry-run
certbot renew

Resolve ACME errors before emergency cert purchases. Webroot and DNS plugins each have distinct failure modes documented in Certbot renew failed troubleshooting.

Test and reload

nginx -t && nginx -s reload

Automate with deploy hooks as described in reload nginx after SSL renewal and reload nginx after Certbot renew.

External verification

Re-run openssl; accept when notAfter advanced and serial differs from the incident capture.

Log rotation friendly evidence

Save nginx error.log excerpts around reload time showing SSL_CTX loads without permission errors. Support bridges run smoother when application teams see proof the edge tier reloaded, not only that certbot email claimed victory.

How to read the output

notAfter on the served leaf is the user-visible expiry. serial changes on re-issuance; unchanged serial after renew suggests reload gap or wrong server block.

issuer and subject confirm CA and name coverage. stream and mail proxy TLS use the same x509 fields but different nginx contexts.

nginx -t success only means syntax is valid—reload still required to load new file contents into workers.

Common mistakes

Certbot updated live symlinks but nobody signaled the master process inside Docker—reload the container or sidecar that actually binds 443.

Multiple nginx packages on one host; hooks reload distribution nginx while customers hit vendor nginx binaries.

Using ssl_certificate with cert.pem missing intermediate chain—some clients fail trust while others show only expiry if an old chain happened to validate.

IPv6 AAAA records point at another machine still serving expired material while IPv4 looks fine.

Ingress annotation mismatches leaving one hostname on an old secret in Kubernetes even after host renew.

Ansible copy tasks skip notify handlers when file checksum unchanged though certbot rotated symlink targets upstream.

Microservice meshes sometimes terminate mTLS inside the cluster while edge nginx still presents a separate public leaf. Incidents labeled nginx ssl may involve only the ingress chart values while application pods use an independent CA—validate both tiers from client perspectives that match real user traffic.

Rate limiting during ACME HTTP-01 can block legitimate renew attempts while serving expired certs to everyone else. correlate letsencrypt.log timestamps with WAF block logs when renew fails at the same hour nginx still serves stale dates.

Blue and green deploys that share a certificate volume require reload on both colors when keepalived promotes passive nodes without running deploy hooks. Document which color received renew hooks last.

lua-resty-auto-ssl and similar modules maintain their own path caches. Standard certbot renew plus nginx reload may be insufficient—consult module docs for memory flush steps unique to those stacks.

Geographic anycast may present different serials per POP if a partial config push succeeded only in one region. Run openssl against multiple resolver vantage points when global complaints exceed single-site suspicion.

When to use automation

PEM mtimes lie. ssldays reads live TLS on your hostname—issuer, SANs, chain trust, expiry—from outside your VPC.

Schedule monitoring with 30, 14, 7, and 1 day thresholds per renewal cycle. Email on all plans; Slack and Discord webhooks on Starter and Pro. Free tier: 3 domains, daily; Starter 25, hourly; Pro 100, hourly. Add RDAP registrar dates where published. Move production hosts to /register after you fix nginx ssl certificate expired so the next cycle pages early.

Frequently asked questions

OpenResty differences?

Reload semantics match nginx; use the openresty binary path in hooks consistent with production.

HTTP/3 or QUIC?

QUIC cert material often follows the same files as TLS 1.2; validate all protocols your clients use after reload.

Wildcard on one block?

Ensure each server_name using the wildcard path actually points ssl_certificate at the renewed fullchain.

Buy two-year cert to skip nginx work?

Longer validity does not remove reload requirements when you eventually replace files—fix process first.

Monitor this hostname on a schedule

Live certificate checks and renewal reminders — not guesswork from PEM files.