/인프라/certbot renew 실패·NET::ERR_CERT_DATE_INVALID 30분 복구 가이드
인프라TLS인증서체인

certbot renew 실패·NET::ERR_CERT_DATE_INVALID 30분 복구 가이드

certbot renew 실패와 NET::ERR_CERT_DATE_INVALID로 사이트가 멈췄나요? 80포트 차단·webroot 404·rate limit 등 증상별 진단표와 nginx/apache 복구 명령, systemd·cron 자동갱신까지 복붙으로 해결합니다.

certbot renew 실패·NET::ERR_CERT_DATE_INVALID 30분 복구 가이드

certbot renew 실패와 NET::ERR_CERT_DATE_INVALID 30분 복구 가이드

어제까지 멀쩡하던 사이트가 새벽에 NET::ERR_CERT_DATE_INVALID를 띄우며 빨간 경고 화면으로 막혔다면, 십중팔구 Let's Encrypt 인증서가 만료됐고 자동 갱신이 조용히 죽어 있던 겁니다. Let's Encrypt 인증서 수명은 90일인데, cron이나 systemd timer가 어느 시점부터 갱신에 실패하면 아무도 모르는 사이 만료일이 다가오고, 결국 사용자 브라우저가 먼저 알려줍니다.

좋은 소식은 대부분의 경우 30분 안에 복구 가능하다는 점입니다. 이 글은 "지금 사이트가 죽어 있다"는 전제로 명령어부터 던집니다. 먼저 증상으로 원인을 특정하고, 모드별 복구 명령을 복붙한 뒤, 자동 갱신을 영구히 되살리는 순서로 갑니다.

1분 응급 진단: 증상 → 원인 매핑표

브라우저나 certbot renew 출력에 뜬 문구를 아래 표에서 찾으세요.

보이는 에러 문구실제 원인즉시 확인 명령복구 섹션
NET::ERR_CERT_DATE_INVALID (브라우저)인증서 이미 만료certbot certificates
Timeout during connect (likely firewall problem)80 포트 차단/방화벽ss -tlnp | grep :80
Connection refused80 포트 미점유(웹서버 다운)systemctl status nginx
Failed authorization procedure ... 404webroot 경로 오류nginx root 디렉티브 확인
DNS problem: NXDOMAIN looking up ADNS-01/레코드 문제dig +short example.com
too many certificates already issued forrate limit 초과(대기 또는 staging)

현재 인증서 상태를 먼저 확인합니다.

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

5대 실패 원인별 정밀 진단과 복구

① 80 포트 차단/점유 (Timeout during connect)

HTTP-01 챌린지는 80 포트로 들어옵니다. 방화벽이나 클라우드 보안그룹이 막고 있으면 timeout, 웹서버가 죽었으면 refused가 뜹니다.

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

웹서버가 이미 80을 잘 쓰고 있다면 webroot 모드를, 80이 비어 있거나 standalone이 편하면 잠시 웹서버를 내리고 갱신합니다.

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

② webroot 경로 오류 (Failed authorization procedure ... 404)

-w 경로와 실제 nginx/apache의 문서 루트가 다르면 챌린지 파일을 못 찾아 404가 납니다. nginx는 root, apache는 DocumentRoot 값을 확인하세요.

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

③ DNS-01 검증 실패

와일드카드(*.example.com)나 DNS 챌린지를 쓸 때 TXT 레코드 전파가 안 됐거나 A 레코드가 잘못된 경우입니다.

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

레코드를 수정하고 전파(TTL)를 기다린 뒤 재시도합니다.

④ rate limit (too many certificates already issued for)

Let's Encrypt는 동일 등록 도메인 세트 기준 주당 5개의 중복 인증서 한도가 있습니다. 복구 중 --force-renewal을 반복하다 보면 쉽게 걸립니다. 한도에 걸렸다면 일주일을 기다리거나 staging 환경으로 검증만 먼저 끝냅니다.

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

핵심: --dry-run은 rate limit를 소모하지 않습니다. 실전 발급 전에 항상 dry-run으로 통과 여부부터 확인하세요.

⑤ 이미 만료된 인증서 (NET::ERR_CERT_DATE_INVALID)

만료 자체는 위 원인 중 하나로 갱신이 막혀 발생한 결과입니다. 원인을 제거한 뒤 강제 갱신합니다.

