D-4 판정 — 갱신은 성공했고, 38분 25초 동안 반영되지 않았다 (시계 보정 후. 처음 적은 36분 39초는 서로 다른 시계를 뺀 값이었다) ============================================================= 수집: 2026-09-04 · 감시 08:10:51 ~ 09:02 UTC (KST-9) ════ 답 1 — "갱신 실패"가 아니라 "갱신됐는데 안 집었다" ════ 07-renewal-hook-missing.txt 에서 두 갈래로 남겼던 것이 갈렸다. (a) 강제 갱신이 실패했다 (b) 성공했는데 훅이 없어 reload 가 안 됐다 → ★ (b) 였다. 디스크 (12-certbot-state.txt) /etc/letsencrypt/archive/auth.hyeonworks.com/ cert1.pem 2026-09-03 10:47:40 KST ← 처음 발급 cert2.pem 2026-09-04 17:22:13 KST ← ★ 강제 갱신, 새로 써졌다 fullchain2.pem 2026-09-04 17:22:13 KST privkey2.pem 2026-09-04 17:22:13 KST Certificate Name: auth.hyeonworks.com Serial Number: 6c7cb6df1da8a6d7995d93c264bb9ecea1d Expiry Date: 2026-12-03 07:21:52+00:00 (VALID: 89 days) 밖에서 본 것 (09-serial-timeline.txt, 5초 간격 564표본) 08:10:51 ~ 08:58:47 serial=0520BB...B853 notAfter=Dec 2 ← 옛 것 08:58:52 serial=06C7CB...EA1D notAfter=Dec 3 ← 바뀐 순간 08:22:13 ~ 08:58:52 구간에서 옛 인증서로 관측된 횟수: 428회 시간 계산 새 인증서 디스크 기록 : 08:22:13 UTC (= 17:22:13 KST, archive mtime) 실제 서빙 시작 : 08:58:52 UTC (= 17:58:52 KST, nginx -s reload) ──────────────────────────────────────────── 공백 : 2305초 = 38분 25초 ← test-server 가 106초 빠른 것을 보정한 값 (보정 전 2199초로 적었던 것을 정정. D-4a 참조) 그리고 이 36분은 **우연히 짧았을 뿐이다.** reload 를 시킨 것은 사람이지 자동화가 아니다. 아무도 안 했다면 다음 nginx 재시작까지 — 즉 무기한 — 옛 인증서를 계속 서빙했을 것이다. 왜 아무도 reload 하지 않았나 — 원인 세 가지가 겹쳤다 1. certbot-renew.service 에 ExecStartPost 가 없다 (07 참조) 2. /etc/letsencrypt/renewal-hooks/{deploy,post,pre}/ 가 전부 비어 있다 deploy/ total 8 (. 과 .. 뿐) post/ total 8 pre/ total 8 3. certbot 에 nginx 플러그인이 없다 — 그래서 certbot 이 스스로 못 고친다 Discovered plugins: dns-cloudflare, manual, null, standalone, webroot (certbot 5.7.0) ★ 세 경로 전부가 비어 있다. 하나라도 있었으면 자동으로 반영됐다. 왜 이게 88일 동안 안 보이나 타이머는 정상이고 오늘도 두 번 status=0/SUCCESS 로 끝났다. 만료 30일 전(= 약 58일 뒤)까지는 certbot 이 갱신 자체를 하지 않으므로 "반영되지 않는다"는 결함이 발현할 기회가 없다. 발현하는 날 증상은 **인증서 만료** 이고, 그때 로그는 여전히 SUCCESS 라고 적혀 있을 것이다. ════ 답 2 — reload 는 무중단이다 (측정됨) ════ 계획서의 질문: "nginx reload 중 진행 중이던 요청은 어떻게 되는가" [새 연결] 0.2초 폴링, 08:10:51 ~ 09:02 전체 표본 8856건 / 비200 **0건** 응답시간 n 중앙 p95 최대 ───────────────────────────────────────────────────────── 장기 평시 08:20~08:50 5398 98.0ms 205.7ms 1942.9ms reload 직전 2분56초 489 116.0ms 200.8ms 387.7ms reload 직후 2분08초 342 132.5ms 204.3ms 475.0ms p95 가 205.7 → 204.3 으로 사실상 동일하고, 최대값은 오히려 낮다. 10초 구간 중앙값은 reload 전후 모두 80~190ms 사이를 오간다(WiFi 잡음). → **reload 로 인한 지연 증가는 관측되지 않았다.** [진행 중이던 요청] 845KB 를 20k/s 로 받아 42초간 살려 둔 요청 08:58:40 시작 · 소요 40.84초 → 08:59:21 종료 reload 는 08:58:52, 즉 **요청 시작 12초 뒤 전송 한가운데**였다 코드=200 바이트=845361(전량) 연결수=1 curl종료=0 · 바이트가 전량이다 → 잘리지 않았다 · 연결수가 1이다 → 중간에 끊겨 재연결한 것이 아니다 · 옛 인증서로 시작한 연결이 새 워커 전환을 관통해 끝까지 갔다 in-flight 전체 50건 중 종료코드≠0 은 0건. (앞서 76건 실패는 로컬 아티팩트였다 — 08-inflight-artifact.txt) ════ 세 줄 요약 ════ 1. **"갱신 성공"과 "새 인증서 서빙"은 다른 사건이다.** 38분 25초 동안 디스크에는 새 인증서가, 네트워크에는 옛 인증서가 있었다. 428번 관측했다. 2. **reload 는 정말 무중단이었다.** 8856건 전부 200, p95 변화 없음, 전송 한가운데였던 42초짜리 요청이 845361바이트를 온전히 받았다. D-4 문서가 "확인하지 않았으므로 그렇게 쓰면 안 된다"고 유보했던 명제가 이제 측정으로 뒷받침된다. 3. **위험한 쪽은 reload 가 아니라 reload 를 부르는 사람이 없다는 것이다.** 훅 디렉터리 3개가 전부 비었고, 유닛에 ExecStartPost 가 없고, nginx 플러그인도 없다. 그리고 그 상태로 타이머는 SUCCESS 를 찍는다.