Spring Boot + Nginx + Let’s Encrypt 환경에서 실제로 겪은 장애 복구 기록
1. 갑자기 서비스가 모두 안됐다
외주 개발을 완료한지 6개월이 지난 지금, 고객사에서 연락이 왔다.
저희 홈페이지 관리자 로그인이 안돼요 ㅠㅠ
홈페이지도 안들어가져요...
확인 한번 부탁드립니다!
홈페이지 확인을 해보니 데이터가 undefined로 내려오고 있고, 관리자 페이지 로그인도 500에러로 뜨고 있었다.
처음엔 이렇게 생각했다.
- DB가 죽었나?
- 서버가 내려갔나?
- 배포를 잘못했었나?
근데 이상한 점이 하나 있었다.
2. 서버에 들어가보니... 다 살아있다?
배포되어있는 AWS EC2에 접속해서 확인해봤다.
ps -ef | grep app.jar

백엔드 살아있음
sudo ss -lntp | grep java

포트도 정상
curl -i http://127.0.0.1:8080/actuator/health
헬스체크도 정상 (이건 구현안되어있으면 프론트에서 호출하는 컨트롤러 URL로 체크)
👉 DB도, 서버도, 백엔드도 멀쩡한데 서비스는 안 된다?
여기서부터 "외부에서 들어오는 경로"를 의심했다.
3. 프론트에서 호출하는 서버 API 주소로 확인해봤다
서버에서 직접 호출해봤다.
curl -i https://(api URL)/actuator/health
하하... 범인을 찾았다.
나온 에러는 다음과 같다 👇 (해결 완료 후 글 작성하는거라 기간 만료 에러 캡처 못함)
curl: (60) SSL certificate problem: certificate has expired
More details here: https://curl.se/docs/sslcerts.html
curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation
and how to fix it, please visit the webpage mentioned above.
4. 원인은 SSL 인증서 완료였다
일단 Nginx 설정 파일에서 인증서 위치 확인
sudo nginx -T | grep ssl_certificate

인증서 상태를 직접 확인해봤다
sudo openssl x509 -in /etc/letsencrypt/live/(api URL)/fullchain.pem -noout -dates
결과 👇

👉 이미 만료됨 (캡처는 새로 갱신한거임)
이 한 줄로 모든 증상이 설명됐다.
왜 이렇게 보였냐면
- HTTPS 인증서 만료
- 브라우저에서 API 요청 자체 차단
- 프론트에서 데이터 전부 못 받음
- 배열이 비어서 undefined 에러 발생
- 결과적으로 “서비스 전체가 죽은 것처럼” 보임
백엔드는 사실 아무 잘못도 없었다.
💡여기서 잠깐
장애는 서버/DB 문제보다 인증서 만료가 더 무섭다
내부 테스트는 다 정상인데, 실제 사용자만 다 막히기 때문이다.
5. 해결 방법 : 인증서 갱신 + Nginx 재시작
이 서버는 Nginx + Let’s Encrypt(Certbot) 구조다.
1️⃣ 인증서 갱신
sudo certbot renew
성공 시 :
Congratulations, all renewals succeeded.
2️⃣ Nginx 재시작 (중요)
sudo systemctl reload nginx
# 또는
sudo systemctl restart nginx
3️⃣ 다시 확인
curl -i https://(api URL)/actuator/health
프론트 새로고침 → 모든 데이터 정상 복구
6. 재발 방지: 자동 갱신 설정 꼭 확인하자
이 장애의 진짜 원인은
👉 Certbot 자동 갱신이 안 되어 있었던 것
타이머 확인
sudo systemctl list-timers | grep certbot
없다면 바로 추가 :
sudo systemctl enable certbot-renew.timer
sudo systemctl start certbot-renew.timer
이제 90일마다 자동 갱신된다.
7. 정리하면서 느낀점
이번 장애에서 제일 무서웠던 점은 이거였다.
- 서버 정상
- DB 정상
- 로그에 에러 없음
- 헬스체크 OK
그런데 서비스는 완전히 죽어 보인다.
그래서 앞으로 이런 증상이 나오면 나는 무조건 이 순서로 본다.
- 서버 프로세스
- 내부 헬스체크
- 외부 HTTPS 호출
- SSL 인증서 만료 여부
8. 같은 환경이라면 꼭 체크해보자
- EC2 + Spring Boot
- Nginx 리버스 프록시
- Let’s Encrypt 사용 중
- “배포 안 했는데 갑자기 서비스 장애”
👉 이 조합이면 인증서 만료부터 의심하는 게 정답이다.
마무리
이번 건은 “서버가 죽은 게 아니라, 입구가 닫혀 있었던 상황” 이었다.
혹시 나처럼 서버는 멀쩡한데 서비스가 전부 안 될 때 이 글이 도움이 됐으면 좋겠다.
'웹 개발 > Spring&JPA' 카테고리의 다른 글
| [리팩토링] OpenFeign으로 외부 API 호출 리팩토링한 기록 (Resilience4j 적용) (0) | 2025.04.06 |
|---|---|
| [트러블슈팅] Spring @Conditional 사용 시 PostConstruct로 빈 등록 실패한 이유 (1) | 2025.04.05 |
| [트러블슈팅] PostgreSQL 한글 정렬 안 되는 문제 해결 (Collation 설정) (0) | 2025.02.04 |
| [Spring Data JPA] 영속성 컨텍스트(Persistence Context)와 엔티티 생명주기 (0) | 2024.08.30 |
| [Spring Boot 3] P6Spy SQL 로그 포맷 커스터마이징 및 파일 로그 설정 (0) | 2024.08.29 |