526 에러가 뜻하는 것

Cloudflare를 앞에 두면 HTTPS 요청은 두 구간으로 나뉩니다. 방문자의 브라우저에서 Cloudflare까지, 그리고 Cloudflare에서 내 서버(원 서버, origin)까지입니다. 구간마다 인증서가 따로 있습니다.

526 에러 “Invalid SSL certificate”는 두 번째 구간의 문제이고, SSL/TLS 모드가 Full (strict)일 때만 납니다. Cloudflare가 원 서버에 연결했고 TLS 핸드셰이크도 끝났는데, 원 서버가 내민 인증서를 검사해 보니 받아 줄 수 없었다는 뜻입니다. strict 모드에서 원 서버 인증서는 다음을 만족해야 합니다.

  • 만료되지 않았을 것
  • 공인 CA나 Cloudflare Origin CA가 발급했을 것
  • 호스트명에 맞을 것. 방문자가 요청한 호스트명이나, 프록시된 CNAME이라면 그 대상 호스트명입니다.

하나라도 어긋나면 Cloudflare는 요청을 넘기지 않고 526을 보여 줍니다. 사설 CA 인증서를 쓰는 원 서버를 위해 Cloudflare가 Custom Origin Trust Store라는 기능도 제공하지만, 기대기 전에 내 요금제에 포함돼 있는지 확인하세요.

방문자 쪽 구간은 영향이 없습니다. 브라우저와 Cloudflare의 연결은 Cloudflare 엣지 인증서를 쓰기 때문에, 방문자는 브라우저 인증서 경고가 아니라 Cloudflare 오류 화면을 봅니다.

방문자라면

내 쪽에서 할 수 있는 것은 없고, 이 오류가 나에게 사이트가 위험하다는 신호도 아닙니다. 거부된 인증서는 Cloudflare 뒤에 있는 사이트 서버의 것입니다. 잠시 후 다시 시도하거나, 운영자에게 오류가 난 시각과 오류 화면 아래쪽의 Ray ID를 알려 주세요.

526이 아니라 NET::ERR_CERT_AUTHORITY_INVALID나 “연결이 비공개로 설정되어 있지 않습니다” 같은 브라우저 경고가 보인다면 다른 문제입니다. ERR_CERT_AUTHORITY_INVALID를 보세요.

어떤 Cloudflare 에러인가

52x 코드는 Cloudflare와 원 서버의 연결이 어디까지 갔는지를 알려 줍니다.

코드멈춘 곳
521원 서버가 TCP 연결을 거부함(듣고 있는 프로그램이 없거나 방화벽이 거부)
522TCP 연결 시간 초과(패킷이 버려지거나, 원 서버에 닿지 않거나, 과부하)
525TCP 연결은 됐지만 TLS 핸드셰이크가 실패함
526핸드셰이크는 끝났지만 Full (strict)에서 원 서버 인증서가 유효하지 않음
520연결은 됐지만 원 서버의 응답이 비어 있거나 Cloudflare가 해석할 수 없음

오류 화면의 문장이 아니라 숫자를 보세요. 525와 526은 둘 다 원 서버와의 ‘SSL’ 문제로 설명되지만 고칠 곳이 다릅니다. 525라면 Cloudflare 525 에러를 보세요.

알아 두면 쓸모 있는 점이 하나 있습니다. Full과 Flexible은 원 서버 인증서를 검증하지 않으므로 526이 날 수 없습니다. 그래서 원 서버 인증서가 몇 달 전에 만료됐는데도, 누군가 존을 strict로 바꾼 날에야 발견하는 일이 흔합니다.

Cloudflare가 보는 인증서를 직접 보기

원 서버의 실제 IP가 필요합니다. Cloudflare DNS 대시보드의 A 또는 AAAA 레코드 값입니다. 프록시를 켠 레코드는 공개 DNS에서 Cloudflare 주소만 나옵니다.

그 IP에 연결하면서 Cloudflare처럼 SNI로 내 호스트명을 보내고, OpenSSL에게 검증을 맡깁니다.

openssl s_client -connect 203.0.113.10:443 -servername www.example.com \
  -verify_hostname www.example.com </dev/null 2>/dev/null | grep -E 'subject=|issuer=|Verify return code'
subject=CN = www.example.com
issuer=C = US, O = Let's Encrypt, CN = R11
Verify return code: 10 (certificate has expired)

Verify return code: 0 (ok)는 일반적인 클라이언트가 그 이름으로 이 인증서를 받아 준다는 뜻입니다. 다른 값이면 실패 이유를 알려 줍니다.

