IT 시행착오··약 8분

HTTPS·커스텀 도메인 DNS 연결 체크리스트

apex와 www를 Cloudflare Workers에 붙일 때 DNS, 프록시, HTTPS, canonical을 실제로 맞춘 순서입니다.

도메인 네임 주석 예시 — HTTPS·DNS 체크리스트 (cc0, wikimedia-commons)

도메인 연결은 “레코드 하나 추가”로 끝나지 않습니다. 서민혁닷컴은 apex(seominhyuk.com)를 대표 주소로 두고, Workers Custom Domain으로 붙였습니다. 겉으로는 단순해 보였는데, DNS·프록시·보안 설정이 겹치면서 “배포는 됐는데 구글이 못 읽는” 상태가 됐습니다.

대표 주소부터 고정

저는 apex를 기준으로 잡았습니다. sitemap, canonical, OG URL, Search Console 모두 https://seominhyuk.com으로 통일합니다. www는 있으면 같은 사이트로 열고, 없으면 나중에 붙여도 됩니다. 중요한 건 문서마다 다른 호스트가 섞이지 않는 것입니다.

workers.dev는 미리보기용으로만 씁니다. 글 안의 절대 URL에 workers.dev를 넣지 않습니다.

처음에 글 몇 개에 workers.dev 절대 경로가 들어간 채로 빌드된 적이 있습니다. 브라우저에서는 “열리는” 것처럼 보여도, Search Console·sitemap·OG가 서로 다른 호스트를 가리키면 색인과 공유 미리보기가 갈라집니다. 배포 전에 site/canonical 설정이 운영 도메인인지 확인하는 습관이 생겼습니다.

Workers용 DNS가 어떻게 생겼는지

Custom Domain을 붙이면 apex에 대략 이런 식이 생깁니다.

  • AAAA100::, Proxied(주황구름)

이건 “내 서버 IP”가 아니라 Cloudflare가 Workers로 라우팅할 때 쓰는 자리표시에 가깝습니다. 예전에 쓰던 A/CNAME이 같은 이름에 남아 있으면 충돌하니, 운영에 안 쓰는 레코드는 지웁니다.

Search Console 도메인 확인용 TXT(google-site-verification=…)는 프록시와 무관하게 apex에 두면 됩니다. 우리 존에는 이미 TXT가 있어서, 콘솔에서 확인만 누르면 되는 상태였습니다.

충돌을 냈던(그리고 지웠던) 레코드

  • apex에 옛 A 레코드와 Workers용 AAAA 100::가 같이 있던 구간 — 어떤 해석기에선 옛 쪽으로 갔습니다.
  • 회색구름(DNS only)으로 두었다가 Workers 라우팅이 안 되는 줄 알고 헤맨 구간 — Workers Custom Domain은 프록시(주황)가 전제에 가깝습니다.
  • 테스트용 CNAME을 남기고 잊어버린 경우 — “왜 이 호스트만 다른 응답?”의 원인 후보가 됩니다.

정리할 때는 dig로 apex A/AAAA/TXT를 한 번에 봅니다.

dig +short seominhyuk.com A
dig +short seominhyuk.com AAAA
dig +short seominhyuk.com TXT

www를 나중에 붙인 방법

