/인프라/certbot renew Failure and NET::ERR_CERT_DATE_INVALID: A 30-Minute Recovery Guide
InfrastructureTLS인증서체인

certbot renew Failure and NET::ERR_CERT_DATE_INVALID: A 30-Minute Recovery Guide

Did certbot renew fail and leave your site stuck on NET::ERR_CERT_DATE_INVALID? Use the symptom-by-symptom diagnostic table for blocked port 80, webroot 404s, and rate limits, plus nginx/apache recovery commands and systemd/cron auto-renewa

certbot renew Failure and NET::ERR_CERT_DATE_INVALID: A 30-Minute Recovery Guide

certbot renew Failure and NET::ERR_CERT_DATE_INVALID: A 30-Minute Recovery Guide

If a site that was fine yesterday suddenly blocked users overnight with a red warning and NET::ERR_CERT_DATE_INVALID, your Let's Encrypt certificate almost certainly expired and auto-renewal had quietly died. Let's Encrypt certificates last 90 days; once cron or a systemd timer starts failing, expiry creeps up unnoticed until browsers tell your users first.

The good news is that most cases are recoverable in 30 minutes. This post assumes the site is down right now and leads with commands. First we pin the cause from symptoms, then copy-paste mode-specific recovery commands, then permanently revive auto-renewal.

1-minute emergency diagnosis: symptom → cause mapping table

Find the message from the browser or certbot renew output in the table below.

Visible error messageActual causeImmediate check commandRecovery section
NET::ERR_CERT_DATE_INVALID (browser)Certificate already expiredcertbot certificates
Timeout during connect (likely firewall problem)Port 80 blocked/firewallss -tlnp | grep :80
Connection refusedPort 80 not bound (web server down)systemctl status nginx
Failed authorization procedure ... 404webroot path errorCheck nginx root directive
DNS problem: NXDOMAIN looking up ADNS-01/record issuedig +short example.com
too many certificates already issued forRate limit exceeded(wait or staging)

First, check the current certificate status.

Bash
# certbot이 관리하는 인증서 목록과 만료일
certbot certificates

# 파일에서 직접 만료일 확인
openssl x509 -enddate -noout -in /etc/letsencrypt/live/example.com/fullchain.pem

# 실제 서비스 중인 인증서를 원격에서 확인
echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -dates

Detailed diagnosis and recovery for the five failure causes

① Port 80 blocked or occupied (Timeout during connect)

The HTTP-01 challenge arrives on port 80. You get a timeout if a firewall or cloud security group is blocking it, and refused if the web server is down.

Bash
ss -tlnp | grep :80        # 누가 80을 점유 중인가
ufw status                 # 방화벽 상태

If the web server is already using port 80 correctly, use webroot mode. If port 80 is free or standalone is simpler, stop the web server briefly and renew.

Bash
# standalone 모드: certbot이 직접 80을 임시 사용
systemctl stop nginx
certbot certonly --standalone -d example.com -d www.example.com
systemctl start nginx

② webroot path error (Failed authorization procedure ... 404)

If the -w path does not match nginx/apache's actual document root, the challenge file is not found and you get a 404. Check nginx root or apache DocumentRoot.

Bash
grep -R "root" /etc/nginx/sites-enabled/
certbot certonly --webroot -w /var/www/html -d example.com

③ DNS-01 validation failure

This happens with a wildcard (*.example.com) or a DNS challenge when the TXT record has not propagated or the A record is wrong.

Bash
dig +short example.com
dig +short TXT _acme-challenge.example.com

Fix the records, wait for propagation (TTL), then retry.

④ rate limit (too many certificates already issued for)

Let's Encrypt allows 5 duplicate certificates per week for the same registered domain set. Repeating --force-renewal during recovery easily hits it. If you are rate-limited, wait a week or finish validation against staging first.

Bash
# staging은 한도가 매우 넉넉하고, dry-run은 한도를 소모하지 않음
certbot renew --dry-run
certbot certonly --staging --standalone -d example.com

