내멋스레 사는 이야기
개발 트러블슈팅 완전 정복 | 웹개발·백엔드·데브옵스 실무 에러 해결법. Docker, GitHub Actions, TypeScript, MySQL, Redis 등 실전 경험 기반의 개발 블로그
목요일
수요일
Nginx SSL 인증서 만료 해결법
🔍 검색 키워드: Nginx SSL 인증서 만료, Let's Encrypt 갱신, TLS 에러, HTTPS 연결 실패, 인증서 업데이트
Nginx SSL 인증서 만료 해결법
증상
브라우저에서 HTTPS 사이트 접속 시:
NET::ERR_CERT_AUTHORITY_INVALID
ERR_SSL_OBSOLETE_VERSION
The certificate has expired
SSL_ERROR_HANDSHAKE_FAILURE_ALERT
또는 서버 로그에:
SSL_ERROR_RX_RECORD_TOO_LONG
no shared ciphers
Peer rejected a valid certificate
certificate verify failed (self signed certificate)
cURL로 확인 시:
$ curl -v https://example.com
* SSL certificate problem: certificate has expired
원인
- 인증서 만료: Let's Encrypt 90일 정책, 또는 상용 인증서 만료
- 자동 갱신 미작동: certbot/Nginx 플러그인 설정 오류
- Nginx 설정 오류: 잘못된 인증서 경로
- 시스템 시간 오류: 서버 시계가 실시간과 다름
- 인증서 체인 미완성: 중간 인증서(Intermediate) 누락
- 포트 443 차단: Let's Encrypt 갱신 포트 막힘
- 권한 오류: 인증서 파일 읽기 권한 부족
해결 방법
방법 1: 현재 인증서 상태 확인
# 인증서 만료 기간 확인
openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem \
-noout -dates
# 출력 예:
# notBefore=Jun 4 12:00:00 2024 GMT
# notAfter=Sep 2 12:00:00 2024 GMT
# SSL 프로토콜 버전 확인
openssl s_client -connect example.com:443 -tls1_2
# 인증서 체인 확인
openssl s_client -connect example.com:443 -showcerts
# 남은 기간 확인 (일 수)
ssl-cert-check -c /etc/letsencrypt/live/example.com/cert.pem
# Nginx 설정에서 인증서 경로 확인
grep "ssl_certificate" /etc/nginx/sites-enabled/default
방법 2: Let's Encrypt 인증서 자동 갱신
# 1. certbot 설치 (미설치 시)
sudo apt-get install certbot python3-certbot-nginx
# 2. 인증서 수동 갱신
sudo certbot renew
# 3. 특정 도메인만 갱신
sudo certbot renew --cert-name example.com
# 4. 강제 갱신 (만료 60일 전이 아니라도)
sudo certbot renew --force-renewal
# 5. 갱신 후 Nginx 재로드
sudo systemctl reload nginx
# 6. Nginx 설정 테스트
sudo nginx -t
자동 갱신 설정 (cron 또는 systemd):
# crontab 설정 (매일 오전 3시 확인)
sudo crontab -e
# 다음 라인 추가:
0 3 * * * /usr/bin/certbot renew --quiet && systemctl reload nginx
# 또는 systemd timer (권장)
sudo systemctl list-timers certbot
sudo systemctl status certbot.timer
방법 3: Nginx 설정 확인 및 수정
server {
listen 443 ssl http2;
server_name example.com www.example.com;
# SSL 인증서 경로 확인
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# TLS 버전 명시 (TLS 1.2 이상)
ssl_protocols TLSv1.2 TLSv1.3;
# 최신 암호화 알고리즘
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
ssl_prefer_server_ciphers on;
# HSTS 설정 (선택사항)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# 설정 테스트
# $ sudo nginx -t
# nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
# nginx: configuration file /etc/nginx/nginx.conf test is successful
}
# HTTP → HTTPS 리다이렉트
server {
listen 80;
server_name example.com www.example.com;
location / {
return 301 https://$host$request_uri;
}
}
설정 적용:
sudo nginx -t
sudo systemctl reload nginx
방법 4: 새 인증서 발급 (기존 만료된 경우)
# 1. certbot 대화형 모드로 새 인증서 발급
sudo certbot certonly --nginx -d example.com -d www.example.com
# 2. 수동 DNS 검증 방식
sudo certbot certonly --manual --preferred-challenges dns \
-d example.com -d www.example.com
# DNS TXT 레코드 추가 후 엔터
# 3. 발급된 인증서 확인
sudo ls -la /etc/letsencrypt/live/example.com/
방법 5: 시스템 시간 확인 및 수정
# 시스템 시간 확인
date
# 시간이 틀렸다면 수정
sudo timedatectl set-ntp true # NTP 자동 동기화
sudo timedatectl set-timezone Asia/Seoul
# 수정 확인
date
timedatectl
# 시간 동기화 강제 실행
sudo ntpdate -s ntp.ubuntu.com
방법 6: SSL 점검 및 모니터링
# SSL Labs 온라인 테스트 (브라우저에서)
# https://www.ssllabs.com/ssltest/analyze.html?d=example.com
# 로컬에서 SSL 테스트
sudo apt-get install sslscan
sslscan --no-failed example.com:443
# 인증서 투명성 로그 확인
curl https://ct.googleapis.com/log/all_logs_list.json
# Nginx 에러 로그 확인
sudo tail -f /var/log/nginx/error.log
# Certbot 갱신 로그 확인
sudo tail -f /var/log/letsencrypt/letsencrypt.log
정리표
| 에러 메시지 | 원인 | 해결법 |
|---|---|---|
| certificate has expired | 인증서 만료 | certbot renew 실행 |
| SSL_ERROR_HANDSHAKE_FAILURE_ALERT | TLS 설정 오류 | Nginx SSL 설정 확인 |
| no shared ciphers | 암호화 불일치 | ssl_ciphers 최신 버전 설정 |
| certificate verify failed | 인증서 체인 누락 | fullchain.pem 사용 확인 |
| ERR_SSL_OBSOLETE_VERSION | 구버전 TLS | TLS 1.2 이상으로 설정 |
팁: Let's Encrypt는 90일마다 갱신이 필요합니다. certbot renew --dry-run으로 자동 갱신을 사전 테스트하고, 갱신 후 systemctl reload nginx로 무중단 재로드하세요. Nginx 재시작 시 기존 연결은 유지되므로 서비스 중단이 없습니다.
피드 구독하기:
글 (Atom)