들어가며
기존 블로그, 깃 허브, 노션 등 여기 저기 분산된 개발 흔적들을 하나로 모으고자 바이브코딩으로 블로그를 만들게 되었다.
Next.js, Typescript, TailwindCss, Pnpm, Mdx 스택 등을 활용해 Vercel에 배포하였고, 나만의 블로그라는 의미로 커스텀 도메인을 붙이고 싶었다. 도메인 등록 서비스는 가비아, 후이즈, 네임칩 등 여럿 있는데 Cloudflare가 비교적 저렴해서 Cloudflare에서 구매하기로 결정했다.
DNS 개념은 CS 스터디를 하며 이것이 취업을 위한 컴퓨터 과학이다 책을 통해 정리했던 내용이라 용어 자체는 낯설지 않았다. 그러나 막상 Cloudflare 대시보드를 열어보니 A 레코드, CNAME, TTL 같은 것들을 실제로 어디에 어떻게 입력해야 하는지는 바로 연결이 안 됐다. 이번에 직접 설정하면서 이론과 연결해보고, 정리하여 첫 게시글로 시작해보고자 한다.
도메인과 DNS
도메인 이름 개념
도메인 이름은 IP 주소와 대응하는 문자열 형태의 식별자다.
IP 주소는 네트워크 상의 호스트를 식별하기 위한 숫자 기반 정보인데, 기억하기 어렵고 서버 이전 등으로 언제든 바뀔 수 있다. 그래서 사람이 기억하기 쉬운 문자열 형태의 도메인 네임을 IP 주소에 대응해서 사용한다. 이 대응 관계를 관리하는 서버를 네임 서버(Name Server) 라고 한다.
도메인 이름의 구조
www.example.com은 점으로 구분된 계층 구조다.
www . example . com .
↑ ↑ ↑ ↑
3단계 2단계 TLD 루트(보통 생략)
- 루트 도메인: 맨 끝 점. 보통 생략한다.
- TLD(최상위 도메인):
com,net,kr,dev같은 것들 - 2단계 도메인: 직접 구매하는 부분
- 서브도메인:
www,mail같은 앞에 붙는 것들- 서브도메인은 별도로 구매하지 않고, DNS 설정에서 레코드를 추가한다.
이 전체를 FQDN(Fully-Qualified Domain Name) 이라고 한다.
DNS 레코드 타입
DNS 관리 화면에서 설정하는 것이 DNS 레코드다.
레코드는 이름, 값, 타입, TTL로 구성되고, 타입마다 역할이 다르다. 이 레코드를 네임 서버에 추가함으로써 IP 주소와 도메인 네임의 대응 관계를 등록한다.
| 타입 | 역할 |
|---|---|
| A | 도메인 → IPv4 주소 매핑 |
| AAAA | 도메인 → IPv6 주소 매핑 |
| CNAME | 별칭 지정. www.example.com → example.com |
| NS | 도메인을 관리하는 네임 서버 지정 |
| MX | 이메일 수신 서버 지정 |
도메인을 입력하면 무슨 일이 생길까
브라우저에 google.co.kr을 치면 구글 화면이 뜬다. 네트워크는 도메인이 아니라 IP로 통신하기 때문에, 브라우저가 가장 먼저 하는 일은 그 도메인에 해당하는 IP 주소를 찾는 거다. 이 과정을 DNS 조회(DNS Lookup) 라고 한다.
- 브라우저가 DNS 조회 요청을 보낸다.
- 로컬 DNS 리졸버(Name Server)가 요청을 처리한다.
- 도메인에 대응하는 IP 주소를 반환한다.
- 그 IP로 HTTP 요청을 보낸다.
특정 도메인의 IP가 궁금하면 터미널에서 확인할 수 있다.
nslookup google.co.krDNS 리졸빙 과정
컴퓨터는 처음부터 직접 루트 서버에 물어보지 않는다. 가장 가까운 DNS 서버인 로컬 네임 서버에 먼저 묻는다. ISP가 자동으로 할당해주거나, 8.8.8.8 같은 공개 DNS를 직접 지정할 수도 있다.
로컬 네임 서버가 이미 알고 있으면 바로 반환한다. 모르면 아래 순서로 단계적으로 질의한다.
로컬 네임 서버 → 루트 네임 서버 (전 세계 13개) → TLD 네임 서버 (.com 담당) → 권한 DNS 서버 (example.com 담당) → IP 주소 반환
권한 DNS 서버(Authoritative DNS Server) 는 특정 도메인의 원본 DNS 데이터를 가진 서버다. Cloudflare에서 도메인을 사면 Cloudflare가 그 역할을 한다. 대시보드에서 내가 설정한 레코드들이 여기 저장된다.
DNS 캐시와 TTL
한 번 조회한 결과는 캐시에 저장된다. TTL이 만료되기 전까지는 캐시를 재사용하므로, 같은 호스트에 대한 추가 DNS 질의가 발생하지 않는다.
DNS 응답에는 TTL(Time To Live) 값이 붙어 있다. 이 시간 동안 캐시가 유지되고, 만료되면 다시 질의한다. TTL이 길수록 DNS 서버 요청이 줄어들지만, 설정을 바꿔도 전파가 느리다.
Cloudflare 기본값은 "자동"이고 대부분 그냥 두면 된다. 설정을 자주 바꿀 예정이라면 짧게 해두는 게 낫다.
TTL은 설정 초반에 짧게 두는 게 편하다. 레코드를 잘못 입력해서 수정해야 할 때, TTL이 길면 변경 사항이 반영되기까지 한참 기다려야 한다.
Cloudflare에서 실제로 연결하기
도메인을 구매하면 아래처럼 Cloudflare DNS 관리 화면이 자동으로 생성된다. 여기서 레코드를 추가하면 된다.