Key point: --dry-run does not consume the rate limit. Always confirm a dry-run pass before a production issuance.

⑤ Already expired certificate (NET::ERR_CERT_DATE_INVALID)

Expiry itself is the result of renewal being blocked by one of the causes above. Remove the cause, then force-renew.

Bash
certbot renew --force-renewal
systemctl reload nginx

Practical tip: During an overnight outage I once blindly ran --force-renewal first, hit the rate limit, and burned more time detouring through staging. The order is always dry-run → fix the cause → actual renewal.

nginx vs apache: what's different

Itemnginxapache
Auto-config plugin--nginx--apache
reload hooksystemctl reload nginxsystemctl reload apache2 (or httpd)
Default webroot locationserver { root ... }DocumentRoot

Using the plugin (--nginx/--apache) handles issuance, config, and reload in one shot. If you only obtained the certificate via webroot/standalone, you must reload yourself for it to take effect.

Permanently restoring auto-renewal: why cron died quietly

The usual reasons cron certbot auto-renewal stops working are three: ⓐ missing deploy-hook—renewal succeeded but reload never ran; ⓑ PATH issues in the cron environment so certbot isn't found; ⓒ snap vs apt path collision (/snap/bin/certbot vs /usr/bin/certbot).

The recommended install today is snap, which registers a systemd timer automatically. Check timer status first.

Bash
systemctl status certbot.timer
systemctl list-timers | grep certbot

If the timer is dead, enable it.

Bash
systemctl enable --now certbot.timer

If you use cron instead of a systemd timer, specify the absolute path and a deploy-hook.

Bash
# crontab -e
0 3 * * * /usr/bin/certbot renew --quiet --deploy-hook "systemctl reload nginx"

--deploy-hook runs only when an actual renewal happened, so you avoid unnecessary reloads. Always pre-validate after configuring.

Bash
certbot renew --dry-run

As of 2026, Let's Encrypt is pushing short-lived certificates (on the order of days), so the reliability of renewal automation matters more than ever. Alternatives like acme.sh exist, but certbot snap + systemd timer is enough for most production environments.

Conclusion: recovery checklist and preventing recurrence

  1. Check expiry with certbot certificates
  2. Identify the cause among the five using the symptom→cause table
  3. Renew with standalone/webroot mode; use --force-renewal if needed
  4. Restore automation with certbot.timer or cron + --deploy-hook
  5. Periodically run certbot renew --dry-run as a pre-check

Finally, set up 14-days-before-expiry alerts via monitoring (an external SSL expiry check or dry-run result notifications) so users never again discover the outage for you overnight.

Frequently Asked Questions (FAQ)

Q. Does running certbot renew --dry-run often hit the rate limit? A. No. dry-run uses the Let's Encrypt staging servers, so it does not consume the production issuance limit (5 duplicates per week). Feel free to run it as often as you like for checks.

Q. Renewal succeeded but the browser still shows the expired certificate. A. The web server did not reload the new certificate. Run systemctl reload nginx (or apache2/httpd) and add --deploy-hook to your automation.

Q. Should I use standalone or webroot? A. If the web server must keep occupying port 80 and zero downtime matters, use webroot. If port 80 is free or a brief stop is acceptable, standalone is simpler.

확인 정보
✦ ✦ ✦
편집 검토 · Editorial Review

Nodelog는 모든 콘텐츠의 내용과 출처를 공개 전에 검토합니다. 환경(OS·버전)에 따라 결과가 달라질 수 있는 기술 정보는 공식 문서와 함께 확인하며, 검토 기준과 정정 원칙은 편집 정책에서 안내합니다. 오류를 발견하시면 이메일로 제보해 주세요 — 확인 후 신속히 정정합니다.

편집 책임 · Nodelog 기술 편집팀·발행 · ·업데이트 ·

Comments

Be the first to comment.