Split View: DNS 완전 정복: 네임서버, DDNS, nslookup 실전 가이드 — 도메인 등록부터 트러블슈팅까지
DNS 완전 정복: 네임서버, DDNS, nslookup 실전 가이드 — 도메인 등록부터 트러블슈팅까지
- 1. DNS 동작 원리 완전 이해
- 2. 네임서버 심화
- 3. DNS 레코드 타입 총정리
- 4. 도메인 등록/이전 실전 가이드
- 5. DDNS (Dynamic DNS) 완전 가이드
- 6. nslookup 완전 활용법
- 7. dig 명령어 마스터리
- 8. DNS 보안
- 9. 실전 트러블슈팅 10가지 시나리오
- 시나리오 1: 도메인 등록했는데 접속이 안 됨 (전파 지연)
- 시나리오 2: SSL 인증서 발급 실패 (CAA 레코드)
- 시나리오 3: 이메일이 스팸함으로 감 (SPF/DKIM/DMARC)
- 시나리오 4: 서브도메인이 작동하지 않음
- 시나리오 5: DNS 변경 후 일부 사용자만 접속 불가 (TTL 캐시)
- 시나리오 6: nslookup은 되는데 브라우저 접속 불가
- 시나리오 7: 도메인 이전 후 DNS 끊김
- 시나리오 8: K8s 내부 DNS 해석 실패 (CoreDNS, ndots)
- 시나리오 9: CDN 연동 후 원본 서버 IP 노출 (DNS Leak)
- 시나리오 10: DDNS 업데이트가 반영되지 않음
- 10. DNS 서비스 비교표
- 실전 퀴즈
- 참고 자료
1. DNS 동작 원리 완전 이해
DNS란? 인터넷의 전화번호부
DNS(Domain Name System)는 사람이 읽을 수 있는 도메인 이름(예: www.example.com)을 컴퓨터가 이해하는 IP 주소(예: 93.184.216.34)로 변환하는 시스템입니다. 1983년 Paul Mockapetris가 RFC 882, 883에서 처음 제안했고, 현재는 RFC 1034, 1035가 기본 명세입니다.
DNS가 없다면 우리는 모든 웹사이트에 접속할 때 IP 주소를 직접 입력해야 합니다. DNS는 인터넷 인프라의 가장 기본적이면서도 가장 중요한 구성 요소입니다.
사용자 입력: www.example.com
↓
DNS Resolution
↓
IP 주소: 93.184.216.34
↓
서버에 HTTP 요청
DNS 계층 구조: Root에서 Subdomain까지
DNS는 트리 구조의 계층적 분산 데이터베이스입니다. 최상위에서 하위로 내려가며:
. (Root)
/ \
com org net kr jp ... (TLD - Top Level Domain)
|
example (SLD - Second Level Domain)
/ \
www mail api (Subdomain)
계층별 역할:
| 계층 | 예시 | 관리 주체 |
|---|---|---|
| Root (.) | . | ICANN / IANA |
| TLD | .com, .kr, .org | 레지스트리 (Verisign, KISA 등) |
| SLD | example.com | 도메인 소유자 |
| Subdomain | www.example.com | 도메인 소유자 |
FQDN(Fully Qualified Domain Name)은 마지막에 점(.)을 포함합니다: www.example.com.
DNS 쿼리 흐름: 재귀적 vs 반복적
DNS 해석은 두 가지 방식이 조합되어 동작합니다.
재귀적 쿼리 (Recursive Query): 클라이언트가 재귀 리졸버에게 "최종 답을 알려줘"라고 요청합니다. 리졸버가 모든 일을 대신 처리합니다.
반복적 쿼리 (Iterative Query): 재귀 리졸버가 각 네임서버에게 "이 도메인 아는 사람 누구야?"라고 물어보면, 네임서버는 "나는 모르지만 저기 물어봐"라고 다음 서버를 안내합니다.
[사용자 PC] → 재귀적 쿼리 → [재귀 리졸버 (ISP/8.8.8.8)]
|
반복적 쿼리 시작
|
┌───────────────┼───────────────┐
↓ ↓ ↓
[Root Server] [TLD Server] [Authoritative NS]
"com은 여기" "example.com "IP는 93.x.x.x"
은 여기"
전체 흐름 상세:
- 사용자가 브라우저에
www.example.com입력 - 브라우저 캐시 확인 → OS 캐시 확인 → hosts 파일 확인
- OS가 설정된 재귀 리졸버(예: 8.8.8.8)에 재귀적 쿼리 전송
- 재귀 리졸버가 캐시 확인 → 없으면 Root 서버에 반복적 쿼리
- Root 서버: "
.comTLD 서버는a.gtld-servers.net이야" - 재귀 리졸버가 TLD 서버에 쿼리
- TLD 서버: "
example.com의 네임서버는ns1.example.com이야" - 재귀 리졸버가 권한 있는 네임서버에 쿼리
- 권한 있는 네임서버: "
www.example.com의 IP는93.184.216.34야" - 재귀 리졸버가 결과를 캐싱하고 클라이언트에 응답
13개 Root 서버와 Anycast
전 세계 DNS의 시작점인 Root 서버는 이름상 13개(A~M)이지만, Anycast 기술 덕분에 실제로는 1,700개 이상의 인스턴스가 전 세계에 분산되어 있습니다.
| Root 서버 | 운영 기관 | 인스턴스 수 (대략) |
|---|---|---|
| A | Verisign | 10+ |
| B | USC-ISI | 6+ |
| C | Cogent | 10+ |
| D | University of Maryland | 200+ |
| E | NASA | 300+ |
| F | ISC | 300+ |
| J | Verisign | 200+ |
| K | RIPE NCC | 100+ |
| L | ICANN | 200+ |
| M | WIDE Project | 10+ |
Anycast란? 같은 IP 주소를 여러 물리적 서버에 할당하는 기술입니다. 사용자의 쿼리는 BGP 라우팅을 통해 가장 가까운 인스턴스로 자동 전달됩니다. 이 덕분에 Root 서버 IP는 13개뿐이지만 전 세계 어디서나 빠른 응답이 가능합니다.
DNS 캐싱: 성능의 핵심
DNS 캐싱은 여러 레벨에서 이루어집니다:
[브라우저 캐시] → [OS 캐시] → [재귀 리졸버 캐시] → [각 네임서버 응답의 TTL]
Chrome: chrome://net-internals/#dns 에서 확인 가능
Windows: ipconfig /displaydns
Linux: systemd-resolve --statistics
macOS: sudo dscacheutil -flushcache
TTL (Time To Live) 이해:
example.com. 3600 IN A 93.184.216.34
↑
TTL = 3600초 (1시간)
TTL 값에 따른 전략:
| TTL 값 | 용도 | 장점 | 단점 |
|---|---|---|---|
| 60초 | DNS 변경 예정 시 | 빠른 전파 | 쿼리 증가, 응답 느림 |
| 300초 (5분) | 일반적인 서비스 | 균형 잡힌 선택 | - |
| 3600초 (1시간) | 안정적 서비스 | 빠른 응답, 쿼리 감소 | 변경 반영 느림 |
| 86400초 (1일) | 거의 변하지 않는 레코드 | 최고 성능 | 긴급 변경 어려움 |
실전 팁: DNS 변경 전에 TTL을 60초로 낮추고, 변경이 완전히 전파된 후 다시 올리세요.
2. 네임서버 심화
권한 있는(Authoritative) vs 재귀(Recursive) 네임서버
| 구분 | Authoritative NS | Recursive Resolver |
|---|---|---|
| 역할 | 특정 도메인의 최종 정보 보유 | 클라이언트 대신 DNS 트리 순회 |
| 데이터 | 존 파일의 원본 데이터 | 캐시된 데이터 |
| 예시 | ns1.cloudflare.com | 8.8.8.8 (Google DNS) |
| 운영 주체 | 도메인 소유자/호스팅 업체 | ISP, Google, Cloudflare |
| 응답 플래그 | AA (Authoritative Answer) 비트 설정 | AA 비트 없음 |
Primary(Master) vs Secondary(Slave) 네임서버
권한 있는 네임서버는 다시 Primary와 Secondary로 나뉩니다.
[Primary NS] ──Zone Transfer──→ [Secondary NS]
(읽기/쓰기) (읽기 전용)
원본 존 파일 관리 Primary 장애 시 백업
레코드 추가/수정/삭제 부하 분산 역할
왜 Secondary가 필요한가?
- 고가용성: Primary 장애 시 Secondary가 응답
- 부하 분산: 쿼리를 분산 처리
- 지리적 분산: 사용자와 가까운 곳에 배치
- RFC 2182 권장: 최소 2개의 네임서버 운영
존 전송 (Zone Transfer): AXFR vs IXFR
Primary에서 Secondary로 존 데이터를 복제하는 방식입니다.
| 방식 | 설명 | 용도 |
|---|---|---|
| AXFR | 전체 존 파일 전송 | 초기 동기화, 데이터 불일치 시 |
| IXFR | 변경분만 전송 | 일반적인 증분 업데이트 |
# AXFR 테스트 (보안상 외부에서는 차단되어야 함)
dig @ns1.example.com example.com AXFR
# SOA 레코드의 Serial로 동기화 여부 확인
dig @ns1.example.com example.com SOA +short
# 2024032301 ns1.example.com. admin.example.com. ...
SOA 레코드의 Serial 번호:
관례적으로 YYYYMMDDNN 형식을 사용합니다 (예: 2026032301). Serial이 증가하면 Secondary가 존 전송을 시작합니다.
글루 레코드(Glue Record)의 필요성
도메인 example.com의 네임서버가 ns1.example.com일 때 순환 참조 문제가 발생합니다:
Q: example.com의 IP는?
→ example.com의 네임서버는 ns1.example.com
→ ns1.example.com의 IP는?
→ example.com의 네임서버에게 물어봐야 하는데...
→ 순환 참조 발생!
해결: 글루 레코드
상위 TLD 서버에 네임서버의 IP를 직접 등록합니다:
;; .com TLD 서버의 위임 레코드
example.com. IN NS ns1.example.com.
example.com. IN NS ns2.example.com.
;; 글루 레코드 (Additional Section)
ns1.example.com. IN A 203.0.113.1
ns2.example.com. IN A 203.0.113.2
주요 DNS 소프트웨어
| 소프트웨어 | 유형 | 특징 |
|---|---|---|
| BIND9 | 권한/재귀 겸용 | 가장 오래된 DNS 서버. 전체 기능 지원 |
| PowerDNS | 권한 전용 | DB 백엔드 지원 (MySQL, PostgreSQL) |
| CoreDNS | 권한/재귀 | Go 기반, 플러그인 아키텍처, K8s 기본 DNS |
| Unbound | 재귀 전용 | 가볍고 보안 중심, DNSSEC 검증 기본 |
| Knot DNS | 권한 전용 | 고성능, 현대적 설계 |
| dnsmasq | 경량 캐싱 | 소규모 네트워크/홈 라우터용 |
CoreDNS in Kubernetes
Kubernetes 1.13부터 CoreDNS가 기본 DNS 서버입니다. Pod 내에서 서비스 이름으로 통신할 수 있는 것이 CoreDNS 덕분입니다.
# CoreDNS Corefile 예시
.:53 {
errors
health {
lameduck 5s
}
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
prometheus :9153
forward . /etc/resolv.conf
cache 30
loop
reload
loadbalance
}
K8s DNS 해석 규칙:
# Pod에서 서비스 접근 시
my-service → my-service.default.svc.cluster.local
my-service.other-ns → my-service.other-ns.svc.cluster.local
my-service.other-ns.svc.cluster.local → 완전한 FQDN
# Pod의 /etc/resolv.conf
nameserver 10.96.0.10 # CoreDNS ClusterIP
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5 # 점(.) 5개 미만이면 search 도메인 추가
ndots:5의 의미:
api.example.com은 점이 2개이므로(5 미만) K8s는 먼저 api.example.com.default.svc.cluster.local 등을 시도합니다. 이것이 외부 DNS 해석을 느리게 만들 수 있어, 외부 도메인은 FQDN(마지막에 . 추가)으로 지정하는 것이 좋습니다.
3. DNS 레코드 타입 총정리
핵심 레코드 타입
| 타입 | 용도 | 예시 |
|---|---|---|
| A | IPv4 주소 매핑 | example.com. IN A 93.184.216.34 |
| AAAA | IPv6 주소 매핑 | example.com. IN AAAA 2606:2800:220:1:: |
| CNAME | 별칭 (다른 도메인으로 포인팅) | www.example.com. IN CNAME example.com. |
| MX | 메일 서버 지정 | example.com. IN MX 10 mail.example.com. |
| TXT | 텍스트 정보 (SPF, DKIM 등) | example.com. IN TXT "v=spf1 ..." |
| NS | 네임서버 지정 | example.com. IN NS ns1.example.com. |
| SOA | 존 권한 정보 | 시리얼, 리프레시, 만료 등 |
| SRV | 서비스 위치 | _sip._tcp.example.com. IN SRV 10 60 5060 sip.example.com. |
| CAA | 인증서 발급 권한 | example.com. IN CAA 0 issue "letsencrypt.org" |
| PTR | 역방향 조회 (IP→도메인) | 34.216.184.93.in-addr.arpa. IN PTR example.com. |
| NAPTR | URI 변환 규칙 | SIP, ENUM에서 사용 |
CNAME의 제약사항
# OK - 서브도메인에 CNAME
www.example.com. IN CNAME example.com.
# BAD - 루트 도메인(Apex)에 CNAME 사용 불가!
# example.com. IN CNAME other.com. (RFC 위반)
# 해결: ALIAS/ANAME (비표준) 또는 Cloudflare의 CNAME Flattening
왜 Apex에 CNAME을 쓸 수 없는가? CNAME은 해당 이름의 다른 모든 레코드와 공존할 수 없습니다. 하지만 Apex 도메인에는 반드시 SOA, NS 레코드가 존재해야 하므로 CNAME과 충돌합니다.
이메일 인증 3총사: SPF, DKIM, DMARC
이메일 스팸과 피싱을 방지하기 위한 3가지 DNS 기반 인증 체계입니다.
SPF (Sender Policy Framework):
example.com. IN TXT "v=spf1 include:_spf.google.com include:sendgrid.net ip4:203.0.113.0/24 -all"
| 메커니즘 | 의미 |
|---|---|
include:domain | 해당 도메인의 SPF도 허용 |
ip4:CIDR | 해당 IP 대역 허용 |
a | 도메인의 A 레코드 IP 허용 |
mx | MX 레코드의 IP 허용 |
-all | 위 목록 외 모두 거부 |
~all | 위 목록 외 소프트 실패 |
DKIM (DomainKeys Identified Mail):
selector1._domainkey.example.com. IN TXT "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEB..."
메일 서버가 이메일에 전자 서명을 추가하고, 수신 서버가 DNS의 공개키로 검증합니다.
DMARC (Domain-based Message Authentication, Reporting, and Conformance):
_dmarc.example.com. IN TXT "v=DMARC1; p=reject; rua=mailto:dmarc-reports@example.com; pct=100"
| 정책 | 의미 |
|---|---|
p=none | 모니터링만 (보고서 수집) |
p=quarantine | 의심스러운 메일 스팸함으로 |
p=reject | 인증 실패 메일 거부 |
실전 존 파일 예시 (BIND 형식)
$TTL 3600
$ORIGIN example.com.
@ IN SOA ns1.example.com. admin.example.com. (
2026032301 ; Serial (YYYYMMDDNN)
3600 ; Refresh (1시간)
900 ; Retry (15분)
1209600 ; Expire (2주)
86400 ; Minimum TTL (1일)
)
; 네임서버
@ IN NS ns1.example.com.
@ IN NS ns2.example.com.
; A 레코드
@ IN A 203.0.113.10
www IN A 203.0.113.10
api IN A 203.0.113.20
; AAAA 레코드
@ IN AAAA 2001:db8::10
; CNAME
blog IN CNAME example.github.io.
docs IN CNAME readthedocs.io.
; MX 레코드 (우선순위 낮은 숫자가 높은 우선순위)
@ IN MX 10 mail.example.com.
@ IN MX 20 mail2.example.com.
mail IN A 203.0.113.30
; TXT 레코드
@ IN TXT "v=spf1 include:_spf.google.com -all"
_dmarc IN TXT "v=DMARC1; p=reject; rua=mailto:dmarc@example.com"
; SRV 레코드
_sip._tcp IN SRV 10 60 5060 sip.example.com.
; CAA 레코드
@ IN CAA 0 issue "letsencrypt.org"
@ IN CAA 0 issuewild "letsencrypt.org"
4. 도메인 등록/이전 실전 가이드
도메인 등록 구조
[ICANN] ──관리──→ [레지스트리] ──위임──→ [레지스트라] ──판매──→ [리셀러]
(Verisign 등) (가비아, Namecheap 등) (호스팅 업체 등)
레지스트리(Registry): TLD 전체를 관리 (예: .com은 Verisign)
레지스트라(Registrar): ICANN 인가를 받아 도메인 등록을 대행
리셀러(Reseller): 레지스트라의 재판매 파트너
한국 레지스트라 비교
| 레지스트라 | .com 연간 비용 | .kr 연간 비용 | 특징 |
|---|---|---|---|
| 가비아 | 약 16,500원 | 약 18,700원 | 국내 최대, 부가 서비스 풍부 |
| 후이즈 | 약 15,400원 | 약 17,600원 | 가격 경쟁력 |
| 카페24 | 약 14,300원 | 약 16,500원 | 호스팅 연동 편리 |
| Hosting.kr | 약 12,100원 | 약 14,300원 | 최저가 지향 |
해외 레지스트라 비교
| 레지스트라 | .com 연간 비용 | 특징 |
|---|---|---|
| Cloudflare Registrar | 약 10.11 USD | 원가 판매, 마크업 없음 |
| Namecheap | 약 8.88 USD (첫해) | 갱신가 상승 주의 |
| Porkbun | 약 9.73 USD | 가성비 좋음 |
| Google Domains | 서비스 종료 → Squarespace 이관 | 2023년 종료 |
Cloudflare Registrar를 추천하는 이유:
- 도매가(원가) 그대로 판매 (마크업 0)
- 갱신가도 동일
- 무료 DNSSEC, Whois Privacy
- Cloudflare CDN/보안 연동 용이
도메인 이전(Transfer) 절차
1. 현재 레지스트라에서 Transfer Lock(도메인 잠금) 해제
2. Auth Code(인증 코드 / EPP 코드) 발급
3. 새 레지스트라에서 Transfer 신청 + Auth Code 입력
4. 기존 레지스트라의 승인 메일 확인 (5~7일 대기)
5. 이전 완료 후 DNS 설정 확인
주의사항:
- 등록/이전 후 60일간 재이전 불가 (ICANN 60-Day Lock)
- 만료 15일 이내의 도메인은 이전 불가
- .kr 도메인은 별도 절차 (KISA 규정)
Whois와 RDAP
# Whois 조회
whois example.com
# RDAP (Whois 후속, JSON 기반)
curl -s "https://rdap.verisign.com/com/v1/domain/example.com" | jq .
RDAP(Registration Data Access Protocol)의 장점:
- 표준화된 JSON 응답
- HTTPS로 보안 전송
- 국제화(IDN) 지원
- 차등 접근 제어 가능
5. DDNS (Dynamic DNS) 완전 가이드
DDNS가 필요한 이유
가정용 인터넷은 대부분 유동 IP를 할당받습니다. ISP가 주기적으로(또는 라우터 재시작 시) IP를 변경하기 때문에, 고정 IP 없이는 집에서 서버를 운영하기 어렵습니다.
문제:
집 서버 IP: 211.xxx.xxx.100 (어제)
집 서버 IP: 211.xxx.xxx.200 (오늘) ← IP 변경됨!
DNS: myserver.example.com → 211.xxx.xxx.100 (어제 등록)
→ 접속 불가!
해결 (DDNS):
IP 변경 감지 → 자동으로 DNS 레코드 업데이트
myserver.example.com → 211.xxx.xxx.200 (자동 갱신)
DDNS 서비스 비교
| 서비스 | 무료 | 커스텀 도메인 | 업데이트 간격 | 특징 |
|---|---|---|---|---|
| DuckDNS | 무료 | X (*.duckdns.org만) | 실시간 | 완전 무료, 오픈소스 |
| No-IP | 무료(30일 갱신) | 유료 | 5분 | 3개 무료 호스트명 |
| Cloudflare DDNS | 무료 | O (자체 도메인) | 실시간 | API로 직접 구현 필요 |
| Synology DDNS | 무료 | X (*.synology.me) | 실시간 | Synology NAS 전용 |
| Dynu | 무료 | O (4개까지) | 실시간 | IPv6 지원 |
실전 셋업 1: ddclient (Linux)
# 설치
sudo apt install ddclient
# /etc/ddclient.conf 설정 (Cloudflare 예시)
protocol=cloudflare
use=web, web=https://api.ipify.org
zone=example.com
login=your-email@example.com
password=your-cloudflare-api-token
myserver.example.com
# 서비스 시작
sudo systemctl enable ddclient
sudo systemctl start ddclient
# 상태 확인
sudo systemctl status ddclient
sudo ddclient -query
실전 셋업 2: Cloudflare API로 DDNS 직접 구현
#!/bin/bash
# cloudflare-ddns.sh
# 설정
CF_API_TOKEN="your-api-token-here"
CF_ZONE_ID="your-zone-id-here"
CF_RECORD_NAME="myserver.example.com"
CF_RECORD_ID="your-record-id-here"
# 현재 공인 IP 확인
CURRENT_IP=$(curl -s https://api.ipify.org)
# DNS에 등록된 IP 확인
DNS_IP=$(dig +short "$CF_RECORD_NAME" @1.1.1.1)
# IP가 변경되었으면 업데이트
if [ "$CURRENT_IP" != "$DNS_IP" ]; then
echo "IP changed: $DNS_IP -> $CURRENT_IP"
curl -s -X PUT \
"https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/dns_records/$CF_RECORD_ID" \
-H "Authorization: Bearer $CF_API_TOKEN" \
-H "Content-Type: application/json" \
--data "{\"type\":\"A\",\"name\":\"$CF_RECORD_NAME\",\"content\":\"$CURRENT_IP\",\"ttl\":60,\"proxied\":false}"
echo "DNS updated successfully"
else
echo "IP unchanged: $CURRENT_IP"
fi
# crontab에 등록 (5분마다 실행)
crontab -e
# */5 * * * * /home/user/cloudflare-ddns.sh >> /var/log/ddns.log 2>&1
실전 셋업 3: Docker + DDNS 자동 업데이트
# docker-compose.yml
version: '3'
services:
cloudflare-ddns:
image: oznu/cloudflare-ddns:latest
restart: always
environment:
- API_KEY=your-cloudflare-api-token
- ZONE=example.com
- SUBDOMAIN=myserver
- PROXIED=false
- RRTYPE=A
- DELETE_ON_STOP=false
- DNS_SERVER=1.1.1.1
docker-compose up -d
홈서버 운영: DDNS + Let's Encrypt + Nginx Proxy Manager
[인터넷] → [공유기 포트포워딩] → [Nginx Proxy Manager] → [서비스들]
|
Let's Encrypt
자동 SSL 발급
# docker-compose.yml - 홈서버 스택
version: '3'
services:
nginx-proxy-manager:
image: jc21/nginx-proxy-manager:latest
restart: unless-stopped
ports:
- '80:80'
- '443:443'
- '81:81' # 관리 패널
volumes:
- ./npm-data:/data
- ./npm-letsencrypt:/etc/letsencrypt
cloudflare-ddns:
image: oznu/cloudflare-ddns:latest
restart: always
environment:
- API_KEY=your-cf-token
- ZONE=example.com
- SUBDOMAIN=home
포트포워딩 + 방화벽 설정
공유기 설정:
외부 80 → 내부 192.168.1.100:80
외부 443 → 내부 192.168.1.100:443
Linux 방화벽 (UFW):
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
보안 주의사항:
- 22번(SSH) 포트는 외부에 절대 개방하지 마세요 (VPN 또는 Tailscale 사용)
- 관리 패널(81번)도 외부 차단
- fail2ban으로 브루트포스 방어
- Cloudflare Proxy를 켜면 원본 IP 노출 방지
6. nslookup 완전 활용법
기본 사용법
# 기본 조회
nslookup example.com
# Server: 8.8.8.8
# Address: 8.8.8.8#53
#
# Non-authoritative answer:
# Name: example.com
# Address: 93.184.216.34
# 특정 DNS 서버로 조회
nslookup example.com 1.1.1.1
레코드 타입별 조회
# MX 레코드 (메일 서버)
nslookup -type=mx gmail.com
# gmail.com mail exchanger = 5 gmail-smtp-in.l.google.com.
# gmail.com mail exchanger = 10 alt1.gmail-smtp-in.l.google.com.
# AAAA 레코드 (IPv6)
nslookup -type=aaaa google.com
# TXT 레코드 (SPF, DKIM 등)
nslookup -type=txt example.com
# NS 레코드 (네임서버)
nslookup -type=ns example.com
# SOA 레코드 (존 정보)
nslookup -type=soa example.com
# CAA 레코드 (인증서 발급 권한)
nslookup -type=caa example.com
# SRV 레코드 (서비스 위치)
nslookup -type=srv _sip._tcp.example.com
# ANY (모든 레코드 - 일부 서버는 차단)
nslookup -type=any example.com
대화형 모드
nslookup
> server 8.8.8.8 # DNS 서버 변경
> set type=mx # 레코드 타입 설정
> gmail.com # 조회
> set type=txt
> example.com
> set debug # 디버그 모드 ON
> example.com # 상세 정보 출력
> set d2 # 더 상세한 디버그
> exit
역방향 조회 (PTR)
# IP → 도메인 조회
nslookup 8.8.8.8
# 8.8.8.8.in-addr.arpa name = dns.google.
nslookup 1.1.1.1
# 1.1.1.1.in-addr.arpa name = one.one.one.one.
실전 예제 10가지
# 1. 특정 도메인의 네임서버 확인
nslookup -type=ns example.com
# 2. 메일 서버 확인 (이메일 문제 디버깅)
nslookup -type=mx company.com
# 3. SPF 레코드 확인 (이메일 스팸 문제)
nslookup -type=txt example.com
# 4. Google DNS vs Cloudflare DNS 비교
nslookup example.com 8.8.8.8
nslookup example.com 1.1.1.1
# 5. IPv6 주소 확인
nslookup -type=aaaa facebook.com
# 6. 와일드카드 서브도메인 테스트
nslookup nonexistent-sub.example.com
# 7. CAA 레코드 확인 (SSL 인증서 발급 전)
nslookup -type=caa example.com
# 8. 역방향 DNS 확인 (IP 소유자 파악)
nslookup 203.0.113.1
# 9. CNAME 체인 추적
nslookup -type=cname www.example.com
# 10. SOA 레코드로 DNS 관리자 확인
nslookup -type=soa example.com
7. dig 명령어 마스터리
dig vs nslookup 차이점
| 항목 | dig | nslookup |
|---|---|---|
| 출력 | 상세 (섹션별 구분) | 간략 |
| DNSSEC | 지원 (+dnssec) | 미지원 |
| 추적 | 지원 (+trace) | 미지원 |
| 배치 모드 | 지원 (-f) | 미지원 |
| 설치 | bind-utils/dnsutils | 대부분 기본 설치 |
| 권장 | DevOps/SRE | 간단한 확인 |
기본 사용법
# 기본 조회
dig example.com
# 출력 구조:
# ;; QUESTION SECTION: ← 질문
# ;example.com. IN A
#
# ;; ANSWER SECTION: ← 응답
# example.com. 3600 IN A 93.184.216.34
#
# ;; AUTHORITY SECTION: ← 권한 있는 네임서버
# example.com. 3600 IN NS a.iana-servers.net.
#
# ;; ADDITIONAL SECTION: ← 추가 정보
# a.iana-servers.net. 3600 IN A 199.43.135.53
#
# ;; Query time: 23 msec
# ;; SERVER: 8.8.8.8#53(8.8.8.8)
자주 쓰는 옵션
# 짧은 출력 (IP만)
dig +short example.com
# 93.184.216.34
# 특정 레코드 타입
dig example.com MX
dig example.com AAAA
dig example.com TXT
dig example.com NS
dig example.com SOA
dig example.com CAA
# 특정 DNS 서버 지정
dig @8.8.8.8 example.com
dig @1.1.1.1 example.com
# 응답 시간만 확인
dig example.com | grep "Query time"
# ;; Query time: 23 msec
Root부터 추적: +trace
# DNS 해석 전체 과정을 Root부터 추적
dig +trace example.com
# 출력 (요약):
# . 518400 IN NS a.root-servers.net. ← Root
# com. 172800 IN NS a.gtld-servers.net. ← TLD
# example.com. 86400 IN NS a.iana-servers.net. ← Authoritative
# example.com. 3600 IN A 93.184.216.34 ← 최종 답
이것은 DNS 트러블슈팅에서 가장 유용한 명령 중 하나입니다. 어느 단계에서 문제가 발생하는지 정확히 알 수 있습니다.
DNSSEC 검증
# DNSSEC 서명 정보 확인
dig +dnssec example.com
# DNSSEC 유효성 검증
dig +sigchase +trusted-key=/etc/trusted-key.key example.com
# DNSSEC 관련 레코드 직접 조회
dig example.com DNSKEY
dig example.com DS
dig example.com RRSIG
dig example.com NSEC
배치 조회
# domains.txt 파일의 모든 도메인 한 번에 조회
cat domains.txt
# example.com
# google.com
# github.com
dig -f domains.txt +short
# 특정 레코드 타입으로 배치 조회
dig -f domains.txt MX +short
고급 옵션
# TCP 모드로 조회 (UDP 대신)
dig +tcp example.com
# 응답의 특정 섹션만 출력
dig +noall +answer example.com # 응답만
dig +noall +authority example.com # 권한 섹션만
dig +noall +stats example.com # 통계만
# TTL 포함 축약 출력
dig +nocmd +noall +answer +ttlid example.com
# 역방향 조회
dig -x 8.8.8.8
# 8.8.8.8.in-addr.arpa. IN PTR dns.google.
# CHAOS 클래스로 DNS 서버 버전 확인
dig @ns1.example.com version.bind CHAOS TXT
# EDNS Client Subnet 테스트
dig +subnet=203.0.113.0/24 example.com @8.8.8.8
실전 예제 15가지
# 1. 특정 네임서버에서 권한 있는 응답 확인
dig @ns1.example.com example.com +norecurse
# 2. DNS 전파 확인 (여러 DNS 서버 비교)
for dns in 8.8.8.8 1.1.1.1 9.9.9.9 208.67.222.222; do
echo "=== $dns ==="
dig @$dns example.com +short
done
# 3. CNAME 체인 전체 추적
dig +trace +nodnssec www.example.com CNAME
# 4. MX 레코드 우선순위 확인
dig example.com MX +short | sort -n
# 5. SPF 레코드 확인
dig example.com TXT +short | grep spf
# 6. DKIM 레코드 확인
dig selector1._domainkey.example.com TXT +short
# 7. DMARC 정책 확인
dig _dmarc.example.com TXT +short
# 8. CAA 레코드 확인 (SSL 발급 전)
dig example.com CAA +short
# 9. SOA 레코드의 시리얼 번호 확인 (존 전송 동기화)
dig example.com SOA +short
# 10. 응답 시간 비교 (DNS 성능 테스트)
for i in $(seq 1 10); do
dig example.com @8.8.8.8 | grep "Query time"
done
# 11. IPv6 레코드 확인
dig example.com AAAA +short
# 12. 와일드카드 DNS 확인
dig random-subdomain.example.com +short
# 13. NSEC/NSEC3 레코드로 DNSSEC 부정 존재 증명
dig nonexistent.example.com NSEC
# 14. DNS 응답 크기 확인 (DDoS 증폭 테스트)
dig example.com ANY +bufsize=4096
# 15. 전체 존 내보내기 시도 (보안 감사)
dig @ns1.example.com example.com AXFR
8. DNS 보안
DNS 공격 유형
1. DNS Cache Poisoning (캐시 오염)
정상: 리졸버 → Authoritative NS → 정확한 IP
공격: 공격자가 가짜 응답을 리졸버 캐시에 주입
결과: 사용자가 피싱 사이트로 유도됨
방어: DNSSEC, 랜덤 소스 포트, 0x20 인코딩
2. DNS Amplification DDoS
공격 방식:
1. 공격자가 피해자 IP로 소스 주소를 위조 (IP Spoofing)
2. 오픈 리졸버에 큰 응답을 유발하는 쿼리 전송 (ANY 타입)
3. 작은 쿼리 → 큰 응답 = 증폭 효과 (50~70배)
4. 모든 응답이 피해자에게 집중
방어: BCP38(소스 주소 검증), RRL(Response Rate Limiting)
3. DNS Hijacking
방식 1: 라우터/ISP 수준에서 DNS 응답 변조
방식 2: 레지스트라 계정 탈취 → 네임서버 변경
방식 3: 악성코드가 시스템 DNS 설정 변경
방어: DNSSEC, 레지스트라 계정 2FA, DNS 모니터링
4. DNS Tunneling
목적: DNS 프로토콜을 악용하여 데이터 유출/원격 제어
방식: DNS 쿼리/응답에 인코딩된 데이터를 숨김
예: malicious-data.encoded.evil.com 으로 TXT 쿼리
→ 방화벽은 정상 DNS 트래픽으로 인식
방어: DNS 쿼리 길이/빈도 모니터링, DNS 방화벽
DNSSEC 동작 원리
DNSSEC은 DNS 응답의 무결성과 출처를 암호학적으로 검증합니다.
신뢰의 체인 (Chain of Trust):
Root (.) → .com → example.com
각 레벨에서:
1. DNSKEY: 존의 공개키
2. RRSIG: 각 레코드의 전자 서명
3. DS: 하위 존의 공개키 해시 (상위 존에 저장)
4. NSEC/NSEC3: "이 이름은 존재하지 않음"의 증명
# DNSSEC 검증 확인
dig +dnssec example.com
# 응답에 'ad' 플래그가 있으면 DNSSEC 검증 성공
# flags: qr rd ra ad; QUERY: 1, ANSWER: 2
# DNSKEY 조회
dig example.com DNSKEY +short
# DS 레코드 조회 (상위 존에서)
dig example.com DS +short
DNS over HTTPS (DoH) / DNS over TLS (DoT)
기존 DNS는 평문 UDP/TCP로 전송되어 ISP나 네트워크 관리자가 DNS 쿼리를 열람/조작할 수 있습니다.
| 프로토콜 | 포트 | 암호화 | 특징 |
|---|---|---|---|
| 일반 DNS | 53 (UDP/TCP) | 없음 | 도청/조작 가능 |
| DoT | 853 (TCP) | TLS | 전용 포트로 차단 가능 |
| DoH | 443 (HTTPS) | HTTPS | HTTPS 트래픽에 숨어 차단 어려움 |
| DoQ | 853 (QUIC) | QUIC | 최신, 낮은 지연 |
# DoH로 DNS 조회 (curl)
curl -s -H "accept: application/dns-json" \
"https://1.1.1.1/dns-query?name=example.com&type=A" | jq .
# DoH 서비스
# Cloudflare: https://1.1.1.1/dns-query
# Google: https://dns.google/dns-query
# Quad9: https://dns.quad9.net/dns-query
# DoT 테스트 (kdig 사용)
kdig -d @1.1.1.1 +tls-ca +tls-host=cloudflare-dns.com example.com
DNS Filtering: Pi-hole, NextDNS, AdGuard Home
[디바이스] → [DNS 필터] → [허용된 쿼리만 통과] → [인터넷]
|
광고/악성 도메인 차단
트래커 차단
성인 콘텐츠 필터링
| 솔루션 | 유형 | 특징 |
|---|---|---|
| Pi-hole | 자체 호스팅 | Raspberry Pi에서 운영, 네트워크 전체 적용 |
| NextDNS | 클라우드 | 월 30만 쿼리 무료, 설정 간편 |
| AdGuard Home | 자체 호스팅 | DoH/DoT 지원, 웹 UI |
기업용: DNS Firewall과 RPZ
RPZ (Response Policy Zone):
DNS 방화벽에서 특정 도메인에 대한 응답을 재정의하는 기술
예시 (BIND RPZ):
; rpz.db
evil-domain.com CNAME . ; NXDOMAIN 응답
malware-c2.com CNAME . ; 차단
phishing-site.com A 10.0.0.1 ; 경고 페이지로 리다이렉트
9. 실전 트러블슈팅 10가지 시나리오
시나리오 1: 도메인 등록했는데 접속이 안 됨 (전파 지연)
증상: 도메인을 등록하고 A 레코드를 설정했는데 브라우저에서 접속이 안 됩니다.
원인: DNS 전파(Propagation)는 전 세계 DNS 서버의 캐시가 갱신되는 데 최대 48시간이 소요됩니다.
# 진단
# 1. 권한 있는 네임서버에서 직접 확인 (이것이 되면 설정은 정상)
dig @ns1.your-dns-provider.com yourdomain.com A +short
# 2. 여러 공개 DNS로 전파 상태 확인
dig @8.8.8.8 yourdomain.com +short
dig @1.1.1.1 yourdomain.com +short
dig @9.9.9.9 yourdomain.com +short
# 3. 온라인 도구로 전 세계 전파 확인
# https://www.whatsmydns.net/
해결:
- 기다립니다 (최대 48시간, 보통 1~4시간)
- 로컬 DNS 캐시 강제 삭제:
ipconfig /flushdns(Windows) 또는sudo dscacheutil -flushcache(macOS) - 사전에 TTL을 낮게 설정했다면 더 빠르게 전파됩니다
시나리오 2: SSL 인증서 발급 실패 (CAA 레코드)
증상: Let's Encrypt로 SSL 인증서를 발급하려는데 실패합니다.
# 진단: CAA 레코드 확인
dig yourdomain.com CAA +short
# 0 issue "digicert.com" ← Let's Encrypt가 허용 목록에 없음!
# 해결: CAA 레코드 추가 또는 수정
# yourdomain.com. IN CAA 0 issue "letsencrypt.org"
# yourdomain.com. IN CAA 0 issuewild "letsencrypt.org"
# CAA 레코드가 없으면 모든 CA가 발급 가능 (기본값)
dig yourdomain.com CAA +short
# (빈 응답 = 제한 없음)
시나리오 3: 이메일이 스팸함으로 감 (SPF/DKIM/DMARC)
증상: 발송한 이메일이 수신자의 스팸함으로 들어갑니다.
# 진단 1: SPF 레코드 확인
dig yourdomain.com TXT +short | grep spf
# "v=spf1 include:_spf.google.com -all"
# 진단 2: DKIM 레코드 확인 (selector는 이메일 헤더에서 확인)
dig google._domainkey.yourdomain.com TXT +short
# 진단 3: DMARC 정책 확인
dig _dmarc.yourdomain.com TXT +short
# "v=DMARC1; p=none; rua=mailto:dmarc@yourdomain.com"
# 해결 체크리스트:
# 1. SPF에 메일 발송 서버 IP/도메인 포함 확인
# 2. DKIM 서명 키 등록 확인
# 3. DMARC 정책 설정 (처음엔 p=none으로 모니터링)
# 4. DMARC 보고서 분석 후 p=quarantine → p=reject 순서로 강화
시나리오 4: 서브도메인이 작동하지 않음
증상: api.example.com은 되는데 staging.example.com은 안 됩니다.
# 진단: 해당 서브도메인 레코드 존재 여부 확인
dig staging.example.com A +short
# (빈 응답 = 레코드 없음)
dig api.example.com A +short
# 203.0.113.20 (정상)
# 와일드카드 레코드 확인
dig *.example.com A +short
해결:
- 해당 서브도메인의 A/CNAME 레코드를 명시적으로 추가
- 또는 와일드카드(
*.example.com) 레코드 설정 - 와일드카드는 명시적 레코드보다 우선순위가 낮음을 기억하세요
시나리오 5: DNS 변경 후 일부 사용자만 접속 불가 (TTL 캐시)
증상: DNS 레코드를 변경했는데, 어떤 사용자는 새 서버로 접속하고 어떤 사용자는 이전 서버로 접속합니다.
# 진단: 각 DNS 서버의 캐시 상태 확인
dig @8.8.8.8 example.com +short # Google DNS
dig @1.1.1.1 example.com +short # Cloudflare DNS
dig @168.126.63.1 example.com +short # KT DNS
# TTL 확인
dig example.com | grep -A1 "ANSWER SECTION"
# example.com. 1800 IN A 203.0.113.10
# ↑ 남은 TTL이 아직 높음
해결:
- TTL 시간만큼 기다립니다
- 다음부터는 DNS 변경 24시간 전에 TTL을 60초로 낮추세요
- 변경 완료 후 TTL을 원래 값으로 복구
시나리오 6: nslookup은 되는데 브라우저 접속 불가
증상: nslookup example.com은 정상 응답하는데 Chrome에서 접속이 안 됩니다.
# 진단 1: hosts 파일 확인
cat /etc/hosts # Linux/macOS
type C:\Windows\System32\drivers\etc\hosts # Windows
# 진단 2: 브라우저 DNS 캐시 확인
# Chrome: chrome://net-internals/#dns → Clear host cache
# 진단 3: HSTS 문제 확인
# Chrome: chrome://net-internals/#hsts
# 도메인 삭제 후 재시도
# 진단 4: 프록시/VPN 설정 확인
# 브라우저 프록시 설정이 DNS를 우회할 수 있음
# 진단 5: DNS over HTTPS 설정 확인
# Chrome 설정 → 개인 정보 보호 및 보안 → 보안 DNS 사용
시나리오 7: 도메인 이전 후 DNS 끊김
증상: 도메인을 다른 레지스트라로 이전한 후 사이트가 다운되었습니다.
# 진단: 현재 네임서버 확인
dig example.com NS +short
# 이전 레지스트라의 네임서버가 보이면 아직 업데이트 안 됨
# 해결 순서:
# 1. 새 레지스트라에서 DNS 레코드를 먼저 설정
# 2. 이전 전에 모든 레코드를 새 곳에 복제
# 3. 네임서버 변경
# 4. 이전 네임서버는 최소 48시간 유지
예방법: 이전 전에 반드시 새 레지스트라에 모든 DNS 레코드를 먼저 설정하세요.
시나리오 8: K8s 내부 DNS 해석 실패 (CoreDNS, ndots)
증상: Pod에서 외부 도메인(api.external.com)에 접속이 안 되거나 매우 느립니다.
# 진단 1: Pod 내에서 DNS 해석 테스트
kubectl exec -it debug-pod -- nslookup api.external.com
# 진단 2: resolv.conf 확인
kubectl exec -it debug-pod -- cat /etc/resolv.conf
# nameserver 10.96.0.10
# search default.svc.cluster.local svc.cluster.local cluster.local
# options ndots:5
# 진단 3: CoreDNS 로그 확인
kubectl logs -n kube-system -l k8s-app=kube-dns
# 문제: ndots:5 때문에 api.external.com (점 2개)이
# api.external.com.default.svc.cluster.local 등을 먼저 시도
해결:
# 방법 1: FQDN 사용 (마지막에 점 추가)
# 코드에서 api.external.com. 으로 호출
# 방법 2: Pod의 dnsConfig 설정
apiVersion: v1
kind: Pod
spec:
dnsConfig:
options:
- name: ndots
value: '2'
시나리오 9: CDN 연동 후 원본 서버 IP 노출 (DNS Leak)
증상: Cloudflare를 사용 중인데 원본 서버 IP가 노출되어 DDoS 공격을 직접 받습니다.
# 진단: 프록시되지 않는 레코드 확인
# Cloudflare 대시보드에서 주황색 구름(프록시 활성)이 아닌
# 회색 구름(DNS Only) 레코드가 있는지 확인
# 서브도메인 스캔으로 노출 여부 확인
dig direct.example.com +short # 원본 IP 노출?
dig mail.example.com +short # MX용 A레코드에 원본 IP?
dig ftp.example.com +short # FTP 서브도메인에 원본 IP?
해결:
- 모든 A/AAAA 레코드에 Cloudflare 프록시 활성화
- MX에 필요한 A 레코드는 별도 IP 사용
- 원본 IP가 이미 노출되었다면 서버 IP를 변경
- 과거 DNS 기록 확인: SecurityTrails, DNS History 등에 원본 IP가 남아있을 수 있음
시나리오 10: DDNS 업데이트가 반영되지 않음
증상: DDNS 서비스를 설정했는데 IP가 변경되어도 DNS가 업데이트되지 않습니다.
# 진단 1: 현재 공인 IP 확인
curl -s https://api.ipify.org
# 진단 2: DNS에 등록된 IP 확인
dig myserver.example.com +short
# 진단 3: DDNS 클라이언트 로그 확인
sudo journalctl -u ddclient -n 50
# 진단 4: API 토큰 유효성 확인
curl -s -X GET "https://api.cloudflare.com/client/v4/user/tokens/verify" \
-H "Authorization: Bearer YOUR_TOKEN" | jq .
# 일반적인 원인:
# 1. API 토큰 만료 또는 권한 부족
# 2. Zone ID 또는 Record ID 오류
# 3. 방화벽이 DDNS 클라이언트의 외부 통신 차단
# 4. cron 작업이 비활성화됨
# 5. IP 확인 서비스(ipify 등) 접속 불가
10. DNS 서비스 비교표
관리형 DNS 서비스
| 서비스 | 무료 플랜 | 관리 DNS | DDNS | DNSSEC | DDoS 방어 | 가격 (유료) |
|---|---|---|---|---|---|---|
| Cloudflare | O (무제한) | O | API로 구현 | O (무료) | O | 무료~엔터프라이즈 |
| AWS Route 53 | X | O | X | O | O (Shield) | 월 0.50 USD/존 |
| Google Cloud DNS | X | O | X | O | O | 월 0.20 USD/존 |
| Azure DNS | X | O | X | O (프리뷰) | O | 월 0.50 USD/존 |
| NS1 | 무료 티어 | O | O | O | O | 커스텀 |
| Dyn (Oracle) | X | O | O | O | O | 커스텀 |
퍼블릭 DNS 리졸버
| 서비스 | Primary | Secondary | DoH | DoT | DNSSEC 검증 | 특징 |
|---|---|---|---|---|---|---|
| Google DNS | 8.8.8.8 | 8.8.4.4 | O | O | O | 가장 널리 사용 |
| Cloudflare | 1.1.1.1 | 1.0.0.1 | O | O | O | 가장 빠름 |
| Quad9 | 9.9.9.9 | 149.112.112.112 | O | O | O | 악성 도메인 차단 |
| OpenDNS | 208.67.222.222 | 208.67.220.220 | O | X | O | 필터링 옵션 |
| AdGuard DNS | 94.140.14.14 | 94.140.15.15 | O | O | O | 광고 차단 |
추천 시나리오별 선택
| 시나리오 | 추천 서비스 | 이유 |
|---|---|---|
| 개인 블로그/사이트 | Cloudflare (무료) | 무료 DNS + CDN + SSL |
| 스타트업 | Cloudflare Pro 또는 Route 53 | 확장성 + 안정성 |
| 대기업 | Route 53 + Cloudflare | 멀티 DNS + 지연 기반 라우팅 |
| 홈서버 | Cloudflare + DDNS | 무료 + 동적 IP 지원 |
| K8s 클러스터 | CoreDNS + External-DNS | 자동화된 DNS 관리 |
실전 퀴즈
Q1: DNS 쿼리에서 재귀적(Recursive) 쿼리와 반복적(Iterative) 쿼리의 차이는?
재귀적 쿼리: 클라이언트가 재귀 리졸버에게 최종 답을 요청합니다. 리졸버가 모든 중간 과정을 대신 처리하고 최종 IP 주소를 돌려줍니다.
반복적 쿼리: 재귀 리졸버가 각 단계의 네임서버(Root, TLD, Authoritative)에게 순서대로 질의합니다. 각 서버는 최종 답 대신 "다음에 물어볼 서버"를 안내합니다.
일반적으로 클라이언트 → 리졸버는 재귀적, 리졸버 → 네임서버들은 반복적 쿼리를 사용합니다.
Q2: 루트 도메인(Apex)에 CNAME 레코드를 설정할 수 없는 이유는?
RFC에 따르면 CNAME은 해당 이름에 대한 유일한 레코드여야 합니다. 즉, CNAME이 있으면 같은 이름에 다른 레코드(A, MX, NS, SOA 등)가 존재할 수 없습니다.
하지만 루트 도메인에는 반드시 SOA와 NS 레코드가 있어야 하므로, CNAME과 공존할 수 없어 설정이 불가능합니다.
대안으로 Cloudflare의 CNAME Flattening이나 일부 DNS 제공자의 ALIAS/ANAME 레코드를 사용할 수 있습니다.
Q3: TTL을 60초로 설정했는데 DNS 변경이 48시간이 지나도 반영되지 않는 이유는?
가능한 원인:
- TTL을 낮추기 전의 캐시가 아직 남아있을 수 있습니다. TTL 변경 자체도 이전 TTL 시간만큼 전파가 필요합니다.
- 일부 ISP DNS 서버는 자체적으로 최소 TTL을 강제합니다 (예: 최소 300초).
- 클라이언트의 OS나 브라우저 캐시가 DNS를 자체적으로 캐시합니다.
- 네임서버 자체를 변경한 경우, TLD 레벨에서 전파에 최대 48시간이 소요됩니다.
해결: DNS 변경 24시간 전에 TTL을 미리 낮춰두고, 변경 후에는 ipconfig /flushdns 등으로 로컬 캐시를 삭제합니다.
Q4: DNSSEC는 DNS 쿼리를 암호화하는 기술인가?
아닙니다. DNSSEC는 DNS 응답의 **무결성(Integrity)**과 **출처(Authenticity)**를 검증하는 기술이지, 암호화(Encryption) 기술이 아닙니다.
DNSSEC으로 보호된 DNS 응답도 여전히 평문으로 전송됩니다. 즉, DNS 쿼리 내용은 네트워크에서 여전히 볼 수 있습니다.
DNS 쿼리의 암호화(프라이버시)를 원하면 DNS over HTTPS(DoH) 또는 DNS over TLS(DoT)를 사용해야 합니다.
정리하면:
- DNSSEC = 응답 위변조 방지 (무결성)
- DoH/DoT = 쿼리 암호화 (프라이버시)
- 둘 다 사용하면 최적의 보안
Q5: K8s Pod에서 외부 도메인 api.external.com에 접속이 느린 이유와 해결 방법은?
원인: Kubernetes의 기본 DNS 설정에서 ndots:5로 인해, 점(.)이 5개 미만인 도메인은 search 도메인을 먼저 추가하여 조회합니다.
api.external.com은 점이 2개이므로, 실제 쿼리 순서는:
api.external.com.default.svc.cluster.local(NXDOMAIN)api.external.com.svc.cluster.local(NXDOMAIN)api.external.com.cluster.local(NXDOMAIN)api.external.com.(성공)
3번의 불필요한 쿼리 후에야 실제 해석이 됩니다.
해결 방법:
- FQDN 사용:
api.external.com.(마지막에 점 추가) - Pod의 dnsConfig에서 ndots를 낮은 값(예: 2)으로 설정
- 자주 접근하는 외부 도메인은 CoreDNS에 캐싱 규칙 추가
참고 자료
RFC 문서
- RFC 1034 - Domain Names - Concepts and Facilities
- RFC 1035 - Domain Names - Implementation and Specification
- RFC 2136 - Dynamic Updates in the DNS (DDNS)
- RFC 2181 - Clarifications to the DNS Specification
- RFC 2308 - Negative Caching of DNS Queries
- RFC 4033, 4034, 4035 - DNS Security Extensions (DNSSEC)
- RFC 6698 - DNS-Based Authentication (DANE/TLSA)
- RFC 7208 - SPF (Sender Policy Framework)
- RFC 7489 - DMARC
- RFC 8484 - DNS over HTTPS (DoH)
- RFC 7858 - DNS over TLS (DoT)
- RFC 8659 - DNS Certification Authority Authorization (CAA)
도구 및 서비스
- dig / nslookup - DNS 조회 명령줄 도구
- whatsmydns.net - 글로벌 DNS 전파 확인
- dnschecker.org - DNS 레코드 확인
- mxtoolbox.com - 이메일 DNS 진단 (SPF, DKIM, DMARC)
- securitytrails.com - DNS 히스토리 조회
- dnsviz.net - DNSSEC 시각화 및 검증
DNS 소프트웨어
- BIND9 - https://www.isc.org/bind/
- CoreDNS - https://coredns.io/
- PowerDNS - https://www.powerdns.com/
- Unbound - https://nlnetlabs.nl/projects/unbound/
- Knot DNS - https://www.knot-dns.cz/
학습 자료
- Cloudflare Learning Center - DNS 개념 (learning.cloudflare.com)
- howdns.works - DNS 동작 시각적 설명
- messwithdns.net - DNS 실습 환경
- Julia Evans - DNS 관련 블로그 및 zines
DNS Complete Guide: Name Servers, DDNS, nslookup — From Domain Registration to Troubleshooting
- 1. Understanding How DNS Works
- 2. Name Servers Deep Dive
- 3. DNS Record Types Complete Reference
- 4. Domain Registration and Transfer Practical Guide
- 5. DDNS (Dynamic DNS) Complete Guide
- 6. nslookup Complete Usage Guide
- 7. Mastering the dig Command
- 8. DNS Security
- 9. 10 Real-World Troubleshooting Scenarios
- Scenario 1: Domain Registered But Cannot Access (Propagation Delay)
- Scenario 2: SSL Certificate Issuance Failure (CAA Record)
- Scenario 3: Emails Going to Spam (SPF/DKIM/DMARC)
- Scenario 4: Subdomain Not Working
- Scenario 5: Some Users Cannot Access After DNS Change (TTL Cache)
- Scenario 6: nslookup Works But Browser Cannot Connect
- Scenario 7: DNS Outage After Domain Transfer
- Scenario 8: K8s Internal DNS Resolution Failure (CoreDNS, ndots)
- Scenario 9: Origin Server IP Exposed After CDN Integration (DNS Leak)
- Scenario 10: DDNS Updates Not Reflecting
- 10. DNS Service Comparison
- Quiz
- References
1. Understanding How DNS Works
What is DNS? The Internet's Phone Book
DNS (Domain Name System) is the system that translates human-readable domain names (e.g., www.example.com) into computer-understandable IP addresses (e.g., 93.184.216.34). It was first proposed by Paul Mockapetris in 1983 through RFC 882 and 883, with RFC 1034 and 1035 serving as the current base specifications.
Without DNS, we would need to type IP addresses directly to visit any website. DNS is the most fundamental yet critical component of internet infrastructure.
User input: www.example.com
|
DNS Resolution
|
IP address: 93.184.216.34
|
HTTP request to server
DNS Hierarchy: From Root to Subdomain
DNS is a hierarchical distributed database with a tree structure. From top to bottom:
. (Root)
/ \
com org net kr jp ... (TLD - Top Level Domain)
|
example (SLD - Second Level Domain)
/ \
www mail api (Subdomain)
Role of each level:
| Level | Example | Managed By |
|---|---|---|
| Root (.) | . | ICANN / IANA |
| TLD | .com, .kr, .org | Registry (Verisign, KISA, etc.) |
| SLD | example.com | Domain owner |
| Subdomain | www.example.com | Domain owner |
An FQDN (Fully Qualified Domain Name) includes a trailing dot: www.example.com.
DNS Query Flow: Recursive vs Iterative
DNS resolution uses a combination of two query types.
Recursive Query: The client asks a recursive resolver to "give me the final answer." The resolver handles everything on the client's behalf.
Iterative Query: The recursive resolver asks each name server "who knows about this domain?" and each server responds with "I don't know, but ask over there," pointing to the next server.
[User PC] -- Recursive Query --> [Recursive Resolver (ISP/8.8.8.8)]
|
Iterative Queries Begin
|
+---------------+---------------+
v v v
[Root Server] [TLD Server] [Authoritative NS]
".com is here" "example.com "IP is 93.x.x.x"
is here"
Detailed flow:
- User types
www.example.comin the browser - Check browser cache, OS cache, hosts file
- OS sends recursive query to configured resolver (e.g., 8.8.8.8)
- Recursive resolver checks cache; if miss, queries Root servers iteratively
- Root server: "
.comTLD server isa.gtld-servers.net" - Recursive resolver queries the TLD server
- TLD server: "Name server for
example.comisns1.example.com" - Recursive resolver queries the authoritative name server
- Authoritative NS: "IP for
www.example.comis93.184.216.34" - Recursive resolver caches the result and responds to the client
13 Root Servers and Anycast
The 13 root servers (A through M) are the starting point of all DNS. Despite being only 13 in name, Anycast technology distributes them across over 1,700 instances worldwide.
| Root Server | Operator | Instances (approx.) |
|---|---|---|
| A | Verisign | 10+ |
| B | USC-ISI | 6+ |
| C | Cogent | 10+ |
| D | University of Maryland | 200+ |
| E | NASA | 300+ |
| F | ISC | 300+ |
| J | Verisign | 200+ |
| K | RIPE NCC | 100+ |
| L | ICANN | 200+ |
| M | WIDE Project | 10+ |
What is Anycast? A technique that assigns the same IP address to multiple physical servers. User queries are automatically routed to the nearest instance via BGP routing. This is why only 13 root server IPs can serve the entire world with fast responses.
DNS Caching: The Key to Performance
DNS caching occurs at multiple levels:
[Browser Cache] -> [OS Cache] -> [Recursive Resolver Cache] -> [TTL from each NS response]
Chrome: chrome://net-internals/#dns to inspect
Windows: ipconfig /displaydns
Linux: systemd-resolve --statistics
macOS: sudo dscacheutil -flushcache
Understanding TTL (Time To Live):
example.com. 3600 IN A 93.184.216.34
^
TTL = 3600 seconds (1 hour)
TTL strategy based on values:
| TTL Value | Use Case | Pros | Cons |
|---|---|---|---|
| 60s | Before DNS changes | Fast propagation | More queries, slower responses |
| 300s (5 min) | General services | Balanced choice | - |
| 3600s (1 hour) | Stable services | Fast responses, fewer queries | Slow change propagation |
| 86400s (1 day) | Rarely changing records | Best performance | Difficult emergency changes |
Pro tip: Lower TTL to 60 seconds before making DNS changes, then raise it back once propagation is complete.
2. Name Servers Deep Dive
Authoritative vs Recursive Name Servers
| Aspect | Authoritative NS | Recursive Resolver |
|---|---|---|
| Role | Holds definitive info for a domain | Traverses DNS tree on behalf of clients |
| Data | Original data from zone files | Cached data |
| Example | ns1.cloudflare.com | 8.8.8.8 (Google DNS) |
| Operator | Domain owner/hosting provider | ISP, Google, Cloudflare |
| Response flag | AA (Authoritative Answer) bit set | No AA bit |
Primary (Master) vs Secondary (Slave) Name Servers
Authoritative name servers are further divided into Primary and Secondary.
[Primary NS] --Zone Transfer--> [Secondary NS]
(read/write) (read only)
Manages original zone file Backup when Primary fails
Add/modify/delete records Load distribution role
Why are Secondary servers needed?
- High availability: Secondary responds when Primary fails
- Load distribution: Queries are spread across servers
- Geographic distribution: Placed near users
- RFC 2182 recommends: At least 2 name servers
Zone Transfer: AXFR vs IXFR
Methods for replicating zone data from Primary to Secondary.
| Method | Description | Use Case |
|---|---|---|
| AXFR | Full zone file transfer | Initial sync, data inconsistency |
| IXFR | Incremental transfer (changes only) | Regular incremental updates |
# Test AXFR (should be blocked from external sources for security)
dig @ns1.example.com example.com AXFR
# Check synchronization via SOA record Serial
dig @ns1.example.com example.com SOA +short
# 2024032301 ns1.example.com. admin.example.com. ...
SOA Record Serial Number:
Conventionally uses YYYYMMDDNN format (e.g., 2026032301). When the Serial increases, Secondary servers initiate zone transfers.
Why Glue Records Are Necessary
When domain example.com's name server is ns1.example.com, a circular reference problem occurs:
Q: What is example.com's IP?
-> example.com's name server is ns1.example.com
-> What is ns1.example.com's IP?
-> Need to ask example.com's name server, but...
-> Circular reference!
Solution: Glue Records
Register the name server's IP directly in the parent TLD server:
;; Delegation records in .com TLD server
example.com. IN NS ns1.example.com.
example.com. IN NS ns2.example.com.
;; Glue records (Additional Section)
ns1.example.com. IN A 203.0.113.1
ns2.example.com. IN A 203.0.113.2
Major DNS Software
| Software | Type | Features |
|---|---|---|
| BIND9 | Auth/Recursive | Oldest DNS server. Full feature set |
| PowerDNS | Auth only | DB backend support (MySQL, PostgreSQL) |
| CoreDNS | Auth/Recursive | Go-based, plugin architecture, K8s default DNS |
| Unbound | Recursive only | Lightweight, security-focused, DNSSEC validation by default |
| Knot DNS | Auth only | High performance, modern design |
| dnsmasq | Lightweight caching | For small networks/home routers |
CoreDNS in Kubernetes
Since Kubernetes 1.13, CoreDNS is the default DNS server. It enables Pods to communicate using service names.
# CoreDNS Corefile example
.:53 {
errors
health {
lameduck 5s
}
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
prometheus :9153
forward . /etc/resolv.conf
cache 30
loop
reload
loadbalance
}
K8s DNS Resolution Rules:
# Accessing services from a Pod
my-service -> my-service.default.svc.cluster.local
my-service.other-ns -> my-service.other-ns.svc.cluster.local
my-service.other-ns.svc.cluster.local -> Full FQDN
# Pod's /etc/resolv.conf
nameserver 10.96.0.10 # CoreDNS ClusterIP
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5 # If fewer than 5 dots, append search domains
What ndots:5 means:
api.example.com has only 2 dots (less than 5), so K8s first tries api.example.com.default.svc.cluster.local etc. This can slow down external DNS resolution. For external domains, use FQDN (add trailing .).
3. DNS Record Types Complete Reference
Core Record Types
| Type | Purpose | Example |
|---|---|---|
| A | IPv4 address mapping | example.com. IN A 93.184.216.34 |
| AAAA | IPv6 address mapping | example.com. IN AAAA 2606:2800:220:1:: |
| CNAME | Alias (points to another domain) | www.example.com. IN CNAME example.com. |
| MX | Mail server designation | example.com. IN MX 10 mail.example.com. |
| TXT | Text info (SPF, DKIM, etc.) | example.com. IN TXT "v=spf1 ..." |
| NS | Name server designation | example.com. IN NS ns1.example.com. |
| SOA | Zone authority info | Serial, refresh, expiry, etc. |
| SRV | Service location | _sip._tcp.example.com. IN SRV 10 60 5060 sip.example.com. |
| CAA | Certificate authority authorization | example.com. IN CAA 0 issue "letsencrypt.org" |
| PTR | Reverse lookup (IP to domain) | 34.216.184.93.in-addr.arpa. IN PTR example.com. |
| NAPTR | URI transformation rules | Used in SIP, ENUM |
CNAME Restrictions
# OK - CNAME on subdomain
www.example.com. IN CNAME example.com.
# BAD - Cannot use CNAME on root domain (Apex)!
# example.com. IN CNAME other.com. (RFC violation)
# Solutions: ALIAS/ANAME (non-standard) or Cloudflare's CNAME Flattening
Why can't you use CNAME on the apex? CNAME cannot coexist with any other records for the same name. But apex domains must have SOA and NS records, which conflict with CNAME.
Email Authentication Trio: SPF, DKIM, DMARC
Three DNS-based authentication systems to prevent email spam and phishing.
SPF (Sender Policy Framework):
example.com. IN TXT "v=spf1 include:_spf.google.com include:sendgrid.net ip4:203.0.113.0/24 -all"
| Mechanism | Meaning |
|---|---|
include:domain | Also allow that domain's SPF |
ip4:CIDR | Allow that IP range |
a | Allow domain's A record IP |
mx | Allow MX record IPs |
-all | Reject all others |
~all | Soft fail all others |
DKIM (DomainKeys Identified Mail):
selector1._domainkey.example.com. IN TXT "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEB..."
The mail server adds a digital signature to emails, and the receiving server verifies it using the public key from DNS.
DMARC (Domain-based Message Authentication, Reporting, and Conformance):
_dmarc.example.com. IN TXT "v=DMARC1; p=reject; rua=mailto:dmarc-reports@example.com; pct=100"
| Policy | Meaning |
|---|---|
p=none | Monitor only (collect reports) |
p=quarantine | Send suspicious mail to spam |
p=reject | Reject failed authentication |
Practical Zone File Example (BIND Format)
$TTL 3600
$ORIGIN example.com.
@ IN SOA ns1.example.com. admin.example.com. (
2026032301 ; Serial (YYYYMMDDNN)
3600 ; Refresh (1 hour)
900 ; Retry (15 min)
1209600 ; Expire (2 weeks)
86400 ; Minimum TTL (1 day)
)
; Name servers
@ IN NS ns1.example.com.
@ IN NS ns2.example.com.
; A records
@ IN A 203.0.113.10
www IN A 203.0.113.10
api IN A 203.0.113.20
; AAAA record
@ IN AAAA 2001:db8::10
; CNAME
blog IN CNAME example.github.io.
docs IN CNAME readthedocs.io.
; MX records (lower number = higher priority)
@ IN MX 10 mail.example.com.
@ IN MX 20 mail2.example.com.
mail IN A 203.0.113.30
; TXT records
@ IN TXT "v=spf1 include:_spf.google.com -all"
_dmarc IN TXT "v=DMARC1; p=reject; rua=mailto:dmarc@example.com"
; SRV record
_sip._tcp IN SRV 10 60 5060 sip.example.com.
; CAA records
@ IN CAA 0 issue "letsencrypt.org"
@ IN CAA 0 issuewild "letsencrypt.org"
4. Domain Registration and Transfer Practical Guide
Domain Registration Structure
[ICANN] --manages--> [Registry] --delegates--> [Registrar] --sells--> [Reseller]
(Verisign, etc.) (Namecheap, etc.) (Hosting, etc.)
Registry: Manages an entire TLD (e.g., .com is Verisign)
Registrar: ICANN-accredited to handle domain registration
Reseller: Resale partner of a registrar
Popular Registrar Comparison
| Registrar | .com Annual Cost | Features |
|---|---|---|
| Cloudflare Registrar | ~10.11 USD | At-cost pricing, zero markup |
| Namecheap | ~8.88 USD (first year) | Watch renewal price increases |
| Porkbun | ~9.73 USD | Good value |
| Google Domains | Service ended, migrated to Squarespace | Ended in 2023 |
| GoDaddy | ~12.99 USD | Large marketplace, upselling concerns |
| Gandi | ~15.00 USD | Privacy by default |
Why Cloudflare Registrar is recommended:
- Wholesale (at-cost) pricing with zero markup
- Renewal price stays the same
- Free DNSSEC and Whois Privacy
- Easy integration with Cloudflare CDN/security
Domain Transfer Procedure
1. Disable Transfer Lock at current registrar
2. Obtain Auth Code (EPP code) from current registrar
3. Initiate Transfer at new registrar + enter Auth Code
4. Confirm approval email from old registrar (5-7 day wait)
5. Verify DNS settings after transfer completes
Important notes:
- 60-day transfer lock after registration/transfer (ICANN 60-Day Lock)
- Cannot transfer domains expiring within 15 days
- Country-code TLDs (.kr, .jp, etc.) may have separate procedures
Whois and RDAP
# Whois lookup
whois example.com
# RDAP (Whois successor, JSON-based)
curl -s "https://rdap.verisign.com/com/v1/domain/example.com" | jq .
RDAP (Registration Data Access Protocol) advantages:
- Standardized JSON responses
- Secure transmission via HTTPS
- Internationalization (IDN) support
- Differentiated access control
5. DDNS (Dynamic DNS) Complete Guide
Why You Need DDNS
Residential internet connections typically assign dynamic IP addresses. ISPs periodically change your IP (or when the router restarts), making it difficult to run servers from home without a static IP.
Problem:
Home server IP: 211.xxx.xxx.100 (yesterday)
Home server IP: 211.xxx.xxx.200 (today) - IP changed!
DNS: myserver.example.com -> 211.xxx.xxx.100 (registered yesterday)
-> Cannot connect!
Solution (DDNS):
Detect IP change -> Automatically update DNS record
myserver.example.com -> 211.xxx.xxx.200 (auto-updated)
DDNS Service Comparison
| Service | Free | Custom Domain | Update Interval | Features |
|---|---|---|---|---|
| DuckDNS | Free | No (*.duckdns.org only) | Real-time | Fully free, open source |
| No-IP | Free (30-day renewal) | Paid | 5 min | 3 free hostnames |
| Cloudflare DDNS | Free | Yes (own domain) | Real-time | Need to implement via API |
| Synology DDNS | Free | No (*.synology.me) | Real-time | Synology NAS only |
| Dynu | Free | Yes (up to 4) | Real-time | IPv6 support |
Setup 1: ddclient (Linux)
# Install
sudo apt install ddclient
# /etc/ddclient.conf configuration (Cloudflare example)
protocol=cloudflare
use=web, web=https://api.ipify.org
zone=example.com
login=your-email@example.com
password=your-cloudflare-api-token
myserver.example.com
# Start service
sudo systemctl enable ddclient
sudo systemctl start ddclient
# Check status
sudo systemctl status ddclient
sudo ddclient -query
Setup 2: DIY DDNS with Cloudflare API
#!/bin/bash
# cloudflare-ddns.sh
# Configuration
CF_API_TOKEN="your-api-token-here"
CF_ZONE_ID="your-zone-id-here"
CF_RECORD_NAME="myserver.example.com"
CF_RECORD_ID="your-record-id-here"
# Get current public IP
CURRENT_IP=$(curl -s https://api.ipify.org)
# Get IP registered in DNS
DNS_IP=$(dig +short "$CF_RECORD_NAME" @1.1.1.1)
# Update if IP has changed
if [ "$CURRENT_IP" != "$DNS_IP" ]; then
echo "IP changed: $DNS_IP -> $CURRENT_IP"
curl -s -X PUT \
"https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/dns_records/$CF_RECORD_ID" \
-H "Authorization: Bearer $CF_API_TOKEN" \
-H "Content-Type: application/json" \
--data "{\"type\":\"A\",\"name\":\"$CF_RECORD_NAME\",\"content\":\"$CURRENT_IP\",\"ttl\":60,\"proxied\":false}"
echo "DNS updated successfully"
else
echo "IP unchanged: $CURRENT_IP"
fi
# Add to crontab (run every 5 minutes)
crontab -e
# */5 * * * * /home/user/cloudflare-ddns.sh >> /var/log/ddns.log 2>&1
Setup 3: Docker + DDNS Auto-Update
# docker-compose.yml
version: '3'
services:
cloudflare-ddns:
image: oznu/cloudflare-ddns:latest
restart: always
environment:
- API_KEY=your-cloudflare-api-token
- ZONE=example.com
- SUBDOMAIN=myserver
- PROXIED=false
- RRTYPE=A
- DELETE_ON_STOP=false
- DNS_SERVER=1.1.1.1
docker-compose up -d
Home Server Stack: DDNS + Let's Encrypt + Nginx Proxy Manager
[Internet] -> [Router Port Forwarding] -> [Nginx Proxy Manager] -> [Services]
|
Let's Encrypt
Auto SSL Issuance
# docker-compose.yml - Home server stack
version: '3'
services:
nginx-proxy-manager:
image: jc21/nginx-proxy-manager:latest
restart: unless-stopped
ports:
- '80:80'
- '443:443'
- '81:81' # Admin panel
volumes:
- ./npm-data:/data
- ./npm-letsencrypt:/etc/letsencrypt
cloudflare-ddns:
image: oznu/cloudflare-ddns:latest
restart: always
environment:
- API_KEY=your-cf-token
- ZONE=example.com
- SUBDOMAIN=home
Port Forwarding + Firewall Configuration
Router settings:
External 80 -> Internal 192.168.1.100:80
External 443 -> Internal 192.168.1.100:443
Linux firewall (UFW):
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
Security considerations:
- Never expose port 22 (SSH) externally (use VPN or Tailscale instead)
- Block admin panel (port 81) from external access
- Use fail2ban for brute force protection
- Enable Cloudflare Proxy to hide origin IP
6. nslookup Complete Usage Guide
Basic Usage
# Basic lookup
nslookup example.com
# Server: 8.8.8.8
# Address: 8.8.8.8#53
#
# Non-authoritative answer:
# Name: example.com
# Address: 93.184.216.34
# Query using a specific DNS server
nslookup example.com 1.1.1.1
Querying by Record Type
# MX records (mail servers)
nslookup -type=mx gmail.com
# gmail.com mail exchanger = 5 gmail-smtp-in.l.google.com.
# gmail.com mail exchanger = 10 alt1.gmail-smtp-in.l.google.com.
# AAAA records (IPv6)
nslookup -type=aaaa google.com
# TXT records (SPF, DKIM, etc.)
nslookup -type=txt example.com
# NS records (name servers)
nslookup -type=ns example.com
# SOA records (zone information)
nslookup -type=soa example.com
# CAA records (certificate authority authorization)
nslookup -type=caa example.com
# SRV records (service location)
nslookup -type=srv _sip._tcp.example.com
# ANY (all records - some servers block this)
nslookup -type=any example.com
Interactive Mode
nslookup
> server 8.8.8.8 # Change DNS server
> set type=mx # Set record type
> gmail.com # Query
> set type=txt
> example.com
> set debug # Debug mode ON
> example.com # Detailed output
> set d2 # More detailed debug
> exit
Reverse Lookup (PTR)
# IP -> Domain lookup
nslookup 8.8.8.8
# 8.8.8.8.in-addr.arpa name = dns.google.
nslookup 1.1.1.1
# 1.1.1.1.in-addr.arpa name = one.one.one.one.
10 Practical Examples
# 1. Check name servers for a domain
nslookup -type=ns example.com
# 2. Check mail servers (email debugging)
nslookup -type=mx company.com
# 3. Check SPF records (email spam issues)
nslookup -type=txt example.com
# 4. Compare Google DNS vs Cloudflare DNS
nslookup example.com 8.8.8.8
nslookup example.com 1.1.1.1
# 5. Check IPv6 addresses
nslookup -type=aaaa facebook.com
# 6. Test wildcard subdomains
nslookup nonexistent-sub.example.com
# 7. Check CAA records (before SSL certificate issuance)
nslookup -type=caa example.com
# 8. Reverse DNS lookup (identify IP owner)
nslookup 203.0.113.1
# 9. Trace CNAME chains
nslookup -type=cname www.example.com
# 10. Check SOA record for DNS administrator info
nslookup -type=soa example.com
7. Mastering the dig Command
dig vs nslookup Differences
| Aspect | dig | nslookup |
|---|---|---|
| Output | Detailed (section-based) | Brief |
| DNSSEC | Supported (+dnssec) | Not supported |
| Trace | Supported (+trace) | Not supported |
| Batch mode | Supported (-f) | Not supported |
| Installation | bind-utils/dnsutils | Usually pre-installed |
| Recommended for | DevOps/SRE | Quick checks |
Basic Usage
# Basic query
dig example.com
# Output structure:
# ;; QUESTION SECTION: <- Question
# ;example.com. IN A
#
# ;; ANSWER SECTION: <- Answer
# example.com. 3600 IN A 93.184.216.34
#
# ;; AUTHORITY SECTION: <- Authoritative name servers
# example.com. 3600 IN NS a.iana-servers.net.
#
# ;; ADDITIONAL SECTION: <- Additional info
# a.iana-servers.net. 3600 IN A 199.43.135.53
#
# ;; Query time: 23 msec
# ;; SERVER: 8.8.8.8#53(8.8.8.8)
Frequently Used Options
# Short output (IP only)
dig +short example.com
# 93.184.216.34
# Specific record types
dig example.com MX
dig example.com AAAA
dig example.com TXT
dig example.com NS
dig example.com SOA
dig example.com CAA
# Specify DNS server
dig @8.8.8.8 example.com
dig @1.1.1.1 example.com
# Check response time only
dig example.com | grep "Query time"
# ;; Query time: 23 msec
Tracing from Root: +trace
# Trace entire DNS resolution from Root
dig +trace example.com
# Output (summary):
# . 518400 IN NS a.root-servers.net. <- Root
# com. 172800 IN NS a.gtld-servers.net. <- TLD
# example.com. 86400 IN NS a.iana-servers.net. <- Authoritative
# example.com. 3600 IN A 93.184.216.34 <- Final answer
This is one of the most useful commands for DNS troubleshooting. You can see exactly at which step a problem occurs.
DNSSEC Verification
# Check DNSSEC signature info
dig +dnssec example.com
# Verify DNSSEC validity
dig +sigchase +trusted-key=/etc/trusted-key.key example.com
# Query DNSSEC-related records directly
dig example.com DNSKEY
dig example.com DS
dig example.com RRSIG
dig example.com NSEC
Batch Queries
# Query all domains from a file at once
cat domains.txt
# example.com
# google.com
# github.com
dig -f domains.txt +short
# Batch query for specific record type
dig -f domains.txt MX +short
Advanced Options
# TCP mode (instead of UDP)
dig +tcp example.com
# Output specific sections only
dig +noall +answer example.com # Answer only
dig +noall +authority example.com # Authority section only
dig +noall +stats example.com # Statistics only
# Abbreviated output with TTL
dig +nocmd +noall +answer +ttlid example.com
# Reverse lookup
dig -x 8.8.8.8
# 8.8.8.8.in-addr.arpa. IN PTR dns.google.
# Check DNS server version via CHAOS class
dig @ns1.example.com version.bind CHAOS TXT
# EDNS Client Subnet test
dig +subnet=203.0.113.0/24 example.com @8.8.8.8
15 Practical Examples
# 1. Check authoritative response from specific name server
dig @ns1.example.com example.com +norecurse
# 2. Check DNS propagation (compare multiple DNS servers)
for dns in 8.8.8.8 1.1.1.1 9.9.9.9 208.67.222.222; do
echo "=== $dns ==="
dig @$dns example.com +short
done
# 3. Trace full CNAME chain
dig +trace +nodnssec www.example.com CNAME
# 4. Check MX record priorities
dig example.com MX +short | sort -n
# 5. Check SPF record
dig example.com TXT +short | grep spf
# 6. Check DKIM record
dig selector1._domainkey.example.com TXT +short
# 7. Check DMARC policy
dig _dmarc.example.com TXT +short
# 8. Check CAA records (before SSL issuance)
dig example.com CAA +short
# 9. Check SOA serial number (zone transfer sync)
dig example.com SOA +short
# 10. Compare response times (DNS performance test)
for i in $(seq 1 10); do
dig example.com @8.8.8.8 | grep "Query time"
done
# 11. Check IPv6 records
dig example.com AAAA +short
# 12. Verify wildcard DNS
dig random-subdomain.example.com +short
# 13. Check NSEC/NSEC3 for DNSSEC authenticated denial
dig nonexistent.example.com NSEC
# 14. Check DNS response size (DDoS amplification test)
dig example.com ANY +bufsize=4096
# 15. Attempt full zone export (security audit)
dig @ns1.example.com example.com AXFR
8. DNS Security
DNS Attack Types
1. DNS Cache Poisoning
Normal: Resolver -> Authoritative NS -> Correct IP
Attack: Attacker injects fake response into resolver cache
Result: Users are redirected to phishing sites
Defense: DNSSEC, random source ports, 0x20 encoding
2. DNS Amplification DDoS
Attack method:
1. Attacker spoofs source IP to victim's IP
2. Sends queries that generate large responses to open resolvers (ANY type)
3. Small query -> Large response = amplification effect (50-70x)
4. All responses flood the victim
Defense: BCP38 (source address validation), RRL (Response Rate Limiting)
3. DNS Hijacking
Method 1: DNS response tampering at router/ISP level
Method 2: Registrar account compromise -> name server change
Method 3: Malware changes system DNS settings
Defense: DNSSEC, registrar 2FA, DNS monitoring
4. DNS Tunneling
Purpose: Abuse DNS protocol for data exfiltration/remote control
Method: Hide encoded data in DNS queries/responses
Example: Query TXT for malicious-data.encoded.evil.com
-> Firewall sees it as normal DNS traffic
Defense: Monitor DNS query length/frequency, DNS firewall
How DNSSEC Works
DNSSEC cryptographically verifies the integrity and origin of DNS responses.
Chain of Trust:
Root (.) -> .com -> example.com
At each level:
1. DNSKEY: Zone's public key
2. RRSIG: Digital signature for each record
3. DS: Hash of child zone's public key (stored in parent zone)
4. NSEC/NSEC3: Proof that "this name does not exist"
# Check DNSSEC verification
dig +dnssec example.com
# 'ad' flag in response means DNSSEC validation succeeded
# flags: qr rd ra ad; QUERY: 1, ANSWER: 2
# Query DNSKEY
dig example.com DNSKEY +short
# Query DS record (from parent zone)
dig example.com DS +short
DNS over HTTPS (DoH) / DNS over TLS (DoT)
Traditional DNS is sent over plaintext UDP/TCP, allowing ISPs and network administrators to view and manipulate DNS queries.
| Protocol | Port | Encryption | Features |
|---|---|---|---|
| Plain DNS | 53 (UDP/TCP) | None | Eavesdropping/tampering possible |
| DoT | 853 (TCP) | TLS | Dedicated port, blockable |
| DoH | 443 (HTTPS) | HTTPS | Hidden in HTTPS traffic, hard to block |
| DoQ | 853 (QUIC) | QUIC | Newest, low latency |
# DoH DNS query (curl)
curl -s -H "accept: application/dns-json" \
"https://1.1.1.1/dns-query?name=example.com&type=A" | jq .
# DoH services
# Cloudflare: https://1.1.1.1/dns-query
# Google: https://dns.google/dns-query
# Quad9: https://dns.quad9.net/dns-query
# DoT test (using kdig)
kdig -d @1.1.1.1 +tls-ca +tls-host=cloudflare-dns.com example.com
DNS Filtering: Pi-hole, NextDNS, AdGuard Home
[Devices] -> [DNS Filter] -> [Only allowed queries pass] -> [Internet]
|
Block ads/malicious domains
Block trackers
Filter adult content
| Solution | Type | Features |
|---|---|---|
| Pi-hole | Self-hosted | Run on Raspberry Pi, network-wide blocking |
| NextDNS | Cloud | 300K queries/month free, easy setup |
| AdGuard Home | Self-hosted | DoH/DoT support, web UI |
Enterprise: DNS Firewall and RPZ
RPZ (Response Policy Zone):
Technology to override responses for specific domains in a DNS firewall
Example (BIND RPZ):
; rpz.db
evil-domain.com CNAME . ; NXDOMAIN response
malware-c2.com CNAME . ; Block
phishing-site.com A 10.0.0.1 ; Redirect to warning page
9. 10 Real-World Troubleshooting Scenarios
Scenario 1: Domain Registered But Cannot Access (Propagation Delay)
Symptom: You registered a domain and set up an A record, but the browser cannot connect.
Cause: DNS propagation across all DNS servers worldwide can take up to 48 hours.
# Diagnosis
# 1. Check directly from authoritative name server (if this works, config is correct)
dig @ns1.your-dns-provider.com yourdomain.com A +short
# 2. Check propagation via multiple public DNS
dig @8.8.8.8 yourdomain.com +short
dig @1.1.1.1 yourdomain.com +short
dig @9.9.9.9 yourdomain.com +short
# 3. Check global propagation online
# https://www.whatsmydns.net/
Resolution:
- Wait (up to 48 hours, usually 1-4 hours)
- Force flush local DNS cache:
ipconfig /flushdns(Windows) orsudo dscacheutil -flushcache(macOS) - Setting a low TTL beforehand speeds up propagation
Scenario 2: SSL Certificate Issuance Failure (CAA Record)
Symptom: Attempting to issue an SSL certificate with Let's Encrypt but it fails.
# Diagnosis: Check CAA records
dig yourdomain.com CAA +short
# 0 issue "digicert.com" <- Let's Encrypt is not in the allow list!
# Fix: Add or modify CAA record
# yourdomain.com. IN CAA 0 issue "letsencrypt.org"
# yourdomain.com. IN CAA 0 issuewild "letsencrypt.org"
# If no CAA records exist, all CAs can issue (default behavior)
dig yourdomain.com CAA +short
# (empty response = no restrictions)
Scenario 3: Emails Going to Spam (SPF/DKIM/DMARC)
Symptom: Sent emails end up in recipients' spam folders.
# Diagnosis 1: Check SPF record
dig yourdomain.com TXT +short | grep spf
# "v=spf1 include:_spf.google.com -all"
# Diagnosis 2: Check DKIM record (selector from email headers)
dig google._domainkey.yourdomain.com TXT +short
# Diagnosis 3: Check DMARC policy
dig _dmarc.yourdomain.com TXT +short
# "v=DMARC1; p=none; rua=mailto:dmarc@yourdomain.com"
# Resolution checklist:
# 1. Verify SPF includes all mail-sending server IPs/domains
# 2. Verify DKIM signing key is registered
# 3. Set up DMARC policy (start with p=none for monitoring)
# 4. Analyze DMARC reports, then strengthen: p=quarantine -> p=reject
Scenario 4: Subdomain Not Working
Symptom: api.example.com works but staging.example.com does not.
# Diagnosis: Check if subdomain record exists
dig staging.example.com A +short
# (empty response = no record)
dig api.example.com A +short
# 203.0.113.20 (working)
# Check wildcard records
dig *.example.com A +short
Resolution:
- Explicitly add A/CNAME record for the subdomain
- Or set up a wildcard (
*.example.com) record - Remember that explicit records take priority over wildcards
Scenario 5: Some Users Cannot Access After DNS Change (TTL Cache)
Symptom: After changing DNS records, some users reach the new server while others still reach the old one.
# Diagnosis: Check cache state at different DNS servers
dig @8.8.8.8 example.com +short # Google DNS
dig @1.1.1.1 example.com +short # Cloudflare DNS
dig @9.9.9.9 example.com +short # Quad9
# Check TTL
dig example.com | grep -A1 "ANSWER SECTION"
# example.com. 1800 IN A 203.0.113.10
# ^ remaining TTL is still high
Resolution:
- Wait for the TTL duration to expire
- Next time, lower TTL to 60 seconds 24 hours before making DNS changes
- Restore TTL to original value after changes are complete
Scenario 6: nslookup Works But Browser Cannot Connect
Symptom: nslookup example.com returns correct results but Chrome cannot access the site.
# Diagnosis 1: Check hosts file
cat /etc/hosts # Linux/macOS
type C:\Windows\System32\drivers\etc\hosts # Windows
# Diagnosis 2: Check browser DNS cache
# Chrome: chrome://net-internals/#dns -> Clear host cache
# Diagnosis 3: Check HSTS issues
# Chrome: chrome://net-internals/#hsts
# Delete domain and retry
# Diagnosis 4: Check proxy/VPN settings
# Browser proxy settings can bypass DNS
# Diagnosis 5: Check DNS over HTTPS settings
# Chrome Settings -> Privacy and Security -> Use secure DNS
Scenario 7: DNS Outage After Domain Transfer
Symptom: Site goes down after transferring the domain to another registrar.
# Diagnosis: Check current name servers
dig example.com NS +short
# If old registrar's NS appear, update hasn't propagated yet
# Resolution steps:
# 1. Set up DNS records at new registrar FIRST
# 2. Replicate ALL records to the new location before transfer
# 3. Change name servers
# 4. Keep old name servers active for at least 48 hours
Prevention: Always set up all DNS records at the new registrar before initiating the transfer.
Scenario 8: K8s Internal DNS Resolution Failure (CoreDNS, ndots)
Symptom: Pod cannot access external domains (api.external.com) or it is very slow.
# Diagnosis 1: Test DNS resolution from within the Pod
kubectl exec -it debug-pod -- nslookup api.external.com
# Diagnosis 2: Check resolv.conf
kubectl exec -it debug-pod -- cat /etc/resolv.conf
# nameserver 10.96.0.10
# search default.svc.cluster.local svc.cluster.local cluster.local
# options ndots:5
# Diagnosis 3: Check CoreDNS logs
kubectl logs -n kube-system -l k8s-app=kube-dns
# Problem: Due to ndots:5, api.external.com (2 dots) causes
# api.external.com.default.svc.cluster.local etc. to be tried first
Resolution:
# Method 1: Use FQDN (add trailing dot)
# In code, call api.external.com. instead
# Method 2: Set Pod dnsConfig
apiVersion: v1
kind: Pod
spec:
dnsConfig:
options:
- name: ndots
value: '2'
Scenario 9: Origin Server IP Exposed After CDN Integration (DNS Leak)
Symptom: Using Cloudflare but origin server IP is exposed, receiving direct DDoS attacks.
# Diagnosis: Check for non-proxied records
# In Cloudflare dashboard, look for grey cloud (DNS Only)
# instead of orange cloud (Proxied) records
# Scan subdomains for exposure
dig direct.example.com +short # Origin IP exposed?
dig mail.example.com +short # Origin IP in MX A record?
dig ftp.example.com +short # Origin IP in FTP subdomain?
Resolution:
- Enable Cloudflare proxy on all A/AAAA records
- Use a separate IP for A records needed by MX
- If origin IP is already exposed, change the server IP
- Check historical DNS records: SecurityTrails, DNS History may retain the origin IP
Scenario 10: DDNS Updates Not Reflecting
Symptom: DDNS service is configured but DNS doesn't update when IP changes.
# Diagnosis 1: Check current public IP
curl -s https://api.ipify.org
# Diagnosis 2: Check IP registered in DNS
dig myserver.example.com +short
# Diagnosis 3: Check DDNS client logs
sudo journalctl -u ddclient -n 50
# Diagnosis 4: Verify API token validity
curl -s -X GET "https://api.cloudflare.com/client/v4/user/tokens/verify" \
-H "Authorization: Bearer YOUR_TOKEN" | jq .
# Common causes:
# 1. API token expired or insufficient permissions
# 2. Wrong Zone ID or Record ID
# 3. Firewall blocking DDNS client outbound communication
# 4. Cron job disabled
# 5. IP check service (ipify, etc.) unreachable
10. DNS Service Comparison
Managed DNS Services
| Service | Free Plan | Managed DNS | DDNS | DNSSEC | DDoS Protection | Pricing (Paid) |
|---|---|---|---|---|---|---|
| Cloudflare | Yes (unlimited) | Yes | Via API | Yes (free) | Yes | Free to Enterprise |
| AWS Route 53 | No | Yes | No | Yes | Yes (Shield) | 0.50 USD/zone/month |
| Google Cloud DNS | No | Yes | No | Yes | Yes | 0.20 USD/zone/month |
| Azure DNS | No | Yes | No | Yes (preview) | Yes | 0.50 USD/zone/month |
| NS1 | Free tier | Yes | Yes | Yes | Yes | Custom |
| Dyn (Oracle) | No | Yes | Yes | Yes | Yes | Custom |
Public DNS Resolvers
| Service | Primary | Secondary | DoH | DoT | DNSSEC Validation | Features |
|---|---|---|---|---|---|---|
| Google DNS | 8.8.8.8 | 8.8.4.4 | Yes | Yes | Yes | Most widely used |
| Cloudflare | 1.1.1.1 | 1.0.0.1 | Yes | Yes | Yes | Fastest |
| Quad9 | 9.9.9.9 | 149.112.112.112 | Yes | Yes | Yes | Malicious domain blocking |
| OpenDNS | 208.67.222.222 | 208.67.220.220 | Yes | No | Yes | Filtering options |
| AdGuard DNS | 94.140.14.14 | 94.140.15.15 | Yes | Yes | Yes | Ad blocking |
Recommended by Scenario
| Scenario | Recommended Service | Reason |
|---|---|---|
| Personal blog/site | Cloudflare (free) | Free DNS + CDN + SSL |
| Startup | Cloudflare Pro or Route 53 | Scalability + reliability |
| Enterprise | Route 53 + Cloudflare | Multi-DNS + latency-based routing |
| Home server | Cloudflare + DDNS | Free + dynamic IP support |
| K8s cluster | CoreDNS + External-DNS | Automated DNS management |
Quiz
Q1: What is the difference between recursive and iterative DNS queries?
Recursive Query: The client asks a recursive resolver for the final answer. The resolver handles all intermediate steps and returns the final IP address.
Iterative Query: The recursive resolver queries each level of name server (Root, TLD, Authoritative) in order. Each server returns a referral to the next server rather than the final answer.
Typically, client-to-resolver uses recursive queries, while resolver-to-name-servers uses iterative queries.
Q2: Why can't you set a CNAME record on the root domain (apex)?
Per the RFC, a CNAME must be the only record for that name. That is, if a CNAME exists, no other records (A, MX, NS, SOA, etc.) can exist for the same name.
However, the root domain must have SOA and NS records, which cannot coexist with a CNAME.
Alternatives include Cloudflare's CNAME Flattening or ALIAS/ANAME records offered by some DNS providers.
Q3: I set TTL to 60 seconds but DNS changes haven't propagated after 48 hours. Why?
Possible causes:
- Cache from before the TTL change may still exist. The TTL change itself needs time equal to the old TTL to propagate.
- Some ISP DNS servers enforce a minimum TTL (e.g., minimum 300 seconds).
- Client OS and browser caches also cache DNS independently.
- If name servers themselves were changed, propagation at the TLD level can take up to 48 hours.
Fix: Lower TTL 24 hours before the planned DNS change, and flush local caches with ipconfig /flushdns etc. after the change.
Q4: Does DNSSEC encrypt DNS queries?
No. DNSSEC verifies the integrity and authenticity of DNS responses, not encryption.
DNS responses protected by DNSSEC are still transmitted in plaintext. The content of DNS queries remains visible on the network.
For DNS query encryption (privacy), use DNS over HTTPS (DoH) or DNS over TLS (DoT).
Summary:
- DNSSEC = prevents response tampering (integrity)
- DoH/DoT = encrypts queries (privacy)
- Using both provides optimal security
Q5: Why is accessing the external domain api.external.com slow from a K8s Pod, and how do you fix it?
Cause: Kubernetes' default DNS setting of ndots:5 means domains with fewer than 5 dots get search domains appended first.
api.external.com has only 2 dots, so the actual query order is:
api.external.com.default.svc.cluster.local(NXDOMAIN)api.external.com.svc.cluster.local(NXDOMAIN)api.external.com.cluster.local(NXDOMAIN)api.external.com.(success)
Three unnecessary queries occur before the actual resolution.
Solutions:
- Use FQDN:
api.external.com.(add trailing dot) - Set ndots to a lower value (e.g., 2) in Pod's dnsConfig
- Add caching rules in CoreDNS for frequently accessed external domains
References
RFC Documents
- RFC 1034 - Domain Names - Concepts and Facilities
- RFC 1035 - Domain Names - Implementation and Specification
- RFC 2136 - Dynamic Updates in the DNS (DDNS)
- RFC 2181 - Clarifications to the DNS Specification
- RFC 2308 - Negative Caching of DNS Queries
- RFC 4033, 4034, 4035 - DNS Security Extensions (DNSSEC)
- RFC 6698 - DNS-Based Authentication (DANE/TLSA)
- RFC 7208 - SPF (Sender Policy Framework)
- RFC 7489 - DMARC
- RFC 8484 - DNS over HTTPS (DoH)
- RFC 7858 - DNS over TLS (DoT)
- RFC 8659 - DNS Certification Authority Authorization (CAA)
Tools and Services
- dig / nslookup - DNS query command-line tools
- whatsmydns.net - Global DNS propagation checker
- dnschecker.org - DNS record checker
- mxtoolbox.com - Email DNS diagnostics (SPF, DKIM, DMARC)
- securitytrails.com - DNS history lookup
- dnsviz.net - DNSSEC visualization and verification
DNS Software
- BIND9 - https://www.isc.org/bind/
- CoreDNS - https://coredns.io/
- PowerDNS - https://www.powerdns.com/
- Unbound - https://nlnetlabs.nl/projects/unbound/
- Knot DNS - https://www.knot-dns.cz/
Learning Resources
- Cloudflare Learning Center - DNS concepts (learning.cloudflare.com)
- howdns.works - Visual DNS explanation
- messwithdns.net - DNS hands-on playground
- Julia Evans - DNS-related blog and zines