인증서가 있는데도 HTTPS 접속이 안 될 때 — openssl로 원인 3가지 구분하기
브라우저에서 "이 사이트는 안전하지 않습니다"가 뜨거나, curl이 아무 응답 없이 실패할 때가 있습니다.
서버에 인증서가 없는 게 아니라 "엉뚱한 인증서"가 응답하는 경우가 많습니다.
원인은 대개 셋 중 하나이고, 명령어 한 줄로 구분됩니다.
결론부터
echo | openssl s_client -connect 도메인:443 -servername 도메인 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates
이 한 줄로 누구 이름의 인증서인지, 언제까지인지, 누가 발급했는지가 나옵니다.
| 증상 | subject 확인 결과 |
원인 |
|---|---|---|
| 만료 오류 | 내 도메인 이름은 맞는데 notAfter가 지났다 |
① 만료 |
| 이름 불일치 | 전혀 다른 이름이 나온다 | ② 이름 불일치 |
| 특정 기기만 오류 | subject는 맞는데 체인이 짧다 |
③ 중간 인증서 누락 |
-servername을 빼먹지 마세요
요즘 서버는 IP 하나에 사이트 여러 개를 올립니다. 그래서 접속할 때 "나는 이 이름으로 접속한다" 고 알려줘야 합니다. 이게 SNI이고, openssl에서는 -servername 옵션입니다.
# 잘못된 예 — SNI 없이 물어보면 서버 기본 인증서가 나온다
openssl s_client -connect example.com:443
# 올바른 예
openssl s_client -connect example.com:443 -servername example.com
이걸 빼면 엉뚱한 인증서를 보고 오진합니다.
① 만료
subject=CN = example.com
notAfter=Mar 30 23:59:59 2026 GMT ← 지났다
이름은 맞는데 날짜가 지난 경우입니다. 자동 갱신이 걸려 있다면 갱신이 실패한 이유를 봐야 합니다.
특히 CDN이나 프록시를 앞단에 붙이면, 인증서 발급 기관이 도메인 소유 확인을 못 해서 갱신이 조용히 실패하는 일이 있습니다. 발급 당시에는 멀쩡하니 만료일이 될 때까지 아무도 모릅니다.
만료일은 미리 확인해두는 게 좋습니다.
for h in a.example.com b.example.com c.example.com; do
printf "%-28s " "$h"
echo | openssl s_client -connect $h:443 -servername $h 2>/dev/null \
| openssl x509 -noout -enddate
done
② 이름 불일치 — 이게 가장 헷갈립니다
접속하려는 곳: example.com
받은 인증서: subject=O="어떤회사", CN=*.someother.com
서버에 인증서는 있습니다. 다만 내 도메인 이름이 아닙니다.
HTTPS는 "인증서가 있냐"가 아니라 "접속하려는 이름과 인증서의 이름이 일치하냐" 를 봅니다. 불일치면 연결 자체가 거부됩니다.
주로 이럴 때 생깁니다.
- 공유 인프라 서비스(포워딩·파킹 등)에 도메인을 연결했는데, 그쪽이 내 도메인 인증서를 발급해주지 않는 경우
- 서비스 연결을 해제했는데 DNS 레코드는 남아서, 그 서비스의 기본 와일드카드 인증서가 응답하는 경우
두 번째가 특히 함정입니다. *.어떤서비스.com 같은 와일드카드가 나오면 "이 도메인 전용 인증서가 발급되지 않은 상태" 라는 뜻입니다.
subject=CN = *.someservice.com ← 전용 인증서 없음. 연결 잔재
subject=CN = example.com ← 정상 발급됨
도메인 연결을 해제했더니 사이트가 죽었는데, 원인을 몰라 한참 헤맸습니다. openssl로 확인해보니 내 도메인 인증서가 아니라 그 서비스의 와일드카드 인증서가 응답하고 있었습니다. DNS 레코드는 그대로 남아 요청은 가는데, 받는 쪽에 연결된 게 없으니 기본 인증서가 나온 것이었습니다.
③ 중간 인증서 누락
subject도 맞고 날짜도 유효한데 특정 환경에서만 오류가 나면 이걸 의심합니다.
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
| grep -A5 'Certificate chain'
체인이 서버 인증서 하나만 나오고 중간 인증서가 없으면, 그걸 캐시해둔 브라우저에서는 되고 없는 곳(모바일·서버·curl)에서는 실패합니다. 서버 설정에서 전체 체인을 함께 내보내야 합니다.
검증 켜고 끄고 비교하기
curl에서 -k를 붙이면 인증서 검증을 건너뜁니다. 붙였을 때와 안 붙였을 때를 비교하면 원인이 인증서인지 아닌지 바로 나옵니다.
curl -s -o /dev/null -w '%{http_code}\n' https://example.com/ # 검증 ON
curl -sk -o /dev/null -w '%{http_code}\n' https://example.com/ # 검증 OFF
- 검증 OFF에서 200, ON에서 000 → 인증서 문제 확정
- 둘 다 000 → 인증서가 아니라 연결·방화벽·DNS 문제
여기서 000은 HTTP 상태 코드가 아니라 "응답을 받지 못했다" 는 뜻입니다.
오류 원문을 보려면 이렇게 합니다.
curl -v https://example.com/ 2>&1 >/dev/null | grep -iE 'certificate|SSL|verify'
정리
-servername을 반드시 붙이세요.subject가 내 도메인 이름인지부터 확인합니다- 와일드카드(
*.서비스명)가 나오면 전용 인증서 미발급 상태입니다 -k붙였을 때와 뺐을 때를 비교하면 인증서 문제인지 아닌지 바로 판별 가능합니다- 만료일은 미리 확인해두세요. 만료 당일에 알면 이미 늦습니다