Bash
certbot renew --force-renewal
systemctl reload nginx

실무 팁: 저는 새벽 장애 때 무작정 --force-renewal부터 치다가 rate limit에 걸려 staging으로 우회하느라 시간을 더 버린 적이 있습니다. 순서는 항상 dry-run → 원인 제거 → 실제 갱신입니다.

nginx vs apache: 무엇이 다른가

항목nginxapache
자동 설정 플러그인--nginx--apache
reload 훅systemctl reload nginxsystemctl reload apache2(혹은 httpd)
기본 webroot 위치server { root ... }DocumentRoot

플러그인(--nginx/--apache)을 쓰면 인증 + 설정 반영 + reload까지 한 번에 처리합니다. webroot/standalone으로 인증서만 받았다면 reload는 직접 해줘야 적용됩니다.

자동 갱신 영구 복구: cron이 조용히 죽은 이유

cron certbot 자동갱신 안됨의 단골 원인은 세 가지입니다. ⓐ deploy-hook 누락으로 갱신은 됐지만 reload가 안 됨, ⓑ cron 환경의 PATH 문제로 certbot을 못 찾음, ⓒ snap과 apt 경로 충돌(/snap/bin/certbot vs /usr/bin/certbot).

요즘 권장 설치는 snap이고, 설치 시 systemd timer가 자동 등록됩니다. 먼저 timer 상태부터 확인하세요.

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

timer가 죽어 있으면 활성화합니다.

Bash
systemctl enable --now certbot.timer

systemd timer 대신 cron을 직접 쓰려면, 절대 경로와 deploy-hook을 명시하세요.

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

--deploy-hook실제 갱신이 일어났을 때만 실행되므로 불필요한 reload를 피할 수 있습니다. 설정 후 반드시 사전 검증하세요.

Bash
certbot renew --dry-run

2026년 현재 Let's Encrypt는 단기 인증서(수일 단위) 도입을 추진 중이라, 갱신 자동화의 안정성은 점점 더 중요해지고 있습니다. acme.sh 같은 대안도 있지만, certbot snap + systemd timer 조합이면 대부분의 운영 환경에서 충분합니다.

결론: 복구 체크리스트와 재발 방지

  1. certbot certificates로 만료 여부 확인
  2. 증상→원인 표로 5대 원인 특정
  3. standalone/webroot 모드로 갱신, 필요 시 --force-renewal
  4. certbot.timer 또는 cron + --deploy-hook으로 자동화 복구
  5. certbot renew --dry-run을 주기적으로 돌려 사전 점검

마지막으로 만료 14일 전 알림을 모니터링(외부 SSL 만료 체크 또는 dry-run 결과 알림)으로 걸어두면, 다시는 새벽에 사용자가 먼저 장애를 알려주는 일은 없습니다.

자주 묻는 질문 (FAQ)

Q. certbot renew --dry-run을 자주 돌리면 rate limit에 걸리나요? A. 아니요. dry-run은 Let's Encrypt staging 서버를 사용하므로 실제 발급 한도(주당 중복 5개)를 소모하지 않습니다. 점검용으로 마음껏 돌려도 됩니다.

Q. 갱신은 성공했다는데 브라우저는 여전히 만료된 인증서를 보여줍니다. A. 웹서버가 새 인증서를 reload하지 않았기 때문입니다. systemctl reload nginx(또는 apache2/httpd)를 실행하고, 자동화에는 --deploy-hook을 추가하세요.

Q. standalone과 webroot 중 무엇을 써야 하나요? A. 80 포트를 웹서버가 계속 점유 중이고 무중단이 중요하면 webroot, 80이 비었거나 잠깐 멈춰도 되면 standalone이 간편합니다.

✦ ✦ ✦
편집 검토 · Editorial Review

이 글은 AI 에이전트가 자료 조사와 1차 초안 작성을 담당하고, 사람 편집자가 사실관계·출처·톤과 맥락을 검토한 뒤 발행했습니다. 환경(OS·버전)에 따라 결과가 다를 수 있으니 적용 전 공식 문서를 함께 확인하세요. 오류를 발견하시면 이메일로 제보해 주세요 — 확인 후 신속히 정정합니다.

초안 · AI (Content Reviewer)·검토 · Nodelog 편집자·발행 ·
관련 공식 문서OpenSSL 공식 문서

댓글

첫 번째 댓글을 남겨보세요.