Verify return code뜻아래 원인
10 (certificate has expired)notAfter 날짜가 지남1
18 (self-signed certificate)뒤에 CA가 없음2
19 (self-signed certificate in certificate chain)아무도 신뢰하지 않는 루트로 체인이 끝남2
20 (unable to get local issuer certificate)발급자를 모름. 중간 인증서 누락인 경우가 많음4
21 (unable to verify the first certificate)leaf에서 체인을 만들지 못함. 대개 중간 인증서 누락4
62 (hostname mismatch)그 이름이 인증서에 없음3

오래된 OpenSSL은 18, 19를 하이픈 없이 “self signed”로 표기합니다. 원 서버가 Cloudflare Origin CA 인증서를 쓴다면 내 컴퓨터는 그 CA를 모르므로 20이나 21을 냅니다. 정상입니다. Cloudflare 문서에서 Origin CA 루트 인증서(내 인증서에 맞춰 RSA 또는 ECC)를 내려받아 -CAfile로 넘기면 만료와 이름 문제만 남습니다.

날짜와 이름을 한 번에 보려면 이렇게 합니다.

openssl s_client -connect 203.0.113.10:443 -servername www.example.com </dev/null 2>/dev/null \
  | openssl x509 -noout -subject -issuer -dates -ext subjectAltName

curl -v --resolve www.example.com:443:203.0.113.10 https://www.example.com/도 같은 검사를 하고, SSL certificate problem: certificate has expired처럼 읽기 쉬운 오류로 멈춥니다.

원 서버에 프록시를 거치지 않는(DNS 전용) 호스트명이 있다면 SSL 점검으로 바깥에서 그 인증서의 만료일과 체인을 볼 수 있습니다. 프록시된 호스트명에서는 Cloudflare 엣지 인증서가 나오는데, 그것은 526의 원인이 아닙니다.

흔한 원인

1. 인증서가 만료됨

526의 압도적인 1위입니다. 원 서버 인증서의 유효 기간이 끝났습니다. 대개 어느 시점에 자동 갱신이 깨졌는데 아무도 몰랐던 것입니다. Cloudflare 뒤에서는 세 가지 경로가 흔합니다.

  • 갱신은 됐는데 서버를 리로드하지 않음. certbot은 디스크에 새 인증서를 썼지만 nginx는 메모리에 있는 옛 인증서를 계속 내놓습니다. 디스크의 날짜(sudo openssl x509 -in /etc/letsencrypt/live/example.com/fullchain.pem -noout -enddate)와 s_client에 나오는 날짜를 비교해 보세요. deploy hook으로 영구히 고칩니다. certbot renew --deploy-hook "systemctl reload nginx".
  • Cloudflare 때문에 갱신이 실패함. HTTP-01 검증 요청은 프록시를 거칩니다. “Always Use HTTPS”가 켜져 있고 원 서버 인증서가 이미 만료됐다면, 검증 요청은 엣지에서 HTTPS로 리다이렉트되고, Cloudflare는 strict 모드로 원 서버에서 그것을 가져오려다 526을 돌려줍니다. 인증서가 한 번 만료되면 갱신이 스스로 회복하지 못합니다. 원 서버를 거치지 않는 DNS-01 방식으로 바꾸세요(certbot에 Cloudflare DNS 플러그인이 있습니다).
  • 타이머가 돌지 않음. systemctl list-timers | grep -i certbot과 sudo certbot renew --dry-run으로 확인하세요.

2. 자체 서명이거나 사설 CA 인증서

새로 만든 서버에서 흔합니다. Debian·Ubuntu가 만드는 snakeoil 인증서(/etc/ssl/certs/ssl-cert-snakeoil.pem), 호스팅 관리 화면의 기본 인증서, “일단 HTTPS가 되게” openssl req -x509로 만든 인증서, 회사 내부 CA가 발급한 인증서 같은 것들입니다. Full은 이것을 모두 받아 주고, Full (strict)는 하나도 받아 주지 않습니다.

해결: Cloudflare Origin CA 인증서(SSL/TLS → Origin Server → Create Certificate)나 Let’s Encrypt 인증서를 설치하세요. 내부 CA를 계속 쓰고 싶다면 요금제에 있을 경우 Custom Origin Trust Store를 쓰면 됩니다.

3. 인증서에 그 이름이 없음

인증서 자체는 유효한데, Cloudflare가 요청한 호스트명용이 아닙니다.

  • example.com만 커버하는데 요청은 www.example.com이거나, 그 반대.
  • 와일드카드 *.example.com은 www.example.com은 커버하지만 example.com과 a.b.example.com은 커버하지 않음.
  • 원 서버에 이 호스트명의 server 블록이 없어서 기본 설정으로 넘어가고, 다른 사이트의 인증서를 내놓음. Cloudflare에 새 서브도메인을 추가하고 원 서버 server_name에는 넣지 않았을 때 흔합니다.
  • 인증서가 origin.example.com처럼 원 서버 자기 이름용인데 방문자는 www.example.com을 씀.

