A Let's Encrypt certificate renews itself every sixty days without anyone noticing - until a change made months earlier blocks the validation. The failure is silent; the first sign is usually a browser warning.

See the real expiry

echo | openssl s_client -servername yourdomain.com -connect yourdomain.com:443 2>/dev/null | openssl x509 -noout -dates

The three blockers

  • A redirect that catches the validation request. The check is a plain HTTP request to /.well-known/acme-challenge/. A blanket http-to-https rule that also redirects that path breaks it.
  • The DNS record moved. The domain now points somewhere else, so the check reaches a server that has never heard of the challenge.
  • A firewall or a WAF blocking port 80. Closing 80 because "everything is https now" closes the door renewal comes through.

Let the challenge through

location ^~ /.well-known/acme-challenge/ {
    root /var/www/html;
    try_files  =404;
}

That block goes before the redirect rule, so the challenge is answered and everything else still goes to https.

Force one renewal and watch it

certbot renew --dry-run

The dry run does the whole exchange without spending a rate limit. If it passes, the real one will.

Let's Encrypt rate-limits repeated failures. Fix the cause and use --dry-run to test; retrying the real command in a loop will lock you out for hours.
On EGPHP hosting renewal is handled for you and this page is for a VPS you run yourself. If a managed certificate ever shows a warning, it is a support ticket, not a config change.