DNS kayıtları ilk bakışta basittir: bir ad, bir tür, bir değer. Sorunlar ayrıntıda çıkar: sonundaki noktası unutulmuş bir MX hedefi, kök alan adına eklenmeye çalışılan bir CNAME, ikinci bir SPF kaydı, IPv6'da hiç yanıt vermeyen bir sunucuyu gösteren AAAA kaydı ya da aslında bir çözümleyicinin önbelleğinde duran eski bir yanıt yüzünden saatlerce beklenen "yayılma" (propagation). Bu rehberde DNS kayıt türlerini (DNS record types) gerçek zone dosyası (bölge dosyası) satırları ve dig çıktılarıyla tek tek ele alıyor, ardından taşıma (migration) için adım adım bir runbook ve bir sorun giderme sırası veriyoruz.
Örneklerde belgeleme için ayrılmış ad ve adresleri kullanıyoruz: example.com, 192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24 ve 2001:db8::/32 (RFC 5737 ve RFC 3849). Uygularken bunların yerine kendi değerlerinizi yazın. dig macOS'ta hazır gelir; Debian ve Ubuntu'da dnsutils (yeni sürümlerde bind9-dnsutils), AlmaLinux ve RHEL'de bind-utils paketiyle kurulur. Windows'ta nslookup ve PowerShell'in Resolve-DnsName komutu yerleşiktir.
Zone dosyası sözdizimi ve TTL
Yalnızca web paneli kullansanız bile orada oluşturduğunuz her kayıt bir zone dosyası satırına karşılık gelir ve dig de kayıtları aynı biçimde yazdırır. Her satırdaki alanlar aynı sıradadır: ad (owner), TTL, sınıf (neredeyse her zaman IN), tür ve veri. Aşağıdaki satırların çoğunda görüldüğü gibi TTL ve sınıf yazılmayabilir.
Kod:
$ORIGIN example.com.
$TTL 3600
@ IN SOA ns1.example.net. hostmaster.example.com. (
2026102701 ; seri numarası (YYYYMMDDnn)
7200 ; refresh
3600 ; retry
1209600 ; expire
3600 ) ; minimum: olumsuz yanıtların önbellek süresi
@ IN NS ns1.example.net.
@ IN NS ns2.example.org.
@ IN A 203.0.113.10
@ IN AAAA 2001:db8:10::10
www IN CNAME example.com.
@ IN MX 10 mx1.example.com.
@ IN MX 20 mx2.example.com.
mx1 IN A 203.0.113.25
mx2 IN A 198.51.100.25
@ IN TXT "v=spf1 mx -all"
api 300 IN A 203.0.113.40
Okurken dört kuralı aklınızda tutun:
- @ işareti $ORIGIN değerini, yani bölgenin kendisini (example.com.) temsil eder. www gibi bir ön eki olmayan çıplak alan adına (example.com) zone apex ya da kısaca apex denir; panellerde kök alan adı veya @ olarak geçer.
- Sondaki nokta adın tam nitelikli bir alan adı (FQDN) olduğunu gösterir. Noktasız adların sonuna $ORIGIN eklenir: zone dosyasında MX hedefini noktasız "mx1.example.com" diye yazarsanız yayınlanan ad mx1.example.com.example.com. olur.
- Web panellerinde durum tersidir: panel, "Ad" ya da "Host" alanına yazdığınız değerin sonuna bölge adını kendisi ekler. Bu alana www.example.com yazmak bazı panellerde www.example.com.example.com kaydı oluşturur; yalnızca www yazın. Microsoft'un DKIM sorun giderme belgesinde yaygın kurulum hataları arasında sayılan "çift alan adı" (double domain) sorunu budur.
- $TTL, TTL'si yazılmamış kayıtların varsayılan değeridir (RFC 2308). api satırındaki 300 yalnızca o kayda özel TTL'dir.
Elle düzenlediğiniz bir zone dosyasını yüklemeden önce BIND'in named-checkzone aracıyla denetleyin:
Bash:
$ named-checkzone example.com example.com.zone
zone example.com/IN: loaded serial 2026102701
OK
TTL (time to live), bir çözümleyicinin (resolver) yanıtı en fazla kaç saniye önbellekte tutabileceğini belirler. Yetkili ad sunucusuna (authoritative nameserver) sorduğunuzda yapılandırılmış değeri, bir çözümleyiciye sorduğunuzda ise kalan süreyi görürsünüz:
Bash:
$ dig +noall +answer www.example.com @ns1.example.net
www.example.com. 3600 IN CNAME example.com.
example.com. 3600 IN A 203.0.113.10
$ dig +noall +answer www.example.com @1.1.1.1
www.example.com. 2417 IN CNAME example.com.
example.com. 2417 IN A 203.0.113.10
İkinci çıktıdaki 2417, 1.1.1.1'in bu yanıtı 2417 saniye daha kullanacağı anlamına gelir. Aşağıdaki değerler bir standarttan değil yerleşik uygulamadan gelir, ama güvenli başlangıç noktalarıdır:
| Durum | TTL | Not |
|---|---|---|
| Sık değişmeyen A, AAAA ve CNAME kayıtları | 3600 (1 saat) | Çoğu site için makul varsayılan |
| Taşıma veya IP değişikliği öncesi | 300 (5 dakika) | Değişiklikten en az eski TTL kadar önce düşürülür |
| MX ve e-posta TXT kayıtları (SPF, DKIM, DMARC) | 3600 ve üzeri | Microsoft, SPF kaydı için en az 3600 öneriyor |
| Sağlık denetimli yük devretme (failover) | 60 | Yalnızca sağlayıcı sağlık denetimi (health check) yapıyorsa anlamlı |
Sağlayıcıların kendi sınırları da vardır. Örneğin Cloudflare'de proxy'li kayıtların TTL'si "Auto" yani 300 saniyedir; proxy'siz (DNS only) kayıtlarda en düşük değer 60 saniye (Enterprise planda 30), en yüksek değer bir gündür.
A ve AAAA: AAAA kaydını yalnızca servis IPv6'da yanıt veriyorsa yayınlayın
A kaydı bir adı IPv4 adresine, AAAA kaydı IPv6 adresine bağlar:
Bash:
$ dig +short A example.com
203.0.113.10
$ dig +short AAAA example.com
2001:db8:10::10
Aynı ada birden fazla A kaydı yazmak DNS round-robin'dir. İstemciler adreslerden birini seçer, ama DNS hangi sunucunun ayakta olduğunu bilmez; sunuculardan biri düştüğünde o adresi seçen istemciler zaman aşımı yaşar. Gerçek yük devretme için sağlık denetimi yapan bir DNS hizmeti ya da bir yük dengeleyici (load balancer) gerekir. Coğrafi (geo), gecikme tabanlı (latency-based) ve ağırlıklı (weighted) yönlendirme de düz kayıtların değil, yönetilen DNS sağlayıcılarının sunduğu özelliklerdir.
AAAA için ölçüt "sunucu IPv6 destekliyor mu" değil, "servis bu IPv6 adresinde gerçekten yanıt veriyor mu" sorusudur. Tarayıcılar IPv6 ve IPv4 bağlantılarını yarıştırır (Happy Eyeballs, RFC 8305); IPv6 adresine hiç bağlanılamıyorsa kullanıcı fark etmeden IPv4'e geçerler. Her istemci bu kadar esnek davranmaz. Let's Encrypt, AAAA kaydı varsa doğrulama bağlantısını her zaman önce IPv6 üzerinden dener ve yalnızca bu bağlantı zaman aşımına uğrarsa IPv4'e geçer; IPv6 tarafındaki sunucu 404 ya da başka bir sitenin içeriğini döndürürse doğrulama başarısız olur ve sertifika yenilenmez.
İki adres ailesini ayrı ayrı test edin; iki komut da aynı durum satırını döndürmelidir:
Bash:
curl -4 -sI https://example.com/ | head -1
curl -6 -sI https://example.com/ | head -1
IPv6 tarafı başarısızsa üç yere bakın: web sunucusu IPv6'da dinliyor mu (nginx'te listen [::]:443 ssl; satırı), güvenlik duvarında IPv6 kuralları ayrıca açılmış mı (iptables kuralları ip6tables'a kendiliğinden geçmez) ve barındırma firması bu adresi gerçekten sunucunuza yönlendiriyor mu. Kendi internet bağlantınızda IPv6 yoksa testi IPv6'sı olan bir sunucudan yapın. Sorunu hemen çözemiyorsanız AAAA kaydını kaldırın; yanlış bir AAAA kaydı, hiç olmamasından daha fazla sorun çıkarır.
CNAME kuralları ve apex sorunu
CNAME bir adı başka bir adın takma adı (alias) yapar; çözümleyici CNAME'i görünce hedef adı sorgulamaya devam eder:
Bash:
$ dig +noall +answer shop.example.com
shop.example.com. 3600 IN CNAME shops.provider.example.net.
shops.provider.example.net. 300 IN A 198.51.100.77
Kurallar standartlardan gelir ve paneller de bunları uygular:
- CNAME bulunan bir adda başka veri olamaz. RFC 1034 (bölüm 3.6.2) bunu açıkça söyler; RFC 2181 (bölüm 10.1) DNSSEC kayıtları dışında istisna tanımaz ve bir adın tek bir CNAME'i olabileceğini ekler. Bu yüzden shop adında CNAME varken aynı ada bir TXT doğrulama kaydı ya da MX ekleyemezsiniz.
- Apex'te CNAME olmaz. Kök alan adında her zaman SOA ve NS kayıtları bulunur ve ilk kural gereği CNAME onlarla yan yana duramaz.
- MX ve NS kayıtlarının hedefi takma ad olamaz. RFC 2181 (bölüm 10.3), bu adların doğrudan A veya AAAA kaydı olmasını şart koşar. RFC 2782 aynı kuralı SRV hedefleri için koyar.
Apex'i bir CDN ya da SaaS hizmetine bağlamanız gerektiğinde sağlayıcıya özgü çözümler devreye girer. Aşağıdakilerden ilk üçü aynı şekilde çalışır: DNS sağlayıcısı hedef adı kendi tarafında çözer ve istemciye A/AAAA kaydı olarak döndürür.
- Cloudflare CNAME flattening: Apex'teki CNAME tüm planlarda varsayılan olarak düzleştirilir. Ücretli planlarda tüm CNAME'leri ya da seçtiğiniz kayıtları da düzleştirebilirsiniz; ancak tüm CNAME'leri düzleştirmek, CNAME'in kendisini görmeyi bekleyen üçüncü taraf alan adı doğrulamalarını bozabilir.
- Route 53 alias kaydı: Apex'te CloudFront, Elastic Load Balancing ve S3 web sitesi gibi AWS kaynaklarına ya da aynı barındırılan bölgedeki (hosted zone) başka bir kayda işaret edebilir. AWS kaynaklarına giden alias sorguları ücretlendirilmez.
- ALIAS ve ANAME: DNSimple'ın ALIAS kaydı gibi, standart olmayan ve sağlayıcıya özgü sözde kayıt türleridir. Adı ve davranışı sağlayıcıdan sağlayıcıya değişir ve her sağlayıcıda bulunmaz; DNS sağlayıcısı değiştirirken yeni sağlayıcıda karşılığı olup olmadığını önceden kontrol edin.
- HTTPS kaydı (RFC 9460): AliasMode, apex'te CNAME benzeri bir yönlendirme sağlar (example.com. 3600 IN HTTPS 0 svc.example.net.). Ancak RFC'nin kendisi, bu kaydı tanımayan istemciler için apex'te A/AAAA kayıtlarının tutulmaya devam edilmesi gerektiğini belirtir; bugün flattening'in yerini tutmaz.
- Elle yazılmış A kaydı: Hizmet sağlayıcının IP adreslerini apex'e A kaydı olarak yazmak çalışır, ama adresler değiştiğinde site hiçbir uyarı olmadan erişilemez hale gelir. Daha sağlam bir yol, www'yi CNAME yapmak ve apex'i yalnızca www'ye yönlendirme (301) yapan, kontrolünüzdeki bir web sunucusuna bağlamaktır.
MX: öncelik, yedek MX ve null MX
Bash:
$ dig +short MX example.com
10 mx1.example.com.
20 mx2.example.com.
Sayı ne kadar küçükse öncelik o kadar yüksektir: gönderen sunucu önce 10'u dener, ulaşamazsa 20'ye geçer. Aynı önceliğe sahip kayıtlar arasında gönderen sunucunun seçimi rastgele yapması gerekir (RFC 5321, bölüm 5.1); bu da yükü dağıtır. MX değeri bir IP adresi olamaz, bir ana bilgisayar adı (hostname) olmalıdır ve bu adın CNAME değil, doğrudan A/AAAA kaydı bulunmalıdır. Cloudflare kullanıyorsanız posta sunucusunun A kaydını proxy'siz (gri bulut) bırakın; Cloudflare'in standart proxy'si SMTP trafiğini taşımaz.
Sıkça gözden kaçan iki davranış var:
- Hiç MX yoksa gönderen sunucular postayı alan adının A/AAAA adresine teslim etmeye çalışır (RFC 5321'deki "implicit MX" kuralı). E-posta almayan bir alan adı için null MX yayınlayın: example.com. IN MX 0 . (RFC 7505). Yanına v=spf1 -all SPF kaydı ve p=reject politikalı bir DMARC kaydı eklemek, alan adının sahte gönderimlerde kullanılmasını da zorlaştırır.
- Barındırılan e-postada değer sağlayıcıdan gelir. Google Workspace bugün tek bir kayıt öneriyor: smtp.google.com, öncelik 1 (aspmx ile başlayan eski kayıtlar hâlâ destekleniyor). Microsoft 365'te MX değerini yönetim merkezinin gösterdiği haliyle, karakteri karakterine kopyalayın.
Yedek MX'e dikkat. Spam gönderen sistemler çoğu zaman doğrudan en düşük öncelikli (sayısı en büyük) MX'e bağlanır, çünkü yedek sunucularda genellikle birincildeki alıcı doğrulaması ve spam filtresi bulunmaz. Yedek sunucu, var olmayan alıcılara gelen postayı da kabul edip birincile aktarır; birincil bu iletileri reddedince de geri dönüş iletilerini (bounce) sahte gönderici adreslerine gönderir. Buna backscatter denir. Oysa gönderen sunucular geçici hatalarda postayı kuyrukta tutup yeniden dener ve RFC 5321, vazgeçme süresinin genellikle en az 4-5 gün olması gerektiğini söyler; birincil sunucunuz birkaç saat kapalı kalsa bile posta kaybolmaz. Google Workspace veya Microsoft 365 kullanıyorsanız kendi yedek MX'inizi eklemeyin. Kendi posta sunucunuzu işletiyorsanız yedek MX'i ancak birincildeki alıcı listesini ve filtreleri aynen uygulayabiliyorsanız kurun.
TXT: SPF, DKIM ve DMARC
TXT kaydı serbest metin taşır; alan adı sahiplik doğrulamaları da burada durur. Bir uzunluk kuralını bilmek gerekir: bir TXT kaydındaki her dize (string) en fazla 255 karakter olabilir. Daha uzun değerler aynı kayıtta birden çok tırnaklı dizeye bölünür ve okuyan taraf bunları arada boşluk bırakmadan birleştirir (RFC 7208 bölüm 3.3, RFC 6376).SPF: tek kayıt, en fazla 10 DNS sorgusu
SPF, zarf göndericisinin (MAIL FROM, Return-Path) alan adı adına hangi sunucuların posta gönderebileceğini bildirir. Klasik hatalardan biri, ikinci bir SPF kaydı eklemektir:
Kod:
; YANLIŞ: iki ayrı SPF kaydı, sonuç permerror
example.com. IN TXT "v=spf1 include:spf.protection.outlook.com -all"
example.com. IN TXT "v=spf1 ip4:203.0.113.25 -all"
; DOĞRU: tek kayıtta birleştirilmiş hali
example.com. IN TXT "v=spf1 ip4:203.0.113.25 include:spf.protection.outlook.com -all"
RFC 7208'e göre birden fazla v=spf1 kaydı bulunan bir alan adında SPF değerlendirmesinin sonucu permerror'dur. İkinci sınır sorgu sayısıdır: include, a, mx, ptr, exists mekanizmaları ve redirect değiştiricisi değerlendirme sırasında DNS sorgusu yaptırır; bunların toplamı 10'u geçerse sonuç yine permerror olur. ip4, ip6 ve all sayılmaz. İç içe include'lar da sayıma girer, dolayısıyla 10'dan az include yazmak 10'dan az sorgu anlamına gelmez. RFC 7208 ayrıca alıcı tarafın boş dönen sorguları (void lookup) ikiyle sınırlamasını ister; bu sınırı aşmak da permerror demektir. Eskimiş girdiler iki soruna da yol açar: sildiğiniz bir sunucuyu gösteren a: veya mx: terimi boş sorgu üretir, artık SPF kaydı yayınlamayan bir hedefe yapılan include ise tek başına permerror sonucunu doğurur. Kullanmadığınız hizmetlerin include'larını kaldırın; hâlâ çözülüyor olsalar bile sorgu hakkınızı harcar ve kontrolünüzde olmayan sunuculara sizin adınıza gönderim izni vermeye devam ederler.
Sayımı elle yapmak için zinciri izleyin:
Bash:
$ dig +short TXT example.com | grep spf1
"v=spf1 ip4:203.0.113.25 include:spf.protection.outlook.com -all"
$ dig +short TXT spf.protection.outlook.com
"v=spf1 ip4:40.92.0.0/15 ip4:40.107.0.0/16 ... -all"
Yazım tarihinde spf.protection.outlook.com ve Google'ın _spf.google.com kayıtları yalnızca ip4/ip6 aralıkları içerdiğinden her biri tek sorgu sayılıyor. Sağlayıcılar bu yapıyı değiştirebilir; sayımı ara sıra tekrarlayın. Diğer kurallar: ptr mekanizmasını kullanmayın (RFC 7208 bu mekanizmanın yayınlanmamasını ister) ve asla +all yazmayın, çünkü herkese izin verir. Microsoft, Microsoft 365 alan adları için -all öneriyor; DMARC zaten -all ile ~all'u aynı şekilde SPF hatası olarak değerlendirir.
DKIM: seçici (selector) kayıtları
DKIM imzası iletinin başlığında d= (imzalayan alan adı) ve s= (seçici) değerlerini taşır. Alıcı, açık anahtarı seçici._domainkey.alanadı biçimindeki addan okur:
Kod:
s2026._domainkey.example.com. IN TXT ( "v=DKIM1; k=rsa; "
"p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx3...birinci_parca"
"...ikinci_parca...IDAQAB" )
2048 bitlik bir anahtar 255 karakteri aştığı için böyle bölünmüş dizelerle yazılır. Paneliniz bölmeyi kendisi yapmıyorsa anahtarın içine boşluk ya da fazladan tırnak karışmadığından emin olun. p= değeri boş olan bir kayıt, anahtarın iptal edildiği anlamına gelir. RFC 8301, imzalayanların en az 1024 bitlik RSA anahtarı kullanmasını zorunlu tutar ve 2048 bit ya da üstünü önerir.
Microsoft 365, TXT yerine iki CNAME kaydı ister: selector1._domainkey ve selector2._domainkey. Hedef değerleri Defender portalından ya da Get-DkimSigningConfig çıktısındaki Selector1CNAME ve Selector2CNAME alanlarından birebir kopyalayın. Mayıs 2025'ten itibaren eklenen özel alan adlarında hedef dkim.mail.microsoft ile, daha eski alan adlarında onmicrosoft.com ile biter. Microsoft'un varsayılan anahtar boyu 1024 bittir; Rotate-DkimSigningConfig -Identity example.com -KeySize 2048 komutuyla 2048 bite geçebilirsiniz. Yeni boyut her seçiciye o seçici etkin hale geldiğinde uygulanır; iki seçicinin de 2048 bitlik anahtar kullanması için anahtarları iki kez döndürmeniz (rotate) gerekir. Kaydı doğrulamak için:
Bash:
$ dig +short TXT selector1._domainkey.example.com
selector1-example-com._domainkey.example.n-v1.dkim.mail.microsoft.
"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA..."
DMARC: politika ve raporlar
DMARC, From başlığındaki alan adının başarılı bir SPF veya DKIM sonucuyla hizalanıp hizalanmadığına (alignment) bakar ve başarısız iletiler için politikanızı bildirir. Kayıt _dmarc adında durur:
Kod:
; 1. aşama: yalnızca izleme
_dmarc.example.com. 3600 IN TXT "v=DMARC1; p=none; rua=mailto:[email protected]"
; raporlar okunup tüm meşru göndericiler hizalandıktan sonra
_dmarc.example.com. 3600 IN TXT "v=DMARC1; p=quarantine; rua=mailto:[email protected]"
_dmarc.example.com. 3600 IN TXT "v=DMARC1; p=reject; rua=mailto:[email protected]"
p=none ile başlayın ve birkaç hafta boyunca rua adresine gelen toplu raporları (aggregate report) okuyarak adınıza posta gönderen bütün sistemleri tespit edin: fatura yazılımı, bülten hizmeti, web sitesinin iletişim formu, ofisteki yazıcının e-postaya tarama özelliği. Hepsi SPF veya DKIM ile hizalandığında quarantine'e, ardından reject'e geçin. sp= etiketi alt alan adları için ayrı politika tanımlar. Raporlar başka bir alan adındaki adrese gidecekse o alan adının bir izin kaydı yayınlaması gerekir; yoksa alıcılar o adrese rapor göndermez:
Kod:
example.com._report._dmarc.rapor.example.net. IN TXT "v=DMARC1"
Güncel bir not: DMARC'ın yeni sürümü Mayıs 2026'da RFC 9989 olarak yayımlandı ve RFC 7489'un yerini aldı. Eski rehberlerde görülen pct etiketi kaldırıldı; test modu için t=y, var olmayan alt alan adları için np= etiketi eklendi. Alıcıların yeni sürümü benimsemesi zaman alacağından kademeli geçişte bu etiketlere değil, raporlara güvenin. Google da Gmail hesaplarına günde 5.000'den fazla ileti gönderenlerden SPF, DKIM ve DMARC istiyor; DMARC politikası olarak p=none yeterli sayılıyor. cPanel sunucusundaki Exim'den Microsoft 365 alan adınız adına giden postalar DMARC nedeniyle reddediliyorsa Exim ve Microsoft 365 DMARC sorununu anlattığımız konuya bakın.
SRV: servis konumu
SRV kaydı bir servisin hangi ana bilgisayarda ve hangi portta çalıştığını bildirir. Biçimi _servis._protokol.ad TTL IN SRV öncelik ağırlık port hedef şeklindedir (RFC 2782). Minecraft Java Edition sunucunuz 25570 portunda çalışıyorsa oyuncuların port yazmadan mc.example.com adresiyle bağlanmasını şöyle sağlarsınız:
Kod:
_minecraft._tcp.mc.example.com. 3600 IN SRV 0 0 25570 oyun1.example.com.
oyun1.example.com. 3600 IN A 203.0.113.60
Bash:
$ dig +short SRV _minecraft._tcp.mc.example.com
0 0 25570 oyun1.example.com.
Öncelik MX'teki gibi çalışır: küçük sayı önce denenir. Ağırlık, aynı öncelikteki hedefler arasında orantılı dağıtım içindir; seçim yapılmayacaksa RFC 2782 ağırlık olarak 0 yazılmasını önerir. Hedef CNAME olamaz ve A/AAAA kaydına sahip olmalıdır; Cloudflare'de bu A kaydı proxy'siz kalmalıdır. Hedef olarak tek başına "." yazmak, servisin bu alan adında sunulmadığını bildirir. SRV kayıtları Outlook'un _autodiscover._tcp aramasında, SIP ve XMPP'de ve Active Directory'de de kullanılır; etki alanı denetleyicileri (domain controller) kendi SRV kayıtlarını DNS'e kendileri kaydeder.
CAA: hangi sertifika otoritesi sertifika verebilir?
CAA kaydı, alan adınız için hangi sertifika otoritelerinin (CA) sertifika verebileceğini sınırlar (RFC 8659). Hiç CAA kaydı yoksa her CA sertifika verebilir.
Kod:
example.com. 3600 IN CAA 0 issue "letsencrypt.org"
example.com. 3600 IN CAA 0 issuewild ";"
example.com. 3600 IN CAA 0 iodef "mailto:[email protected]"
Bu kümeyle normal adlar için yalnızca Let's Encrypt sertifika verebilir, joker (wildcard) sertifikayı hiçbir CA veremez ve kurala aykırı taleplerde CA iodef adresine bildirim gönderebilir. Let's Encrypt'ten DNS-01 doğrulamasıyla joker sertifika alıyorsanız ikinci satırı issuewild "letsencrypt.org" yapın. Bilmeniz gerekenler:
- issuewild tek başına normal sertifikaları kısıtlamaz. Yalnızca issuewild yazıp issue yazmazsanız normal adlar için her CA sertifika verebilir.
- CA, sertifika istenen addan başlayıp üst alan adlarına doğru çıkar ve bulduğu ilk CAA kümesini uygular. Yani example.com'daki CAA, kendi CAA kaydı olmayan bütün alt alan adlarını kapsar. Bu aramada CNAME'ler izlenir.
- Cloudflare'de Universal SSL açıkken herhangi bir CAA kaydı eklerseniz Cloudflare, iş ortağı olduğu CA'lar için gereken kayıtları kendisi ekler. Bu kayıtlar panelde görünmez, dig ile görürsünüz.
- Panelinizin AutoSSL özelliği ya da CDN sağlayıcınız başka bir CA kullanıyorsa onun tanımlayıcısını da ekleyin (örneğin Google Trust Services için pki.goog, Sectigo için sectigo.com). Aksi halde o CA bir sonraki sertifika talebini ya da yenilemeyi reddeder.
- Let's Encrypt, RFC 8657'deki validationmethods ve accounturi parametrelerini de tanır; 0 issue "letsencrypt.org; validationmethods=dns-01" yalnızca DNS-01 doğrulamasına izin verir.
Bash:
$ dig +short CAA example.com
0 issue "letsencrypt.org"
0 issuewild ";"
0 iodef "mailto:[email protected]"
NS, SOA ve glue kayıtları
NS kayıtları bölgenin yetkili ad sunucularını gösterir ve iki yerde bulunur: üst bölgede (.com gibi bir TLD'de; alan adını kaydettiğiniz firma, yani registrar üzerinden ayarlanır) ve kendi bölgenizde. İkisi aynı olmalıdır. Üst bölgedeki kopyayı TLD sunucusuna doğrudan sorarak görürsünüz:
Bash:
$ dig NS example.com @a.gtld-servers.net +norecurse +noall +authority
example.com. 172800 IN NS ns1.example.net.
example.com. 172800 IN NS ns2.example.org.
Buradaki 172800 saniye (48 saat), .com uzantısını işleten kuruluşun (registry) belirlediği değerdir ve ad sunucusu değişikliklerinin neden kayıt değişikliklerinden yavaş yerleştiğini açıklar. Diğer TLD'ler farklı değerler kullanır; dig +trace hepsini gösterir. RFC 1034 her bölgenin en az iki sunucuda bulunmasını şart koşar ve bu sunucuların farklı ağlarda olması tek arıza noktasını ortadan kaldırır. Yönetilen DNS sağlayıcısı seçimini Cloudflare, Route 53, BunnyDNS ve NS1 karşılaştırmamızda ele aldık.
SOA kaydı bölgenin yönetim bilgilerini taşır:
Bash:
$ dig +short SOA example.com
ns1.example.net. hostmaster.example.com. 2026102701 7200 3600 1209600 3600
Alanlar sırasıyla şunlardır: birincil ad sunucusu, sorumlu kişinin e-posta adresi (ilk nokta @ yerine geçer, yani [email protected]), seri numarası, ikincil sunucular için refresh, retry ve expire süreleri ve son olarak minimum. Seri numarası için YYYYMMDDnn biçimi yaygındır (RFC 1912); ikincil sunucular bölgeyi seri numarası arttığında yeniden çeker. Yönetilen DNS hizmetleri bunu sizin yerinize yapar; zone dosyasını elle yönetiyorsanız her değişiklikte seri numarasını artırmayı unutmayın. Son alan bugün olumsuz yanıtların önbellek süresini belirler; buna yayılma bölümünde döneceğiz.
Glue kaydı: Ad sunucularınız kendi alan adınızın içindeyse (example.com için ns1.example.com gibi), çözümleyici ns1'in adresini öğrenmek için yine example.com'a sormak zorunda kalır. Bu döngüyü kırmak için üst bölgede ad sunucusunun IP adresi de tutulur; buna glue (yapıştırıcı) kayıt denir. Registrar panellerinde "child nameserver", "host kaydı" ya da "özel ad sunucusu tanımlama" gibi adlarla geçer:
Kod:
; .com bölgesinde, registrar paneli üzerinden oluşturulur
example.com. 172800 IN NS ns1.example.com.
example.com. 172800 IN NS ns2.example.com.
ns1.example.com. 172800 IN A 203.0.113.53
ns2.example.com. 172800 IN A 198.51.100.53
cPanel veya DirectAdmin sunucularında ns1 ve ns2'yi aynı IP adresine bağlamak sık görülür. Teknik olarak çalışır, ama sunucu kapandığında alan adınız için yanıt verecek hiçbir ad sunucusu kalmaz. Sunucu IP'si değiştiğinde registrar'daki glue kaydını güncellemek de taşımalarda kolayca atlanan bir adımdır.
PTR ve ters DNS: kaydı IP adresinin sahibi yazar
PTR kaydı bir IP adresini bir ada çevirir ve in-addr.arpa (IPv6 için ip6.arpa) altındaki bir bölgede durur. Bu bölge IP bloğunun sahibine aittir; bu yüzden PTR kaydını kendi alan adınızın DNS panelinden yazamazsınız. VPS ve bulut sağlayıcılarında "Reverse DNS" ya da "rDNS" alanından ayarlanır; sabit IP'li kurumsal internet hatlarında internet servis sağlayıcınıza başvurmanız gerekir.
Bash:
$ dig -x 203.0.113.25 +short
mail.example.com.
$ dig +short A mail.example.com
203.0.113.25
İki yönün birbirini doğrulaması (forward-confirmed reverse DNS) e-posta için kritiktir. Gmail tüm göndericilerden, gönderen IP adresinin bir ana bilgisayar adına çözülen bir PTR kaydı olmasını ve o adın A veya AAAA kaydının aynı IP'yi göstermesini istiyor. PTR adını posta sunucusunun HELO/EHLO adıyla aynı tutmak iyi bir uygulamadır. Sunucunuz IPv6 üzerinden de posta gönderiyorsa IPv6 adresinin de kendi PTR kaydı olmalıdır.
Joker (wildcard) kayıtların tuzakları
*.example.com kaydı, bölgede hiç bulunmayan adlar için yanıt üretir. RFC 4592'de tanımlanan bu davranışın şaşırtıcı yanları var:
Kod:
*.example.com. 300 IN A 203.0.113.10
www.example.com. 300 IN TXT "site-verification=abc123"
- blog.example.com için A sorgusu 203.0.113.10 döner, ama www.example.com için A sorgusu boş döner: www adı (yalnızca bir TXT kaydıyla da olsa) var olduğu için joker devreye girmez. Bir alt ada doğrulama TXT'si eklemek o adın web sitesini bu şekilde bozabilir.
- Joker kayıt apex'i kapsamaz; example.com'un kendi kayıtları gerekir.
- DNS jokeri birden fazla etiketi kapsayabilir: b.example.com yoksa a.b.example.com da eşleşir. TLS joker sertifikası ise yalnızca tek bir etiketi kapsar; *.example.com sertifikası a.b.example.com için geçersizdir.
- Yanlış yazılmış adlar NXDOMAIN yerine yanıt aldığı için hatalar gizlenir. Jokeri kontrolünüzden çıkabilecek bir hedefe (örneğin silinmiş bir bulut kaynağına) yönlendirirseniz bütün alt adlar ele geçirilme (subdomain takeover) riskine açılır.
"DNS yayılması" (propagation) aslında önbellek meselesidir
DNS, değişiklikleri dünyaya dağıtan bir mekanizma içermez. Yetkili sunucularınız yeni değeri hemen verir; eski yanıtı önbelleğe almış her çözümleyici ise o yanıtın TTL'si dolana kadar eskisini vermeye devam eder. "Propagation" dediğimiz şey, binlerce çözümleyicideki eski TTL'lerin birbirinden bağımsız olarak dolmasıdır. Bu yüzden en kötü durumdaki bekleme süresini yeni TTL değil, değişiklikten önceki TTL belirler. whatsmydns.net gibi araçlar dünyanın farklı yerlerindeki çözümleyicilerden örnek alarak bu süreci gösterir.Olumsuz önbellekleme (negative caching) aynı mantıkla çalışır. Henüz oluşturmadığınız bir adı sorgularsanız çözümleyici "bu ad yok" (NXDOMAIN) ya da "bu türde kayıt yok" (NODATA) yanıtını da önbelleğe alır. Süre, SOA kaydının TTL'si ile SOA minimum alanından küçük olanıdır (RFC 2308) ve yanıtın authority bölümündeki SOA satırında görünür:
Bash:
$ dig yeni.example.com A +noall +authority
example.com. 3600 IN SOA ns1.example.net. hostmaster.example.com. 2026102701 7200 3600 1209600 3600
Bu örnekte kaydı hemen ardından ekleseniz bile, olumsuz yanıtı önbelleğe almış çözümleyiciler bir saate kadar "yok" demeyi sürdürür. Yeni bir alt alan adını, kaydı oluşturmadan önce sorgulamamak bu yüzden iyi bir alışkanlıktır.
Ad sunucusu değişikliklerinde belirleyici olan, üst bölgedeki NS kayıtlarının TTL'sidir (.com için 48 saat). Önbellek süresinin dolmasını beklemek istemiyorsanız Google Public DNS (dns.google/cache) ve Cloudflare 1.1.1.1 (one.one.one.one/purge-cache) için önbellek temizleme sayfaları var; diğer çözümleyiciler için yapabileceğiniz bir şey yok. Kendi bilgisayarınızın önbelleğini de temizleyin:
Kod:
Windows: ipconfig /flushdns
macOS: sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder
Linux: resolvectl flush-caches (systemd-resolved kullanan dağıtımlarda)
Chrome: chrome://net-internals/#dns -> Clear host cache
Taşıma runbook'u: TTL'yi düşür, değiştir, doğrula, geri yükselt
Sunucu taşırken ya da bir IP adresini değiştirirken şu sırayı izleyin:- Envanter çıkarın. Bölgeyi dışa aktarın ve her kaydı listeleyin: doğrulama TXT'leri, DKIM seçicileri, SRV, CAA ve glue kayıtları dahil. Kayıtları dnscontrol, octoDNS ya da bir Terraform sağlayıcısıyla sürüm kontrolünde tutuyorsanız bu adım zaten hazırdır.
- 24-48 saat önce TTL'yi düşürün. Değişecek kayıtların TTL'sini 300'e indirin ve asıl değişikliği eski TTL kadar süre geçmeden yapmayın: eski TTL 86400 ise en az 24 saat bekleyin. Yapılandırılmış değeri yetkili sunucuya sorarak doğrulayın: dig +noall +answer www.example.com @ns1.example.net
- Yeni sunucuyu DNS kayıtlarına dokunmadan test edin. curl --resolve example.com:443:203.0.113.20 -I https://example.com/ komutu isteği doğru ad ve sertifikayla yeni IP'ye gönderir. Tarayıcıda denemek için hosts dosyasını kullanabilirsiniz.
- Geçişi yapın. Düşük trafikli bir saat seçin ve IP ile birlikte değişmesi gerekenleri de güncelleyin: SPF kaydındaki ip4 değerleri, yeni posta IP'sinin PTR kaydı ve ad sunucusu adresleri değiştiyse glue kayıtları.
- Doğrulayın. Önce yetkili sunucuyu sorgulayın (dig @ns1.example.net example.com A +norecurse; flags satırında aa görünmeli), sonra 1.1.1.1, 8.8.8.8, 9.9.9.9 ve kendi internet servis sağlayıcınızın çözümleyicisini. Eski değeri veren bir çözümleyicide TTL sütunu ne kadar bekleyeceğinizi söyler.
- Eski sunucuyu hemen kapatmayın. Eski TTL'nin en az iki katı kadar süre geçene ve erişim günlüklerinde (log) trafik bitene kadar açık tutun.
- TTL'yi geri yükseltin: 3600 ya da daha üstüne.
DNS sağlayıcısını değiştiriyorsanız (NS değişikliği) şu adımlar eklenir:
- Bölgeyi yeni sağlayıcıya aktarın ve registrar'a dokunmadan önce her kaydı yeni sunuculara doğrudan sorarak karşılaştırın: dig @yeni-ns1.example.net example.com MX +short
- DNSSEC açıksa önce registrar'daki DS kaydını kaldırın ve DS kaydının TTL'si kadar bekleyin (.com'da 86400 saniye). Ardından NS kayıtlarını değiştirin. Yeni sağlayıcıda DNSSEC'i açıp yeni DS kaydını registrar'a girmeden önce NS değişikliğinin oturmasını bekleyin (.com'da 48 saat); hâlâ eski sunuculara soran bir çözümleyici yeni DS kaydını eski anahtarlarla karşılaştırır ve doğrulama başarısız olur. Eski DS kaydını bırakıp ad sunucularını değiştirmek ise doğrulama yapan çözümleyicilerde alan adınızı tamamen erişilemez kılar. Bazı DNS sağlayıcıları, bölgeyi geçiş boyunca imzalı tutan çoklu imzalayıcı (multi-signer, RFC 8901) yöntemini de destekler.
- NS değişikliğinden sonra eski sağlayıcıdaki bölgeyi en az 48 saat güncel tutun; bazı çözümleyiciler bir süre eski sunuculara sormaya devam eder.
Sorun giderme: dig +trace, nslookup ve DNSSEC
1. Yetki devri (delegation) zincirini izleyin. dig +trace kök sunuculardan başlar, her seviyenin verdiği NS kayıtlarını ve sonunda yetkili yanıtı gösterir:
Bash:
$ dig +trace +nodnssec example.com A
. 518400 IN NS a.root-servers.net.
; ... diğer kök sunucular ...
;; Received 811 bytes from 192.168.1.1#53(192.168.1.1) in 12 ms
com. 172800 IN NS a.gtld-servers.net.
; ...
;; Received 828 bytes from 198.41.0.4#53(a.root-servers.net) in 40 ms
example.com. 172800 IN NS ns1.example.net.
example.com. 172800 IN NS ns2.example.org.
;; Received 120 bytes from 192.5.6.30#53(a.gtld-servers.net) in 36 ms
example.com. 3600 IN A 203.0.113.10
;; Received 56 bytes from 192.0.2.53#53(ns1.example.net) in 28 ms
TLD'nin gösterdiği ad sunucuları kayıtları düzenlediğiniz panele ait değilse yaptığınız değişiklikler hiçbir zaman yayına girmez. "DNS'i değiştirdim ama hiçbir şey olmadı" şikâyetlerinin sık rastlanan bir nedeni budur: kayıt registrar panelinde düzenlenmiştir, ama alan adı Cloudflare'e ya da hosting firmasının ad sunucularına yönlendirilmiştir. Listelenen ad sunucularından biri hiç yanıt vermiyor ya da REFUSED döndürüyorsa o sunucu bölgeyi sunmuyordur; buna lame delegation denir.
2. Yetkili sunucuya doğrudan sorun. dig @ns1.example.net www.example.com +norecurse komutunun çıktısında flags satırında aa (authoritative answer) görüyorsanız yanıt doğrudan kaynaktan gelmiştir. Değer burada doğruysa sorun önbellektir ve TTL dolunca kendiliğinden geçer.
3. Çözümleyicileri karşılaştırın. dig +short www.example.com komutunun @1.1.1.1 ve @8.8.8.8 sonuçları farklıysa çözümleyiciler değeri farklı zamanlarda önbelleğe almıştır. dig'in gösterdiği IP panele girdiğinizden farklıysa ve kayıt Cloudflare'de proxy'liyse bu normaldir: dig, Cloudflare'in anycast adreslerini döndürür.
4. SERVFAIL görüyorsanız DNSSEC'i denetleyin. Doğrulama yapan çözümleyiciler (1.1.1.1, 8.8.8.8) SERVFAIL döndürüyor ama +cd (checking disabled) bayrağıyla yanıt geliyorsa sorun neredeyse her zaman DNSSEC'tir. Sık rastlanan nedenlerden biri DS uyuşmazlığıdır: registrar'daki DS kaydı, bölgenin yayınladığı anahtarla (DNSKEY) eşleşmez. Süresi dolmuş imzalar (RRSIG) da aynı sonucu verir. Bu hatayı görmek için bilerek bozuk tutulan dnssec-failed.org test alan adını deneyebilirsiniz (çıktılar yazım tarihine aittir):
Bash:
$ dig +short dnssec-failed.org A @1.1.1.1
# çıktı boş: yanıtın başlığında status: SERVFAIL yazar
$ dig +short +cd dnssec-failed.org A @1.1.1.1
96.99.227.255
$ dig +short DS dnssec-failed.org
42069 13 2 62726F6B656E20636861696E206F662074727573742073656E642068 656C7021
$ dig +cd +multi DNSKEY dnssec-failed.org | grep "key id"
) ; KSK; alg = ECDSAP256SHA256 ; key id = 50719
) ; ZSK; alg = ECDSAP256SHA256 ; key id = 32784
DS kaydındaki anahtar etiketi (key tag) 42069, bölgedeki KSK'nin etiketi ise 50719'dur; güven zinciri tam burada kopar. Yeni dig sürümleri bu durumu yanıtta EDE: 9 (DNSKEY Missing) bilgisiyle de gösterir; macOS ile gelen eski dig aynı bilgiyi OPT=15 satırında ham olarak yazar. Görsel analiz için DNSViz (dnsviz.net) ve Verisign DNSSEC Debugger kullanışlıdır. Çözüm, registrar'daki DS kaydını DNS sağlayıcınızın verdiği güncel değerle değiştirmektir. DNSSEC'i kapatacaksanız önce DS kaydını kaldırın, imzalamayı DS'nin TTL'si dolduktan sonra durdurun.
5. Windows'ta nslookup ve Resolve-DnsName kullanın.
Kod:
C:\> nslookup -type=mx example.com 1.1.1.1
Non-authoritative answer:
example.com MX preference = 10, mail exchanger = mx1.example.com
C:\> nslookup -type=txt _dmarc.example.com 8.8.8.8
C:\> nslookup -type=srv _ldap._tcp.dc._msdcs.corp.example.com
PS C:\> Resolve-DnsName -Name example.com -Type MX -Server 1.1.1.1
PS C:\> Resolve-DnsName -Name dnssec-failed.org -Server 1.1.1.1 -DnssecCd
PS C:\> Clear-DnsClientCache
"Non-authoritative answer" ifadesi yalnızca yanıtın alan adının kendi ad sunucularından değil, özyinelemeli bir çözümleyiciden (recursive resolver) geldiğini söyler, hata değildir; yetkili yanıt için sunucu olarak alan adının ad sunucularından birini yazın. Resolve-DnsName'in tür listesinde CAA bulunmadığından CAA için WSL içindeki dig'i kullanın. Son bir uyarı: dig ANY example.com tüm kayıtları listelemez. RFC 8482'ye göre sunucular ANY sorgularına kısaltılmış yanıt verebilir; Cloudflare örneğin yalnızca HINFO "RFC8482" döndürür. Her kayıt türünü ayrı sorgulayın.
Kayıt türleri özet tablosu
| Tür | Ne işe yarar | Örnek değer | Dikkat |
|---|---|---|---|
| A | Adı IPv4 adresine bağlar | 203.0.113.10 | Birden çok A kaydı sağlık denetimi yapmaz |
| AAAA | Adı IPv6 adresine bağlar | 2001:db8:10::10 | Yalnızca servis IPv6'da yanıt veriyorsa |
| CNAME | Adı başka bir adın takma adı yapar | shops.provider.example.net. | Apex'te ve başka kayıtla aynı adda olmaz |
| MX | Posta sunucularını öncelik sırasıyla bildirir | 10 mx1.example.com. | Hedef A/AAAA olmalı; IP adresi ya da CNAME olmaz |
| TXT | SPF, DKIM, DMARC ve doğrulamalar | "v=spf1 ... -all" | Tek SPF; dize başına 255 karakter |
| SRV | Servisin ana bilgisayarını ve portunu bildirir | 0 0 25570 oyun1.example.com. | Hedef CNAME olamaz |
| CAA | Sertifika verebilecek CA'ları sınırlar | 0 issue "letsencrypt.org" | Kullandığınız bütün CA'ları ekleyin |
| NS | Yetkili ad sunucularını gösterir | ns1.example.net. | En az iki; registrar'daki kayıtla aynı olmalı |
| SOA | Bölge bilgileri ve olumsuz önbellek süresi | ns1.example.net. hostmaster.example.com. 2026102701 ... | Elle yönetimde seri numarasını artırın |
| PTR | IP adresini ada çevirir | mail.example.com. | IP adresinin sahibi ayarlar |
| DS | DNSSEC zincirini üst bölgeye bağlar | 12345 13 2 9F86D081... | Bölgedeki DNSKEY ile eşleşmeli |
Sık yapılan hatalar
- Kaydı yanlış panelde düzenlemek. Önce dig NS example.com +short ile alan adının hangi ad sunucularına yönlendiğini görün.
- Zone dosyasında sondaki noktayı unutmak ya da panelde Ad alanına tam alan adını yazmak (çift alan adı).
- Apex'e CNAME eklemeye çalışmak ya da CNAME olan bir ada TXT veya MX eklemek.
- İkinci bir SPF kaydı oluşturmak, 10 sorgu sınırını aşmak, kullanılmayan include'ları kayıtta bırakmak.
- Servis IPv6'da yanıt vermezken AAAA kaydı yayınlamak.
- Birincildeki filtreleri uygulamayan bir yedek MX kurmak.
- CAA kümesine panelin ya da CDN sağlayıcısının kullandığı CA'yı eklememek; sertifika yenilemesi aylar sonra başarısız olur.
- DNS sağlayıcısını değiştirirken registrar'daki eski DS kaydını bırakmak.
- Yeni bir adı oluşturmadan önce sorgulayıp olumsuz önbelleğe düşürmek.
- Posta, SSH veya oyun sunucusu adlarını Cloudflare'de proxy'li bırakmak.
- TTL'yi değişiklikten birkaç dakika önce düşürüp hemen değiştirmek: çözümleyicilerde eski TTL hâlâ geçerlidir.
Sık sorulan sorular
DNS değişikliği ne kadar sürede yayılır?Bir kaydın değerini değiştirdiğinizde en kötü durum, değişiklikten önceki TTL kadardır. Ad sunucusu değişikliğinde üst bölgedeki NS kayıtlarının TTL'si belirleyicidir; .com için bu 48 saattir. Yetkili sunucuya sorduğunuzda yeni değer hemen görünmelidir.
Kök alan adına (apex) CNAME ekleyebilir miyim?
Hayır; CNAME oradaki SOA ve NS kayıtlarıyla çakışır. Sağlayıcınızın CNAME flattening, ALIAS/ANAME ya da alias kaydı özelliğini kullanın veya apex'i A kaydıyla tutup www'yi CNAME yapın.
AAAA kaydı eklemek zorunda mıyım?
Hayır. Servis IPv6 üzerinden düzgün yanıt veriyorsa ekleyin; curl -6 testi başarısızsa eklemeyin.
dig neden panele girdiğimden farklı bir IP adresi gösteriyor?
Ya kayıt Cloudflare gibi bir proxy'nin arkasındadır, ya CNAME düzleştirilmiştir ya da sorguladığınız çözümleyici eski yanıtı önbellekte tutuyordur. dig komutunu +norecurse ile doğrudan yetkili ad sunucusuna yöneltin: yeni değer orada görünüyorsa yalnızca önbellekteki eski yanıtların süresinin dolmasını bekliyorsunuz demektir. Proxy'li bir kayıt orada da proxy'nin adreslerini, düzleştirilmiş bir CNAME ise hedefin o anki adreslerini gösterir; girdiğiniz asıl değer yalnızca sağlayıcının panelinde görünür.
Hangi TTL değerini kullanmalıyım?
Günlük kullanım için 3600 iyi bir başlangıçtır. Planlı bir değişiklikten 24-48 saat önce 300'e düşürün, iş bitince geri yükseltin.
Microsoft 365 veya Google Workspace için yedek MX eklemeli miyim?
Hayır. Bu hizmetler kendi yedekliliklerini sağlar ve gönderen sunucular geçici hatalarda postayı günlerce yeniden dener. Ek bir MX, spam'e açılan bir kapıdan öteye geçmez.
Sonuç ve sonraki adımlar
DNS sorunlarının çoğu birkaç kurala dayanır: CNAME yalnız durur, SPF tek kayıttır, AAAA ancak IPv6 çalışıyorsa yayınlanır, PTR kaydını IP adresinin sahibi yazar ve "yayılma" dediğimiz şey eski TTL'nin dolmasından ibarettir. Bugün yapabilecekleriniz:- dig NS ve dig +trace ile alan adınızın gerçekte hangi ad sunucularından yönetildiğini doğrulayın.
- SPF kaydınızın tek olduğunu ve 10 sorgu sınırının altında kaldığını kontrol edin; DMARC'ı p=none ile başlatıp raporları okumaya başlayın.
- AAAA kayıtlarınızı curl -6 ile test edin.
- CAA kümenizin kullandığınız bütün CA'ları kapsadığından emin olun.
- Bölgenizi dışa aktarıp sürüm kontrolüne alın ve bir sonraki taşımada bu runbook'u izleyin.
DNS records look simple: a name, a type, a value. The trouble lives in the details. An MX target that lost its trailing dot, a CNAME someone tries to put on the bare domain, a second SPF record, an AAAA record pointing at a server that never answers on IPv6, or hours spent "waiting for propagation" while a resolver is simply holding an old answer in its cache. This reference goes through the DNS record types one by one with real zone-file lines and dig output, then gives you a migration runbook and a troubleshooting sequence.
All examples use names and addresses reserved for documentation: example.com, 192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24 and 2001:db8::/32 (RFC 5737 and RFC 3849). Substitute your own values. dig ships with macOS; on Debian and Ubuntu it comes in the dnsutils package (bind9-dnsutils on newer releases), on AlmaLinux and RHEL in bind-utils. Windows has nslookup and PowerShell's Resolve-DnsName built in.
Zone-file syntax and TTL
Even if you only ever touch a web panel, every record you create there corresponds to one zone-file line, and dig prints records in the same format. Each line has the same fields in the same order: owner name, TTL, class (almost always IN), type and data. TTL and class are optional, as most lines below show.
Kod:
$ORIGIN example.com.
$TTL 3600
@ IN SOA ns1.example.net. hostmaster.example.com. (
2026102701 ; serial (YYYYMMDDnn)
7200 ; refresh
3600 ; retry
1209600 ; expire
3600 ) ; minimum: how long negative answers are cached
@ IN NS ns1.example.net.
@ IN NS ns2.example.org.
@ IN A 203.0.113.10
@ IN AAAA 2001:db8:10::10
www IN CNAME example.com.
@ IN MX 10 mx1.example.com.
@ IN MX 20 mx2.example.com.
mx1 IN A 203.0.113.25
mx2 IN A 198.51.100.25
@ IN TXT "v=spf1 mx -all"
api 300 IN A 203.0.113.40
Four rules make it readable:
- @ stands for $ORIGIN, the zone itself (example.com.). The bare domain is called the zone apex.
- A trailing dot marks a fully qualified domain name (FQDN). Names without one get $ORIGIN appended, so an MX target written as "mx1.example.com" without the dot in a zone file is published as mx1.example.com.example.com.
- Web panels work the other way round: they append the zone to whatever you type in the Name or Host field. Typing www.example.com there creates www.example.com.example.com on some panels; type just www. Microsoft's DKIM troubleshooting guide lists this "double domain" among the common setup mistakes.
- $TTL sets the default for records that have no explicit TTL (RFC 2308). The 300 on the api line overrides it for that record only.
If you edit zone files by hand, validate them with BIND's named-checkzone before loading:
Bash:
$ named-checkzone example.com example.com.zone
zone example.com/IN: loaded serial 2026102701
OK
The TTL (time to live) is the maximum number of seconds a resolver may cache an answer. Ask the authoritative nameserver and you see the configured value; ask a recursive resolver and you see the time it has left:
Bash:
$ dig +noall +answer www.example.com @ns1.example.net
www.example.com. 3600 IN CNAME example.com.
example.com. 3600 IN A 203.0.113.10
$ dig +noall +answer www.example.com @1.1.1.1
www.example.com. 2417 IN CNAME example.com.
example.com. 2417 IN A 203.0.113.10
The 2417 in the second answer means 1.1.1.1 will keep handing out that answer for another 2417 seconds. The values below are conventions rather than standards, but they are safe starting points:
| Situation | TTL | Note |
|---|---|---|
| Stable A, AAAA and CNAME records | 3600 (1 hour) | Sensible default for most sites |
| Before a migration or IP change | 300 (5 minutes) | Lower it at least one old TTL before the change |
| MX and mail TXT records (SPF, DKIM, DMARC) | 3600 or more | Microsoft recommends at least 3600 for SPF |
| Health-checked failover | 60 | Only meaningful if the provider runs health checks |
Providers add limits of their own. On Cloudflare, proxied records use TTL "Auto", which is 300 seconds; DNS-only records accept a minimum of 60 seconds (30 on Enterprise) and a maximum of one day.
A and AAAA: publish AAAA only when the service answers on IPv6
An A record maps a name to an IPv4 address, an AAAA record to an IPv6 address:
Bash:
$ dig +short A example.com
203.0.113.10
$ dig +short AAAA example.com
2001:db8:10::10
Putting several A records on one name is DNS round-robin. Clients pick one of the addresses, but DNS has no idea which server is alive: when one goes down, the clients that picked its address hit timeouts. Real failover needs a DNS service with health checks or a load balancer in front. Geo, latency-based and weighted routing are features of managed DNS providers, not of plain records.
For AAAA the question is not "does the server support IPv6" but "does the service actually answer on this IPv6 address". Browsers race IPv6 and IPv4 connections (Happy Eyeballs, RFC 8305), so when the IPv6 address is unreachable they quietly fall back to IPv4 and users rarely notice. Other clients are less forgiving. When a name has an AAAA record, Let's Encrypt always tries IPv6 first for its validation connection and falls back to IPv4 only if that connection times out. If the IPv6 side answers with a 404 or with another site's content, validation fails and the certificate does not renew.
Test both address families separately; both commands should return the same status line:
Bash:
curl -4 -sI https://example.com/ | head -1
curl -6 -sI https://example.com/ | head -1
If IPv6 fails, check three things: is the web server listening on IPv6 (in nginx, a listen [::]:443 ssl; line), does the firewall allow IPv6 separately (iptables rules do not carry over to ip6tables), and does the hosting provider actually route that address to your server. If your own connection has no IPv6, run the test from a server that has it. If you cannot fix it quickly, remove the AAAA record: a wrong AAAA record causes more trouble than a missing one.
CNAME rules and the apex problem
A CNAME makes one name an alias of another; when a resolver meets one, it carries on and resolves the target:
Bash:
$ dig +noall +answer shop.example.com
shop.example.com. 3600 IN CNAME shops.provider.example.net.
shops.provider.example.net. 300 IN A 198.51.100.77
The rules come from the standards, and panels enforce them:
- A name with a CNAME cannot hold any other data. RFC 1034 (section 3.6.2) says so directly, and RFC 2181 (section 10.1) allows no exception apart from DNSSEC records and adds that a name can have only one CNAME. That is why you cannot add a TXT verification record or an MX next to the CNAME on shop.
- No CNAME at the apex. The apex always carries SOA and NS records, and by the first rule a CNAME cannot sit beside them.
- MX and NS targets must not be aliases. RFC 2181 (section 10.3) requires those names to have A or AAAA records of their own. RFC 2782 applies the same rule to SRV targets.
When the apex has to point at a CDN or SaaS hostname, provider-specific features fill the gap. The first three below work the same way: the DNS provider resolves the target on its side and answers the client with A/AAAA records.
- Cloudflare CNAME flattening: a CNAME at the apex is flattened by default on every plan. Paid plans can also flatten all CNAMEs or selected records, but flattening everything can break third-party domain verification that expects to see the CNAME itself.
- Route 53 alias records: at the apex they can point to AWS resources such as CloudFront, Elastic Load Balancing or an S3 website endpoint, or to another record in the same hosted zone. Alias queries to AWS resources are not charged.
- ALIAS and ANAME: non-standard, provider-specific pseudo-records such as DNSimple's ALIAS. Names and behaviour vary and not every provider has one, so check for an equivalent before you move to a new DNS provider.
- HTTPS record (RFC 9460): AliasMode gives CNAME-like aliasing at the apex (example.com. 3600 IN HTTPS 0 svc.example.net.), but the RFC itself says address records must stay at the apex for clients that do not support it. It does not replace flattening today.
- Hand-written A records: copying the provider's IP addresses into apex A records works until those addresses change, and then the site goes down without warning. A sturdier option is to make www the CNAME and point the apex at a web server you control that only redirects (301) to www.
MX: priorities, backup MX and null MX
Bash:
$ dig +short MX example.com
10 mx1.example.com.
20 mx2.example.com.
Lower numbers win: a sending server tries 10 first and moves to 20 only if it cannot reach 10. Among records with equal preference the sender must pick at random (RFC 5321, section 5.1), which spreads the load. The MX value cannot be an IP address; it must be a hostname, and that hostname needs its own A/AAAA record rather than a CNAME. On Cloudflare, keep the mail server's A record DNS-only (grey cloud), because Cloudflare's standard proxy does not carry SMTP.
Two behaviours catch people out:
- No MX at all: senders fall back to the domain's A/AAAA address (the "implicit MX" rule in RFC 5321). For a domain that never receives mail, publish a null MX: example.com. IN MX 0 . (RFC 7505). Adding v=spf1 -all and a DMARC record with p=reject also makes the domain harder to abuse for spoofing.
- Hosted mail dictates the value: Google Workspace now recommends a single record, smtp.google.com with priority 1 (the older aspmx records are still supported). For Microsoft 365, copy the MX value exactly as the admin center shows it.
A word of caution on backup MX. Spammers often go straight to the lowest-priority MX (the one with the highest number), because backup servers frequently lack the primary's recipient validation and spam filtering. The backup accepts mail for recipients that do not exist and relays it to the primary; when the primary rejects it, the backup sends bounces to the forged sender addresses, which is known as backscatter. Legitimate senders, meanwhile, already queue mail during temporary failures and retry, and RFC 5321 says the give-up time should generally be at least 4-5 days, so a primary that is down for a few hours loses nothing. With Google Workspace or Microsoft 365, do not add a backup MX of your own. If you run your own mail server, add a backup only if it applies the same recipient list and filtering as the primary.
TXT: SPF, DKIM and DMARC
TXT records carry free-form text, including domain verification tokens. One length rule matters: each string inside a TXT record is limited to 255 characters. Longer values are split into several quoted strings within the same record, and the reader joins them with no spaces in between (RFC 7208 section 3.3, RFC 6376).SPF: one record, at most 10 DNS lookups
SPF lists the servers allowed to send mail for the envelope sender's domain (MAIL FROM, the Return-Path). A classic mistake is a second SPF record:
Kod:
; WRONG: two separate SPF records, the result is permerror
example.com. IN TXT "v=spf1 include:spf.protection.outlook.com -all"
example.com. IN TXT "v=spf1 ip4:203.0.113.25 -all"
; RIGHT: merged into one record
example.com. IN TXT "v=spf1 ip4:203.0.113.25 include:spf.protection.outlook.com -all"
Under RFC 7208, a domain with more than one v=spf1 record evaluates to permerror. The second limit is lookups: the include, a, mx, ptr and exists mechanisms and the redirect modifier each trigger DNS queries during evaluation, and if their total exceeds 10 the result is permerror again. ip4, ip6 and all do not count. Nested includes do count, so fewer than 10 includes does not guarantee fewer than 10 lookups. RFC 7208 also tells receivers to limit "void" lookups (queries that return no records) to two; going over is another permerror. Stale entries cause both problems: an a: or mx: term naming a host you deleted produces void lookups, and an include whose target no longer publishes an SPF record is a permerror on its own. Remove includes for services you no longer use; even while they still resolve, they spend lookups and keep authorising servers you do not control.
To count by hand, follow the chain:
Bash:
$ dig +short TXT example.com | grep spf1
"v=spf1 ip4:203.0.113.25 include:spf.protection.outlook.com -all"
$ dig +short TXT spf.protection.outlook.com
"v=spf1 ip4:40.92.0.0/15 ip4:40.107.0.0/16 ... -all"
At the time of writing, spf.protection.outlook.com and Google's _spf.google.com contain only ip4/ip6 ranges, so each costs a single lookup. Providers can change that, so recount now and then. Two more rules: do not use the ptr mechanism (RFC 7208 says it should not be published), and never write +all, which authorises everyone. Microsoft recommends -all for Microsoft 365 domains; DMARC treats -all and ~all alike as an SPF failure anyway.
DKIM: selector records
A DKIM signature carries d= (the signing domain) and s= (the selector) in the message header. The receiver fetches the public key from selector._domainkey.domain:
Kod:
s2026._domainkey.example.com. IN TXT ( "v=DKIM1; k=rsa; "
"p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx3...first_chunk"
"...second_chunk...IDAQAB" )
A 2048-bit key runs past 255 characters, so it is published as split strings like this. If your panel does not split it for you, make sure no spaces or stray quotes end up inside the key. A record with an empty p= value means the key has been revoked. RFC 8301 requires signers to use RSA keys of at least 1024 bits and recommends 2048 bits or more.
Microsoft 365 asks for two CNAME records instead of a TXT: selector1._domainkey and selector2._domainkey. Copy the targets exactly from the Defender portal or from the Selector1CNAME and Selector2CNAME fields of Get-DkimSigningConfig. For custom domains added since May 2025 the targets end in dkim.mail.microsoft; older domains point under onmicrosoft.com. Microsoft's default key size is 1024 bits; Rotate-DkimSigningConfig -Identity example.com -KeySize 2048 switches to 2048 bits. The new size applies to each selector as it becomes active, so both selectors use 2048-bit keys only after the second rotation. To check the record:
Bash:
$ dig +short TXT selector1._domainkey.example.com
selector1-example-com._domainkey.example.n-v1.dkim.mail.microsoft.
"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA..."
DMARC: policy and reports
DMARC checks whether the domain in the From header aligns with a passing SPF or DKIM result, and tells receivers what to do with mail that fails. The record lives at _dmarc:
Kod:
; stage 1: monitor only
_dmarc.example.com. 3600 IN TXT "v=DMARC1; p=none; rua=mailto:[email protected]"
; once the reports are clean and every legitimate sender aligns
_dmarc.example.com. 3600 IN TXT "v=DMARC1; p=quarantine; rua=mailto:[email protected]"
_dmarc.example.com. 3600 IN TXT "v=DMARC1; p=reject; rua=mailto:[email protected]"
Start with p=none and spend a few weeks reading the aggregate reports that arrive at the rua address to find every system sending as your domain: the invoicing software, the newsletter service, the website's contact form, the office scanner. Once all of them align through SPF or DKIM, move to quarantine and then to reject. The sp= tag sets a separate policy for subdomains. If reports go to an address on another domain, that domain must publish an authorisation record, or receivers will not send reports there:
Kod:
example.com._report._dmarc.reports.example.net. IN TXT "v=DMARC1"
A current note: the revised DMARC specification was published in May 2026 as RFC 9989, replacing RFC 7489. The pct tag you will see in older guides is gone; t=y now signals test mode, and np= sets a policy for non-existent subdomains. Receivers will adopt the revision gradually, so during a staged rollout rely on the reports rather than on either tag. Google, for its part, requires anyone sending more than 5,000 messages a day to Gmail accounts to set up SPF, DKIM and DMARC, and accepts p=none as the DMARC policy. If mail that Exim on a cPanel server sends for your Microsoft 365 domain is being rejected under DMARC, see our thread on fixing Exim delivery with Microsoft 365 and DMARC.
SRV: service location
An SRV record tells clients which host and port provide a service. The format is _service._proto.name TTL IN SRV priority weight port target (RFC 2782). If your Minecraft Java Edition server runs on port 25570, this lets players connect to mc.example.com without typing a port:
Kod:
_minecraft._tcp.mc.example.com. 3600 IN SRV 0 0 25570 game1.example.com.
game1.example.com. 3600 IN A 203.0.113.60
Bash:
$ dig +short SRV _minecraft._tcp.mc.example.com
0 0 25570 game1.example.com.
Priority works as in MX: lower is tried first. Weight spreads load proportionally among targets with the same priority; when there is nothing to choose between, RFC 2782 recommends a weight of 0. The target cannot be a CNAME and must have A/AAAA records, and on Cloudflare that A record must stay DNS-only. A target of "." on its own announces that the service is not offered at this domain. SRV records also drive Outlook's _autodiscover._tcp lookup, SIP, XMPP and Active Directory, where domain controllers register their own SRV records.
CAA: which certificate authorities may issue
A CAA record limits which certificate authorities (CAs) may issue certificates for your domain (RFC 8659). With no CAA records at all, any CA may issue.
Kod:
example.com. 3600 IN CAA 0 issue "letsencrypt.org"
example.com. 3600 IN CAA 0 issuewild ";"
example.com. 3600 IN CAA 0 iodef "mailto:[email protected]"
With this set, only Let's Encrypt may issue for ordinary names, no CA may issue a wildcard certificate, and a CA may report requests that violate the policy to the iodef address. If you get Let's Encrypt wildcards through DNS-01 validation, change the second line to issuewild "letsencrypt.org". Points to know:
- issuewild alone does not restrict ordinary certificates. Publish issuewild without any issue record and every CA may still issue for non-wildcard names.
- A CA starts at the requested name and climbs towards the parent domains, applying the first CAA set it finds. So a CAA set on example.com covers every subdomain that has no CAA records of its own. CNAMEs are followed during the lookup.
- On Cloudflare with Universal SSL, adding any CAA record makes Cloudflare add records for its partner CAs automatically. They do not show in the dashboard; you see them with dig.
- If your control panel's AutoSSL or your CDN uses another CA, add its identifier as well (pki.goog for Google Trust Services, sectigo.com for Sectigo, for example). Otherwise that CA will refuse the next issuance or renewal.
- Let's Encrypt also honours the validationmethods and accounturi parameters from RFC 8657: 0 issue "letsencrypt.org; validationmethods=dns-01" allows DNS-01 validation only.
Bash:
$ dig +short CAA example.com
0 issue "letsencrypt.org"
0 issuewild ";"
0 iodef "mailto:[email protected]"
NS, SOA and glue records
NS records name the authoritative servers for a zone and exist in two places: in the parent zone (a TLD such as .com, set through your registrar) and in your own zone. The two sets should match. You can see the parent's copy by asking a TLD server directly:
Bash:
$ dig NS example.com @a.gtld-servers.net +norecurse +noall +authority
example.com. 172800 IN NS ns1.example.net.
example.com. 172800 IN NS ns2.example.org.
The 172800 seconds (48 hours) is set by the .com registry, and it is why nameserver changes settle more slowly than record changes. Other TLDs use other values; dig +trace shows them all. RFC 1034 requires every zone to be served by at least two servers, and putting them on different networks removes the single point of failure. We compared managed DNS providers in Cloudflare, Route 53, BunnyDNS, NS1: picking a managed DNS service.
The SOA record holds the zone's administrative data:
Bash:
$ dig +short SOA example.com
ns1.example.net. hostmaster.example.com. 2026102701 7200 3600 1209600 3600
In order: the primary nameserver, the responsible person's mailbox (the first dot stands for @, so [email protected]), the serial number, the refresh, retry and expire timers used by secondary servers, and finally the minimum. YYYYMMDDnn is the usual serial format (RFC 1912); secondaries pull the zone again when the serial goes up. Managed DNS services handle this for you, but if you maintain zone files by hand, bump the serial with every change. The last field now sets how long negative answers are cached, which we come back to under propagation.
Glue records: if your nameservers live inside your own domain (ns1.example.com serving example.com), a resolver would have to ask example.com to find ns1's address. To break that loop, the parent zone also stores the nameservers' IP addresses, known as glue. Registrars call this "child nameservers", "host records" or "register nameserver":
Kod:
; in the .com zone, created through the registrar's panel
example.com. 172800 IN NS ns1.example.com.
example.com. 172800 IN NS ns2.example.com.
ns1.example.com. 172800 IN A 203.0.113.53
ns2.example.com. 172800 IN A 198.51.100.53
On cPanel or DirectAdmin servers it is common to point ns1 and ns2 at the same IP address. It works, but when the server goes down your domain's DNS goes down with it. Updating the glue at the registrar after the server's IP changes is also an easy migration step to miss.
PTR and reverse DNS: set by whoever owns the IP
A PTR record maps an IP address back to a name and lives in a zone under in-addr.arpa (ip6.arpa for IPv6). That zone belongs to whoever holds the IP block, so you cannot create PTR records from your domain's DNS panel. On VPS and cloud platforms you set it in a "Reverse DNS" or "rDNS" field; on business lines with static IPs you ask your ISP.
Bash:
$ dig -x 203.0.113.25 +short
mail.example.com.
$ dig +short A mail.example.com
203.0.113.25
The two directions confirming each other (forward-confirmed reverse DNS) matters for email. Gmail requires every sender's IP to have a PTR record that resolves to a hostname, with that hostname's A or AAAA record pointing back to the same IP. Keeping the PTR name identical to the mail server's HELO/EHLO name is good practice. If the server also sends over IPv6, the IPv6 address needs a PTR record of its own.
Wildcard caveats
A *.example.com record synthesises answers for names that do not exist in the zone. The behaviour, defined in RFC 4592, has a few surprises:
Kod:
*.example.com. 300 IN A 203.0.113.10
www.example.com. 300 IN TXT "site-verification=abc123"
- An A query for blog.example.com returns 203.0.113.10, but an A query for www.example.com comes back empty: www exists (even if only as a TXT record), so the wildcard does not apply. Adding a verification TXT record to a subdomain can take its website down this way.
- The wildcard does not cover the apex; example.com needs records of its own.
- A DNS wildcard can span several labels: if b.example.com does not exist, a.b.example.com matches too. A TLS wildcard certificate covers exactly one label, so a *.example.com certificate is not valid for a.b.example.com.
- Typos resolve instead of returning NXDOMAIN, which hides mistakes. And if the wildcard points at a target that can slip out of your control (a deleted cloud resource, for example), every subdomain becomes a takeover risk.
"Propagation" is really caching
Nothing in DNS pushes changes out to the world. Your authoritative servers serve the new value immediately; every resolver that cached the old answer keeps serving it until that answer's TTL runs out. What people call propagation is thousands of old TTLs expiring independently. So the worst-case wait is set by the TTL before the change, not by the new one. Tools such as whatsmydns.net sample resolvers around the world and let you watch the process.Negative caching works the same way. Query a name before you create it, and the resolver caches "no such name" (NXDOMAIN) or "no record of this type" (NODATA) as well. The duration is the smaller of the SOA record's own TTL and the SOA minimum field (RFC 2308), and it shows up in the SOA line in the authority section of the response:
Bash:
$ dig new.example.com A +noall +authority
example.com. 3600 IN SOA ns1.example.net. hostmaster.example.com. 2026102701 7200 3600 1209600 3600
In this example, even if you add the record a minute later, resolvers that cached the negative answer will keep saying it does not exist for up to an hour. That is why it pays not to query a new subdomain before its record exists.
For nameserver changes, the TTL of the NS records in the parent zone decides (48 hours for .com). If you would rather not wait, Google Public DNS (dns.google/cache) and Cloudflare's 1.1.1.1 (one.one.one.one/purge-cache) offer cache purge pages; for other resolvers there is nothing you can do. Flush your own machine's cache as well:
Kod:
Windows: ipconfig /flushdns
macOS: sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder
Linux: resolvectl flush-caches (distributions using systemd-resolved)
Chrome: chrome://net-internals/#dns -> Clear host cache
Migration runbook: lower the TTL, switch, verify, raise it again
When you move a server or change an IP address, work in this order:- Take an inventory. Export the zone and list every record, including verification TXT records, DKIM selectors, SRV, CAA and glue. If you keep DNS in version control with dnscontrol, octoDNS or a Terraform provider, this step is already done.
- Lower the TTL 24-48 hours ahead. Set the records you will change to 300 and do not make the actual change until at least one old TTL has passed: if the old TTL was 86400, wait at least 24 hours. Confirm the configured value against the authoritative server: dig +noall +answer www.example.com @ns1.example.net
- Test the new server without touching DNS. curl --resolve example.com:443:203.0.113.20 -I https://example.com/ sends the request to the new IP with the correct name and certificate. For a browser test, use your hosts file.
- Switch. Pick a low-traffic window and update whatever moves with the IP: ip4 entries in your SPF record, the PTR record for a new mail IP, and glue records if your nameserver addresses change.
- Verify. Query the authoritative server first (dig @ns1.example.net example.com A +norecurse; look for aa in the flags line), then 1.1.1.1, 8.8.8.8, 9.9.9.9 and your ISP's resolver. On a resolver that still returns the old value, the TTL column tells you how long to wait.
- Do not switch the old server off straight away. Keep it running for at least twice the old TTL and until its logs show no more traffic.
- Raise the TTL again to 3600 or more.
Changing DNS provider (an NS change) adds these steps:
- Import the zone at the new provider and, before touching the registrar, compare every record by querying the new servers directly: dig @new-ns1.example.net example.com MX +short
- If DNSSEC is on, remove the DS record at the registrar first and wait out its TTL (86400 seconds for .com). Then change the NS records. Enable DNSSEC at the new provider and add its DS record at the registrar only after the NS change has settled (48 hours for .com): a resolver still talking to the old servers would compare the new DS with the old keys and fail. Switching nameservers while the old DS record is still published makes your domain unreachable for every validating resolver. Some DNS providers also support a multi-signer migration (RFC 8901) that keeps the zone signed throughout.
- After the NS change, keep the zone at the old provider current for at least 48 hours; some resolvers keep asking the old servers for a while.
Troubleshooting: dig +trace, nslookup and DNSSEC
1. Follow the delegation chain. dig +trace starts at the root servers and shows the NS records each level hands out, ending with the authoritative answer:
Bash:
$ dig +trace +nodnssec example.com A
. 518400 IN NS a.root-servers.net.
; ... other root servers ...
;; Received 811 bytes from 192.168.1.1#53(192.168.1.1) in 12 ms
com. 172800 IN NS a.gtld-servers.net.
; ...
;; Received 828 bytes from 198.41.0.4#53(a.root-servers.net) in 40 ms
example.com. 172800 IN NS ns1.example.net.
example.com. 172800 IN NS ns2.example.org.
;; Received 120 bytes from 192.5.6.30#53(a.gtld-servers.net) in 36 ms
example.com. 3600 IN A 203.0.113.10
;; Received 56 bytes from 192.0.2.53#53(ns1.example.net) in 28 ms
If the nameservers the TLD hands out do not belong to the panel where you edit records, your changes will never go live. This is a common cause of "I changed DNS and nothing happened": the record was edited at the registrar while the domain is delegated to Cloudflare or to the hosting company's nameservers. If one of the listed nameservers does not answer at all or returns REFUSED, it is not serving the zone, which is known as a lame delegation.
2. Ask the authoritative server directly. When dig @ns1.example.net www.example.com +norecurse shows aa (authoritative answer) in the flags line, the answer comes straight from the source. If the value is right there, the problem is caching, and it clears by itself once the TTL runs out.
3. Compare resolvers. If dig +short www.example.com gives different results against @1.1.1.1 and @8.8.8.8, the resolvers cached the value at different times. If dig shows a different IP from the one you entered and the record is proxied on Cloudflare, that is expected: dig returns Cloudflare's anycast addresses.
4. Getting SERVFAIL? Check DNSSEC. If validating resolvers such as 1.1.1.1 and 8.8.8.8 return SERVFAIL but the query works with +cd (checking disabled), the problem is almost always DNSSEC. A frequent cause is a DS mismatch: the DS record at the registrar does not match the key (DNSKEY) the zone publishes. Expired signatures (RRSIG) have the same effect. The test domain dnssec-failed.org is kept broken on purpose so you can see this for yourself (outputs as of writing):
Bash:
$ dig +short dnssec-failed.org A @1.1.1.1
# no output: the response header says status: SERVFAIL
$ dig +short +cd dnssec-failed.org A @1.1.1.1
96.99.227.255
$ dig +short DS dnssec-failed.org
42069 13 2 62726F6B656E20636861696E206F662074727573742073656E642068 656C7021
$ dig +cd +multi DNSKEY dnssec-failed.org | grep "key id"
) ; KSK; alg = ECDSAP256SHA256 ; key id = 50719
) ; ZSK; alg = ECDSAP256SHA256 ; key id = 32784
The DS record carries key tag 42069, while the zone's KSK has key tag 50719, so the chain of trust breaks exactly here. Newer dig versions also report this as EDE: 9 (DNSKEY Missing) in the response; the older dig bundled with macOS prints the same information raw in an OPT=15 line. DNSViz (dnsviz.net) and the Verisign DNSSEC Debugger draw the whole chain for you. The fix is to replace the DS record at the registrar with the current value from your DNS provider. If you are turning DNSSEC off, remove the DS record first and stop signing only after its TTL has expired.
5. On Windows, use nslookup and Resolve-DnsName.
Kod:
C:\> nslookup -type=mx example.com 1.1.1.1
Non-authoritative answer:
example.com MX preference = 10, mail exchanger = mx1.example.com
C:\> nslookup -type=txt _dmarc.example.com 8.8.8.8
C:\> nslookup -type=srv _ldap._tcp.dc._msdcs.corp.example.com
PS C:\> Resolve-DnsName -Name example.com -Type MX -Server 1.1.1.1
PS C:\> Resolve-DnsName -Name dnssec-failed.org -Server 1.1.1.1 -DnssecCd
PS C:\> Clear-DnsClientCache
"Non-authoritative answer" only means the answer came from a recursive resolver rather than from one of the domain's own nameservers; it is not an error. For an authoritative answer, name one of the domain's nameservers as the server. Resolve-DnsName has no CAA type, so use dig under WSL for CAA lookups. One last warning: dig ANY example.com does not list every record. Under RFC 8482 servers may answer ANY queries minimally, and Cloudflare, for instance, returns only HINFO "RFC8482". Query each type separately.
Record types at a glance
| Type | What it does | Example value | Watch out for |
|---|---|---|---|
| A | Maps a name to an IPv4 address | 203.0.113.10 | Several A records do no health checking |
| AAAA | Maps a name to an IPv6 address | 2001:db8:10::10 | Only if the service answers on IPv6 |
| CNAME | Makes a name an alias of another | shops.provider.example.net. | Not at the apex, not beside other records |
| MX | Lists mail servers in priority order | 10 mx1.example.com. | Target needs A/AAAA; never an IP or a CNAME |
| TXT | SPF, DKIM, DMARC and verification tokens | "v=spf1 ... -all" | One SPF record; 255 characters per string |
| SRV | Gives a service's host and port | 0 0 25570 game1.example.com. | Target cannot be a CNAME |
| CAA | Limits which CAs may issue certificates | 0 issue "letsencrypt.org" | List every CA you actually use |
| NS | Names the authoritative nameservers | ns1.example.net. | At least two; must match the registrar |
| SOA | Zone metadata and negative-cache time | ns1.example.net. hostmaster.example.com. 2026102701 ... | Bump the serial when editing by hand |
| PTR | Maps an IP address back to a name | mail.example.com. | Set by whoever owns the IP |
| DS | Links the DNSSEC chain to the parent zone | 12345 13 2 9F86D081... | Must match the zone's DNSKEY |
Common mistakes
- Editing records in the wrong panel. Run dig NS example.com +short first to see which nameservers the domain actually uses.
- Leaving out the trailing dot in a zone file, or typing the full domain into a panel's Name field (the double domain).
- Trying to put a CNAME on the apex, or adding TXT or MX records to a name that is already a CNAME.
- Creating a second SPF record, going over the 10-lookup limit, or leaving includes for services you no longer use.
- Publishing AAAA records while the service does not answer on IPv6.
- Running a backup MX without the primary's filtering.
- Leaving the CA used by your panel or CDN out of the CAA set; the renewal fails months later.
- Leaving the old DS record at the registrar when changing DNS provider.
- Querying a new name before creating it and getting it stuck in negative caches.
- Leaving mail, SSH or game server hostnames proxied on Cloudflare.
- Lowering the TTL a few minutes before the change and switching immediately: resolvers still hold the old TTL.
FAQ
How long does DNS propagation take?When you change a record's value, the worst case is the TTL that was in place before the change. For a nameserver change, the TTL of the NS records in the parent zone decides, which is 48 hours for .com. The authoritative server should show the new value immediately.
Can I put a CNAME on my root domain (apex)?
No; it would clash with the SOA and NS records that live there. Use your provider's CNAME flattening, ALIAS/ANAME or alias records, or keep A records at the apex and make www the CNAME.
Do I have to add AAAA records?
No. Add them when the service answers properly over IPv6; if the curl -6 test fails, leave them out.
Why does dig show a different IP from the one I entered?
Either the record sits behind a proxy such as Cloudflare, the CNAME is being flattened, or the resolver you asked is still holding an old answer. Point dig at the authoritative nameserver with +norecurse: if it shows the new value, you are only waiting for caches to expire. A proxied record shows the proxy's addresses even there, and a flattened CNAME shows the target's current addresses; the value you actually entered is visible only in the provider's dashboard.
Which TTL should I use?
3600 is a good everyday value. Lower it to 300 24-48 hours before a planned change and raise it again once the work is done.
Should I add a backup MX for Microsoft 365 or Google Workspace?
No. Those services handle their own redundancy, and sending servers retry for days after temporary failures. An extra MX only opens another door for spam.
Conclusion and next steps
Most DNS problems come down to a handful of rules: a CNAME stands alone, SPF is a single record, AAAA goes out only when IPv6 works, PTR belongs to whoever owns the IP, and "propagation" is old TTLs running out. What you can do today:- Confirm with dig NS and dig +trace which nameservers actually serve your domain.
- Check that you have exactly one SPF record under the 10-lookup limit; start DMARC at p=none and begin reading the reports.
- Test your AAAA records with curl -6.
- Make sure your CAA set covers every CA you use.
- Export your zone into version control and follow this runbook on your next migration.
Son düzenleyen: