Cloudflare에 API로 존을 만들면 DNS 레코드를 하나도 안 가져온다

하려던 일

마케팅 홈페이지를 루트 도메인에 붙이려 했다. 정적 호스팅은 Cloudflare Pages를 쓰기로 했고, Pages는 커스텀 도메인을 CNAME으로 연결한다.

문제는 루트 도메인, 그러니까 example.com 같은 apex에는 CNAME을 둘 수 없다는 것이다. DNS 명세상 apex에는 SOA와 NS가 이미 있고, CNAME은 같은 이름에 다른 레코드가 공존하는 것을 허용하지 않는다. 그래서 DNS 제공자들은 apex에서 CNAME처럼 동작하는 ALIAS, ANAME, CNAME 플래트닝 같은 비표준 레코드를 제공한다.

쓰던 등록기관에는 그게 없었다. A 레코드로 IP를 박는 방법이 남지만, Pages의 앞단 IP는 고정이 아니다.

남은 길은 하나였다. 네임서버 자체를 Cloudflare로 옮기는 것.

중간에 타협하려다 말았다

처음에는 「기존 네임서버를 유지하면서 Cloudflare를 하나 더 추가하면 되지 않나」를 생각했다. 안 된다. 위임은 집합이다. 상위 존은 등록된 네임서버 중 아무거나 골라 질의하고, 그 집합 안에 서로 다른 답을 가진 서버가 섞여 있으면 응답이 요청마다 달라진다. 완전히 죽지도 않고 완전히 살지도 않는, 가장 진단하기 어려운 상태가 된다.

전부 옮기거나, 아예 옮기지 않거나 둘 중 하나다.

놓칠 뻔한 것

Cloudflare 대시보드로 도메인을 추가해 본 사람은 온보딩 중간에 「기존 DNS 레코드를 스캔했습니다」 화면을 봤을 것이다. 자동으로 긁어 와서 새 존에 채워 준다.

API로 존을 만들면 그 단계가 없다. 존은 만들어지지만 레코드는 텅 비어 있다. 그리고 응답 어디에도 "비어 있습니다"라고 쓰여 있지 않다. 성공은 성공대로 반환된다.

이 상태에서 네임서버만 바꿨다면 어떻게 됐을까. 상위 존이 새 네임서버를 가리키고, 새 네임서버는 아무 레코드도 모른다. 메일 수신용 MX 레코드가 사라지므로 회사 메일이 즉시 죽는다. 애플리케이션과 API가 붙어 있던 하위 도메인 셋도 같이 죽는다. 홈페이지 하나 띄우려다 살아 있던 것들을 전부 내리는 셈이다.

막아준 것은 코드가 아니라 순서였다

작업 계획에 「네임서버를 바꾸기 직전, 기존 존의 레코드와 새 존의 레코드를 1:1로 대조한다」는 단계를 넣어 뒀었다. 그 단계가 실제로 걸러냈다. 대조해 보니 새 존에는 아무것도 없었다.

기존 제공자에서 레코드를 하나씩 읽어 새 존에 다시 만들고, 개수와 값이 맞는 것을 확인한 다음에야 위임을 바꿨다.

같은 함정이 하나 더 있었다. Pages의 커스텀 도메인도 API로 추가하면 필요한 DNS 레코드를 자동으로 만들어 주지 않는다. 도메인이 계속 「대기 중」에 멈춰 있어서 한참을 들여다봤는데, 원인은 그냥 가리킬 CNAME이 없다는 것이었다. 직접 만들어 주니 바로 활성이 됐다.

두 경우 모두 같은 구조다. 대시보드가 대신 해 주던 일을 API는 하지 않는다. 그런데 실패로 보이지 않는다.

전파 확인은 공개 리졸버로 하지 말 것

바꾼 뒤에 확인하려고 공개 DNS로 조회했더니 계속 옛 네임서버가 나왔다. 이 존의 기본 TTL이 하루라서, 공개 리졸버의 캐시는 한참 동안 옛값을 준다. 여기서 「전파가 안 됐다」고 판단하고 되돌렸다면 아무 이유 없이 한 번 더 흔든 셈이 됐을 것이다.

정확한 답은 상위 레지스트리의 네임서버에 직접 물어보는 것이다. 거기에는 캐시가 끼지 않는다. 레지스트리가 새 위임을 이미 알고 있다면 전파는 시작된 것이고, 나머지는 캐시가 만료되기를 기다리는 시간일 뿐이다.

덧붙이자면 이 확인을 OS 기본 조회 도구로 하려다 한 번 헤맸다. 한국어 로케일에서 출력이 깨져 읽을 수가 없었다. 결국 DNS-over-HTTPS로 JSON 응답을 받아서 봤다. 진단 도구가 읽히지 않으면 진단이 아니라 추측이 된다.

← 개발 기록 목록으로