카테고리 없음

인증서가 있는데도 HTTPS 접속이 안 될 때 — openssl로 원인 3가지 구분하기

바뿌 2026. 9. 28. 00:36

브라우저에서 "이 사이트는 안전하지 않습니다"가 뜨거나, 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 붙였을 때와 뺐을 때를 비교하면 인증서 문제인지 아닌지 바로 판별 가능합니다
  • 만료일은 미리 확인해두세요. 만료 당일에 알면 이미 늦습니다