Vercel에서 도메인 추가
Vercel 대시보드 Settings → Domains에서 구매한 도메인을 추가하면 어떤 DNS 레코드를 입력해야 하는지 알려준다.

Cloudflare에 레코드 입력
Vercel이 알려준 대로 루트 도메인(@)에 A 레코드를 입력했다.
유형: A
이름: @
IPv4: 76.76.21.21
TTL: 자동
www 서브도메인도 같은 곳으로 연결되도록 CNAME을 추가했다.
유형: CNAME
이름: www
값: cname.vercel-dns.com
TTL: 자동
왜 루트 도메인은 A 레코드이고, www는 CNAME인가
CNAME(Canonical Name)은 어떤 도메인 이름을 다른 도메인의 별칭(alias) 으로 지정하는 레코드다. www.example.com CNAME example.com이라면, www.example.com은 IP를 직접 가지지 않고 example.com을 다시 조회한다.
루트 도메인(@)에 CNAME을 쓸 수 없는 이유는 DNS 표준 규칙 때문이다. 루트 도메인(example.com)은 Zone Apex라고 부르며, 반드시 두 가지 레코드를 가져야 한다.
- SOA(Start of Authority): 해당 존의 기본 정보(담당 네임 서버, 시리얼 번호, TTL 정책 등)를 담는 메타 레코드. DNS 제공자(Cloudflare)가 자동으로 관리하며 직접 설정하지 않는다.
- NS(Name Server): 이 도메인을 관리하는 네임 서버 목록.
그런데 CNAME은 해당 이름에 다른 어떤 레코드도 공존할 수 없다는 제약이 있다.
example.com CNAME something.com ← SOA, NS와 공존 불가그래서 루트 도메인에는 IP를 직접 가리키는 A 레코드를, www처럼 제약이 없는 서브도메인에는 CNAME을 사용한다. 결과적으로 레코드는 다음과 같은 구조가 된다.
minyeongkim.dev A 76.76.21.21
www.minyeongkim.dev CNAME cname.vercel-dns.comVercel이 관리하는 cname.vercel-dns.com을 가리키면, Vercel 쪽에서 IP가 바뀌어도 사용자가 DNS를 다시 수정할 필요가 없다는 장점도 있다.
Vercel이 특정 IP(76.76.21.21)를 안내하는 이유
이 IP는 내 서버의 IP가 아니라 Vercel Edge Network의 공용 진입점이다.
여러 프로젝트가 동일한 IP를 공유하더라도 문제가 없는 이유는 HTTP 요청에 포함된 Host 헤더 때문이다. Vercel은 Host 헤더를 보고 어떤 프로젝트인지 식별해 라우팅하며, SSL도 SNI(Server Name Indication)를 통해 도메인 단위로 구분된다. IP는 공유하지만 서비스는 도메인 단위로 분리되는 구조다.
Cloudflare를 "DNS 제공자"로만 사용하는 구조