www.seominhyuk.com은 처음엔 DNS조차 없었습니다. Custom Domain API가 계정 토큰 방식 때문에 거절돼서, 대신:

  1. wwwAAAA 100:: Proxied 추가
  2. Workers Route: www.seominhyuk.com/*warpsense-blog

으로 연결했습니다. 로컬 DNS 캐시 때문에 Could not resolve host가 한동안 날 수 있습니다. dig @1.1.1.1 www.seominhyuk.com AAAA로 전파를 보고, 필요하면 apex와 같은 Cloudflare anycast IP로 --resolve 해서 응답만 먼저 확인했습니다.

dig @1.1.1.1 www.seominhyuk.com AAAA +short
# 로컬 캐시가 꼬였을 때: 공개 리졸버로 전파만 먼저 확인
curl -sI --resolve www.seominhyuk.com:443:<cloudflare-anycast-ip> \
  https://www.seominhyuk.com/ | head -n 15

--resolve로 본문이 오면 DNS·Worker 라우팅은 된 것이고, 로컬 resolver만 늦은 겁니다. 반대로 dig에는 100::가 보이는데 curl이 연결 실패면 레코드 타입·프록시 토글·Route 패턴(/* 누락)을 의심합니다.

www를 apex로 301할지, 둘 다 같은 콘텐츠로 둘지는 취향입니다. 저는 문서는 apex canonical로 고정하고, www는 같은 Worker로 열어 두되 OG·sitemap에는 apex만 넣습니다. 호스트가 두 개면 “어느 쪽이 대표인지”를 문서 층에서 한 번 더 박아야 합니다.

HTTPS와 “열리는데 본문이 없는” 함정

자물쇠가 켜져 있어도, Bot Fight / Managed Challenge가 있으면 사람 브라우저만 통과하고 봇은 Just a moment... HTML을 받습니다. DNS·인증서는 정상인데 검수만 실패하는 패턴입니다. 도메인을 붙인 뒤 꼭:

curl -sI -A "AdsBot-Google (+http://www.google.com/adsbot.html)" https://seominhyuk.com/

cf-mitigated: challenge가 없는지 봅니다.

브라우저에서 자물쇠가 보인다고 “도메인 작업 끝”이라고 선언하지 않습니다. 제가 겪은 순서는 대략 이랬습니다.

  1. DNS 레코드 정리 → dig로 AAAA/100:: 확인
  2. 브라우저로 HTTPS 200 확인(사람 통과)
  3. AdsBot curl → 챌린지 발견
  4. Bot Fight 끄기·퍼지 → 다시 AdsBot 200

1·2만 하고 AdSense·Search Console로 넘어가면, “도메인은 맞는데 검수만 실패”로 며칠을 날릴 수 있습니다. 챌린지 해제는 Bot Fight 글에, Workers 쪽 배포 흐름은 정적 사이트 Workers에 있습니다.

배포 직후 캐시와 혼합 콘텐츠

배포 직후 옛 HTML이 남으면 “DNS를 다시 건드린” 줄 알고 레코드를 더 만지게 됩니다. 이상하면 존 캐시 퍼지 후 시크릿 창·curl을 다시 합니다. 혼합 콘텐츠(http 리소스)는 블로그에 거의 없지만, OG 이미지나 외부 스크립트가 http면 콘솔 경고가 납니다. 절대 URL은 https로 통일합니다.

서브도메인으로 앱·블로그를 나누는 이야기는 서브도메인으로 서비스 나누기에 있습니다. 블로그 apex만 쓸 때도 app. / crawl.을 나중에 붙일 여지를 DNS에 남겨 두면 편합니다. 지금 안 쓰는 이름을 성급히 다른 서비스에 붙이면, 나중에 대표 주소를 바꾸기 어렵습니다.

운영 체크리스트(내가 쓰는 순서)

도메인을 만질 때마다 이 순서를 지키면, “레코드만 고치다 보안·캐시를 놓치는” 일이 줄었습니다.

  1. 대표 호스트(apex)를 문서·sitemap·OG·Search Console에 고정한다.
  2. dig로 A/AAAA/TXT와 100::·프록시 상태를 본다.
  3. 브라우저로 HTTPS·리다이렉트를 본다(사람 경로).
  4. AdsBot/Googlebot curl로 HTML·sitemap을 본다(봇 경로).
  5. 이상하면 캐시 퍼지 후 4를 반복하고, 그래도 cf-mitigated: challenge면 Bot Fight를 의심한다.

한 줄로 말하면: 대표 호스트 하나로 문서를 맞추고, Workers용 레코드를 정리하고, HTTPS 다음에 봇 응답까지 확인하면 도메인 작업이 끝납니다. dig 성공 ≠ 크롤 가능, 브라우저 자물쇠 ≠ AdsBot 200입니다.