해결: 프록시를 거치는 모든 이름을 넣어 인증서를 다시 발급하거나(certbot --expand -d example.com -d www.example.com), example.com과 *.example.com으로 Origin CA 인증서를 만들고, 호스트명마다 server 블록이 있는지 확인하세요. 와일드카드 규칙은 브라우저와 같습니다. ERR_CERT_COMMON_NAME_INVALID를 참고하세요.

4. 체인이 불완전함

원 서버가 자기 인증서만 보내고, 그것을 신뢰할 수 있는 루트까지 이어 주는 중간 인증서는 보내지 않습니다. 브라우저는 빠진 중간 인증서를 스스로 받아 와서 넘어가 주기도 하지만, Cloudflare의 검증도 그렇게 해 주리라 기대하면 안 됩니다. 전체 체인을 보내세요.

전형적인 실수는 nginx ssl_certificate가 certbot의 fullchain.pem이 아니라 cert.pem을 가리키는 것, Apache 설정에서 체인 파일이 빠진 것, 상용 인증서를 설치하면서 업체가 함께 보내 준 CA 번들을 빠뜨린 것입니다. nginx가 실제로 읽는 파일은 sudo nginx -T | grep -E 'ssl_certificate'로 확인하세요. 자세한 내용은 인증서 체인 문제에 있습니다.

5. 호스트명 하나나 원 서버 하나만 실패함

사이트 대부분은 되는데 서브도메인 하나만 526이라면, 그 호스트명이 자기 인증서를 쓰는 다른 서버를 가리키거나 SSL 모드가 따로 걸려 있는 것입니다. Configuration Rule이나 예전 Page Rule로 존은 Full인 채로 호스트명 하나만 Full (strict)로 설정할 수 있습니다.

같은 URL에서 526이 났다 안 났다 한다면 뒤에 원 서버가 여러 대 있고(프록시된 A 레코드 여러 개, 로드밸런서 풀) 그중 하나의 인증서가 잘못된 것입니다. 원 서버 IP마다 s_client 명령을 돌려 보세요.

SaaS 플랫폼을 가리키는 프록시된 CNAME은 특수한 경우입니다. 인증서는 플랫폼이 내놓는데, 일부 플랫폼은 레코드가 프록시를 거치는 동안 내 커스텀 도메인용 인증서를 발급하지 못합니다. 그 플랫폼의 Cloudflare 연동 문서를 확인하세요.

임시방편: Flexible이 아니라 Full

사이트가 내려가 있는데 인증서를 고치는 데 시간이 걸린다면, 존 전체나 Configuration Rule로 그 호스트명만 Full로 바꾸면 바로 살아납니다. 원 서버 구간은 계속 암호화되고, Cloudflare가 상대가 누구인지 확인하는 것만 멈춥니다. 어딘가에 알림을 걸어 두고, 인증서를 고치면 되돌리세요.

Flexible로는 가지 마세요. 원 서버로 가는 트래픽이 암호화되지 않고, 원 서버가 HTTP를 HTTPS로 리다이렉트한다면 526이 리다이렉트 루프로 바뀔 뿐입니다. 선택지는 Cloudflare SSL 모드에서 비교합니다.

다시 깨지기 어려운 해결

항상 프록시를 거칠 사이트라면 Origin CA 인증서가 가장 손이 덜 갑니다. example.com과 *.example.com으로 긴 유효 기간(최대 15년)을 골라 만들고, 원 서버에 인증서와 키를 설치하고, 웹 서버를 리로드하고, s_client와 Cloudflare Origin CA 루트로 확인한 뒤 Full (strict)로 바꾸면 됩니다. 같은 단계를 525 가이드에서도 설명합니다.

그 호스트명을 언젠가 DNS 전용으로 돌릴 수도 있거나, Cloudflare 밖의 무언가가 원 서버를 직접 검사한다면 DNS-01로 갱신하는 Let’s Encrypt를 쓰세요. 어느 쪽이든 원 서버 인증서 만료일을 누군가의 달력이나 모니터링에 올려 두세요. 자세한 내용은 SSL 만료 체크리스트에 있습니다.

고친 다음에

  • 페이지를 새로고침하세요. 오류 화면마다 새 Ray ID가 붙으므로, 새 Ray ID로 526이 또 나온다면 Cloudflare가 아직 인증서를 거부하고 있는 것입니다.
  • 신고된 호스트명 하나만이 아니라 프록시를 거치는 모든 호스트명에 -verify_hostname을 넣은 openssl 검사를 돌리세요.
  • 공개 호스트명에 SSL 점검을 돌려 방문자 쪽 인증서도 정상인지 확인하세요.

비슷해 보이는 다른 오류

내 도메인에서 바로 확인

무료, 가입 불필요. 이 가이드가 다루는 항목을 바로 검사하고 조치 방법을 알려드립니다.