Cloudflare에서 레코드 추가할 때 프록시(주황색 구름 아이콘)는 꺼야 한다. 켜두면 Vercel과 이중 프록시가 되어 SSL 충돌이나 리다이렉트 루프가 발생할 수 있다.
현재 구조에서 Cloudflare는 트래픽을 중계하지 않는다. 단지 이 도메인의 권한 DNS 서버 역할만 수행한다.
역할은 다음과 같이 분리된다.
- Cloudflare → DNS 정보 관리 (도메인 → IP 매핑)
- Vercel → 실제 트래픽 처리 및 콘텐츠 제공
Cloudflare 프록시를 켜면 구조는 이렇게 바뀐다.
Vercel은 자체적으로 글로벌 CDN, Edge Network, SSL 자동 발급, DDoS 보호, 캐싱을 전부 제공한다. 여기에 Cloudflare 프록시까지 켜면 사용자 → Cloudflare → Vercel → Vercel 서버 구조가 돼 이중 프록시가 된다.
이중 프록시가 문제가 되는 이유
① SSL 충돌 가능성 — Vercel과 Cloudflare 둘 다 인증서를 발급한다. SSL 모드 설정이 맞지 않으면 리다이렉트 루프나 525, 526 오류가 발생할 수 있다.
② 캐시 이중화 — Cloudflare 캐시와 Vercel 캐시가 겹치면서 캐시 무효화가 꼬일 수 있다.
Vercel 공식 문서에도 Cloudflare 같은 리버스 프록시를 앞단에 두는 것을 권장하지 않는다고 명시되어 있다.
DNS 전파 대기 및 할당
설정 직후 바로 접속이 되지 않는다. TTL과 캐시 정책에 따라 전파 시간이 달라지는데, Cloudflare는 빠른 편이라 2~3분 정도 걸렸다.
전파가 완료됐는지 확인할 때 브라우저로 들어가보는 것보다 nslookup으로
확인하는 게 정확하다. 브라우저는 이전 DNS 캐시를 물고 있을 수 있어서, 전파는
됐는데 브라우저에서 여전히 안 되는 경우가 있다.
nslookup minyeongkim.dev도메인이 나오면 전파 완료다.
설정 후 Vercel에서 도메인이 정상 할당된 걸 확인할 수 있다.

마치며
책으로 DNS를 배울 때는 개념을 이해하는 데 집중했다. 루트 서버, TLD, 권한 DNS 서버 같은 구조를 머리로는 알고 있었지만, 실제 설정 화면에서 이 개념들이 어떻게 연결되는지는 선명하지 않았다.
이번에 Cloudflare에서 레코드를 직접 추가하고, Vercel이 안내하는 값들의 의미를 하나씩 확인해보면서 그 구조가 구체적으로 보이기 시작했다. 루트 도메인에는 왜 CNAME을 둘 수 없는지, Vercel이 왜 특정 IP를 공용으로 사용하는지, 왜 Cloudflare를 DNS 제공자로만 두는 구성을 권장하는지까지 따라가 보니 DNS는 단순히 “도메인을 IP로 바꿔주는 기능”이 아니었다.
도메인을 연결하는 작업 자체는 몇 줄의 레코드를 추가하는 것으로 끝난다. 하지만 그 뒤에는 RFC로 정의된 규칙, TTL 기반 캐시 동작, 계층적으로 나뉜 네임 서버 구조, 그리고 CDN 환경에서의 도메인 기반 라우팅 방식이 함께 작동하고 있다.
이번 설정을 통해 DNS는 더 이상 외워야 할 개념이 아니라 서비스가 실제로 어떻게 흘러가는지 이해하기 위한 기반이라는 걸 느꼈다. 다음에는 DNSSEC, DNS over HTTPS, CNAME Flattening 같은 주제도 이어서 정리해볼 생각이다.
참고
- 이것이 취업을 위한 컴퓨터 과학이다 — 5장 네트워크 (05-5 DNS) 정리 노트: GitHub
- Cloudflare with Vercel