Bir Web Uygulaması için DNS Kayıtlarını Kurmak: Apex, www, api, CNAME Flattening, CAA ve Doğrulama TXT'leri
Apex'te CNAME kullanılamaz, çünkü CNAME olan bir isimde başka kayıt olamaz ve apex'te SOA ile NS zorunludur; çözüm sağlayıcının ALIAS, CNAME flattening veya Azure DNS alias özelliğidir. Bookstore'un apex, www, api ve staging kayıtlarını BIND'de kuruyor, PowerDNS'te ALIAS'ın TTL davranışını görüyor, App Service ve Front Door doğrulama TXT'lerini, CAA aramasının üst isimlere tırmanmasını ve dangling CNAME'leri bulan bir script'i gerçek koşularla inceliyoruz.
Sürüm notu: Bu yazıdaki örnekler BIND (açık kaynak DNS sunucusu) 9.20, PowerDNS Authoritative Server 5.0.8 ve dig 9.20 ile Docker 29 üzerinde denenmiştir; Azure ve Cloudflare adımları 14 Kasım 2026 tarihli resmi dokümanlardan aktarılmıştır, bir Azure veya Cloudflare hesabında çalıştırılmamıştır.
Önce Tahmin Et
Sitedeki serilerin ortak örnek uygulaması Bookstore (bir online kitapçı) için bir önceki yazıda domain'i aldık ve DNS'i ayrı bir sağlayıcıya delege ettik. Şimdi Ayşe, Bookstore'un Angular uygulamasını bir PaaS'a taşımak istiyor ve platform ona "domain'ini bookstore-web.azurewebsites.net'e CNAME (bir ismi başka bir isme bağlayan takma ad kaydı) ile bağla" diyor. DNS panelinde isim alanına @ (yani bookstore.example'ın kendisi), tip alanına CNAME yazıyor ve kaydetmeye çalışıyor.
Tahmin et: Panel bu kaydı kabul eder mi? Etmiyorsa neden? Peki panel itiraz etmeseydi, Bookstore'un mail'ine ve doğrulama kayıtlarına ne olurdu? Bu yazıda Bookstore'un bütün DNS haritasını kuruyoruz ve bu sorunun cevabıyla başlıyoruz.
Bookstore'un Hedef Haritası
Önce neyin nereye gideceğine karar verelim. Bookstore'un web'i (bookstore-web, Angular) ve API'si (Bookstore.Api) ayrı yerlerde çalışıyor; staging ortamı da production'la aynı isim düzeninde. A kaydı IPv4, AAAA (IPv6 adres kaydı) IPv6 adresi tutar; TXT (serbest metin kaydı) ise doğrulama gibi işler için kullanılır:
| İsim | Kayıt | Hedef | Ne için |
|---|---|---|---|
bookstore.example | A + AAAA | 203.0.113.10, 2001:db8:10::10 | Angular uygulaması, Nginx arkasında |
www.bookstore.example | CNAME | bookstore.example | Apex'e 301 redirect |
api.bookstore.example | CNAME + TXT | bookstore-api.azurewebsites.net | Bookstore.Api, App Service'te |
staging.bookstore.example | A | 203.0.113.11 | Staging web |
staging-api.bookstore.example | CNAME + TXT | bookstore-api-staging.azurewebsites.net | Staging API |
İki karar dikkat çekebilir. Birincisi, kanonik adres apex (bookstore.example) ve www ona yönleniyor. Tersi de olabilirdi; Teknik SEO (arama motoru optimizasyonu) serisinin redirect ve canonical yazılarında anlattığımız gibi önemli olan birini seçip diğerini 301 ile ona göndermek. DNS redirect yapamaz: CNAME yalnızca "bu ismin cevabı şu ismin cevabıyla aynı" der, tarayıcının adres çubuğundaki www'yu değiştirmez. 301'i web sunucusu (veya altıncı yazıda göreceğimiz CDN (içeriği kullanıcıya yakın sunuculardan dağıtan ağ) kuralı) verir. İkincisi, staging adları staging.api gibi iç içe değil, staging-api gibi düz. Böylece tek bir *.bookstore.example wildcard certificate'ı hepsini kapsar; SSL/TLS Certificate'ları ve HTTPS serisinin ilk yazısında gördüğümüz gibi wildcard yalnızca bir seviye eşleşir.
Bu haritanın zone dosyası, laboratuvardaki DNS sağlayıcısı container'ında şöyle:
$TTL 3600
@ IN SOA ns1.dnshost.example. hostmaster.bookstore.example. 2026111402 7200 3600 1209600 300
@ IN NS ns1.dnshost.example.
@ IN A 203.0.113.10
@ IN AAAA 2001:db8:10::10
www IN CNAME bookstore.example.
staging IN A 203.0.113.11
api IN CNAME bookstore-api.azurewebsites.net.
asuid.api IN TXT "9ABEB8D35A69D8E0F4A0BFF18E629B9F43A21C43C122B267F86E53CCD94D5DDD"
staging-api IN CNAME bookstore-api-staging.azurewebsites.net.
asuid.staging-api IN TXT "E0569773CCBDE09F6A6E5713B605DB0178702CB5C816155CD142437EF63CE573"
@ IN CAA 0 issue "letsencrypt.org"
@ IN CAA 0 issue "digicert.com"
@ IN CAA 0 issuewild ";"
@ IN CAA 0 iodef "mailto:security@bookstore.example"
@ IN TXT "google-site-verification=pX3c9QeLr0vT2mWb8yKdN5hJ7sFa1uZo4iGyE6"
promo IN CNAME bookstore-promo-2025.azurewebsites.net.
En alttaki promo satırı haritada yok; geçen yılki kampanyadan kalmış ve kimse silmemiş. Ona yazının sonunda döneceğiz. asuid TXT'leri ve CAA (certificate verebilecek kuruluşları sınırlayan kayıt) kayıtlarını da sırayla açacağız.
Apex'te Neden CNAME Olmaz?
Önce Tahmin Et'teki kaydı BIND'e yükletmeyi denedim:
$ cat apex-cname.zone
$TTL 3600
@ IN SOA ns1.dnshost.example. hostmaster.bookstore.example. 2026111401 7200 3600 1209600 300
@ IN NS ns1.dnshost.example.
@ IN CNAME bookstore-web.azurewebsites.net.
$ named-checkzone bookstore.example apex-cname.zone
dns_master_load: apex-cname.zone:4: bookstore.example: CNAME and other data
dns_master_load: apex-cname.zone:4: bookstore.example: CNAME and other data
zone bookstore.example/IN: loading from master file apex-cname.zone failed: CNAME and other data
zone bookstore.example/IN: not loaded due to errors.
Kural şu: bir isimde CNAME varsa, o isimde başka hiçbir kayıt olamaz. CNAME, "bu ismin her şeyi için şuraya bak" demek; aynı isimde bir de MX (mail sunucusu kaydı) veya TXT olursa resolver hangisine inanacağını bilemez. Apex'te ise SOA (zone'un yetki ve seri numarası bilgisi) ve NS (nameserver) kayıtları zorunlu, yani apex'te CNAME her zaman bu kuralı çiğner. Panel itiraz etmeseydi, CNAME'i izleyen resolver'lar Bookstore'un MX, SPF (domain adına mail gönderebilecek sunucuların listesi) ve doğrulama TXT'lerini artık azurewebsites.net tarafında arardı. Mail'ler gitmez, Search Console doğrulaması düşerdi. Hata ayıklaması en zor DNS sorunlarından biri olurdu, çünkü site çalışmaya devam ederdi.
Aynı kural apex dışında da geçerli ve en sık şu şekilde karşına çıkar: www'yu bir platforma CNAME ile bağlamışsın, sonra bir SaaS aracı "doğrulama için www'ya TXT ekle" diyor:
$ named-checkzone bookstore.example www-cname-txt.zone
dns_master_load: www-cname-txt.zone:6: www.bookstore.example: CNAME and other data
zone bookstore.example/IN: loading from master file www-cname-txt.zone failed: CNAME and other data
zone bookstore.example/IN: not loaded due to errors.
Bu yüzden Azure gibi platformlar doğrulama TXT'sini CNAME'in yanına değil, asuid.www veya _dnsauth.www gibi ayrı bir isme koydurur.
ALIAS, ANAME, CNAME Flattening ve Azure DNS Alias
Apex'i bir hostname'e bağlama ihtiyacı o kadar yaygın ki her büyük DNS sağlayıcısı kendi çözümünü yazmış. Adları farklı ama fikir aynı: CNAME'i resolver'a bırakmak yerine authoritative sunucu hedefi kendisi çözer ve sonucu düz A/AAAA kaydı olarak döner. Standart bir record tipi yok; ALIAS (sağlayıcıya özgü sanal kayıt tipi) ve ANAME (aynı fikrin başka sağlayıcılardaki adı) sağlayıcı tarafındaki özellikler, zone dosyasının kendisinde bir karşılıkları yok. Bu davranışı açık kaynak PowerDNS'te çalıştırıp görmek mümkün. Laboratuvara geçici bir PowerDNS container'ı ekledim ve apex'i, bilinen bir public hedefe, example.net'e ALIAS ile bağladım:
# pdns.conf
launch=bind
bind-config=/etc/pdns-lab/named.conf
local-address=0.0.0.0
resolver=1.1.1.1
expand-alias=yes
; bookstore.example.zone
$TTL 3600
@ IN SOA ns1.dnshost.example. hostmaster.bookstore.example. 2026111401 7200 3600 1209600 300
@ IN NS ns1.dnshost.example.
@ IN ALIAS example.net.
www IN CNAME example.net.
$ dig @192.0.2.30 bookstore.example A +norec +noall +comments +answer
;; flags: qr aa; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
bookstore.example. 61 IN A 104.20.21.8
bookstore.example. 61 IN A 172.66.175.59
$ dig @192.0.2.30 bookstore.example AAAA +norec +noall +answer
bookstore.example. 300 IN AAAA 2606:4700:10::6814:1508
bookstore.example. 300 IN AAAA 2606:4700:10::ac42:af3b
$ dig @192.0.2.30 www.bookstore.example A +norec +noall +answer
www.bookstore.example. 3600 IN CNAME example.net.
$ dig @1.1.1.1 example.net A +noall +answer
example.net. 60 IN A 104.20.21.8
example.net. 60 IN A 172.66.175.59
Üç şey görülüyor. Apex sorusuna CNAME değil, aa bayraklı düz A ve AAAA cevapları geldi; SOA ve NS ile yan yana durabildiler. www ise normal bir CNAME döndü ve hedefi çözmek resolver'a kaldı. En ilginci TTL (kaydın cache'te tutulabileceği süre): zone'da 3600 yazmasına rağmen apex cevabının TTL'i 61. PowerDNS hedefi kendi resolver'ına sordu ve oradan gelen kalan TTL'i aktardı. Yani apex'in cache süresi senin zone'un değil, hedefin kontrolünde. Hedef IP'sini değiştirdiğinde apex de ona uyar; ALIAS'ın amacı da zaten bu.
Bu davranışın üç ticari karşılığı:
- Cloudflare CNAME flattening: Apex'te bir CNAME yazarsın, Cloudflare zinciri kendisi izleyip sonucu A/AAAA olarak döner. Apex'te bu varsayılan davranış; diğer isimler için "flatten all CNAMEs" ücretli planlarda. Cloudflare'in dokümanı iki uyarı yapıyor: düzleştirilen bir isim CNAME döndürmediği için, CNAME'in varlığını kontrol eden üçüncü taraf doğrulamaları başarısız olabilir; hedefin A/AAAA kaydı yoksa cevap boş döner ve bu bir yayılma sorunu gibi görünür.
- Azure DNS alias record: A, AAAA ve CNAME kayıtları bir DNS değeri yerine bir Azure kaynağını (Standard SKU (Azure'daki ürün katmanı) public IP, Traffic Manager profili, Azure CDN endpoint'i, Front Door endpoint'i) gösterebilir ve apex'te kullanılabilir. Kaynak silinirse kayıt boş bir record set'e döner; yani silinmiş bir IP'yi göstermeye devam etmez. App Service'in kendisi bu listede yok; App Service için Microsoft'un önerisi apex'te uygulamanın IP'sine A kaydı.
- Diğer sağlayıcıların ALIAS/ANAME'i: Mantık aynı, ama TTL'in nasıl ayarlandığı, IPv6'yı destekleyip desteklemediği ve hedef çözülemezse ne döndüğü sağlayıcıdan sağlayıcıya değişiyor. Kullanmadan önce sağlayıcının dokümanında bu üç soruya cevap ara.
Önemli bir yan etki daha var: flattening'de hedefi çözen sağlayıcının resolver'ı, kullanıcı değil. Hedef bir CDN ise ve kullanıcının konumuna göre farklı IP döndürüyorsa, yakınlık hesabı kullanıcıya göre değil sağlayıcının resolver'ına göre yapılır. Büyük sağlayıcılar bunu EDNS (DNS protokolüne ek alanlar ekleyen uzantı) Client Subnet ile, yani resolver'ın kullanıcının ağ bloğunu sorguya eklemesiyle, veya kendi anycast ağlarıyla telafi eder, ama bu da sağlayıcıya göre değişir. Bookstore'un apex'ini bir CDN'e bağlarken bunun ayrıntısını beşinci ve altıncı yazılarda göreceğiz.
PaaS'a Bağlamak: App Service, Container Apps ve Front Door
Bir PaaS platformu senin domain'ini kabul etmeden önce iki şey ister: trafiği ona yönlendiren bir kayıt (A veya CNAME) ve domain'in sana ait olduğunu kanıtlayan bir doğrulama kaydı. Microsoft Learn'deki güncel tablolar şöyle:
App Service: Apex için uygulamanın IP adresine bir A kaydı ve asuid adında bir TXT. Alt domain için <app>.azurewebsites.net'e CNAME (IP değişebileceği için A yerine önerilen bu) ve asuid.<alt-domain> TXT'si. TXT'nin değeri uygulamanın "domain verification ID"si. Microsoft bu TXT'nin teknik olarak zorunlu olmadığını, ama başka App Service uygulamalarının senin alt domain'ini ele geçirmesini önlediği için şiddetle önerildiğini yazıyor. Free (F1) katmanında custom domain yok.
Container Apps: Aynı asuid düzeni; apex için environment'ın IP'sine A, alt domain için uygulamanın ürettiği adrese CNAME. Ücretsiz managed certificate için iki ek şart var ve ikisi de doğrudan DNS'le ilgili. CNAME, uygulamanın adresine doğrudan gitmeli; arada bir Traffic Manager veya Cloudflare gibi ara bir CNAME varsa certificate verilemez ve yenilenemez. Domain'de bir CAA kaydı varsa 0 issue "digicert.com" izni şart.
Azure Front Door Standard/Premium: Doğrulama için _dnsauth.<alt-domain> adında bir TXT, trafik için Front Door endpoint'ine (*.azurefd.net) CNAME. Apex için Azure DNS kullanıyorsan alias record, başka bir sağlayıcı kullanıyorsan onun flattening/ALIAS özelliği gerekir.
Laboratuvarda api kayıtları App Service düzenine göre:
$ dig @192.0.2.20 api.bookstore.example A +norec +noall +answer
api.bookstore.example. 3600 IN CNAME bookstore-api.azurewebsites.net.
$ dig @192.0.2.20 asuid.api.bookstore.example TXT +norec +noall +answer
asuid.api.bookstore.example. 3600 IN TXT "9ABEB8D35A69D8E0F4A0BFF18E629B9F43A21C43C122B267F86E53CCD94D5DDD"
Managed certificate'ın DNS'e bağımlılığı genelde unutulan kısım. Platform certificate'ı yenilerken domain'i yeniden doğrular: CNAME hâlâ doğru yere mi gidiyor, CAA izin veriyor mu, doğrulama kaydı yerinde mi? Bir yıl önce kurulup çalışan bir domain, biri "kullanılmayan TXT'leri temizleyelim" dediği için veya CAA'ya yeni bir CA (certificate veren kuruluş) eklenip DigiCert unutulduğu için yenilemede düşebilir. Certificate tarafının ayrıntıları SSL/TLS Certificate'ları ve HTTPS serisinin "Yönetilen Platformlarda Certificate" yazısında.
CAA: Hangi CA Certificate Verebilir?
CAA (Certification Authority Authorization; domain için hangi sertifika kuruluşlarının certificate verebileceğini söyleyen kayıt), IETF'in (internet standartlarını yazan kuruluş) RFC (internet standart dokümanı) 8659 numaralı dokümanında tanımlı. Bir CA (Certificate Authority; certificate veren kuruluş) certificate vermeden önce CAA'ya bakmak zorunda. Bookstore'un kayıtları:
$ dig @192.0.2.20 bookstore.example CAA +norec +noall +answer
bookstore.example. 3600 IN CAA 0 iodef "mailto:security@bookstore.example"
bookstore.example. 3600 IN CAA 0 issuewild ";"
bookstore.example. 3600 IN CAA 0 issue "letsencrypt.org"
bookstore.example. 3600 IN CAA 0 issue "digicert.com"
Okunuşu şöyle: Bookstore'un isimleri için yalnızca Let's Encrypt (Nginx tarafındaki Certbot için) ve DigiCert (App Service ve Container Apps managed certificate'ları için) certificate verebilir. issuewild ";" ise kimsenin wildcard vermesine izin vermiyor; bir wildcard certificate'a ihtiyaç duyduğunda bu satırı bilinçli olarak değiştirmek zorunda kalırsın. RFC 8659'a göre bir isim için issuewild varsa wildcard'larda issue satırları dikkate alınmaz. iodef, kurala aykırı bir istek gelirse CA'nın nereye haber verebileceğini söyler; bunu desteklemek CA'lar için zorunlu değil. Baştaki 0 flag'i; 128 olursa "bu tag'i anlamıyorsan certificate verme" anlamına gelir.
CAA'nın en çok yanlış anlaşılan kısmı aramanın nasıl yapıldığı. CA önce tam isme bakar; orada CAA yoksa bir üst isme çıkar ve ilk bulduğu CAA kümesini kullanır. Hiçbir seviyede bulamazsa herkes certificate verebilir. Bu davranışı taklit eden kısa bir script:
#!/bin/sh
# Kullanım: caa-lookup.sh <isim> <sunucu>
# Bir CA'nın kullanacağı CAA kümesini bulur: önce ismin kendisi, sonra her üst isim.
name=${1%.}; server=$2
while [ -n "$name" ]; do
caa=$(dig @"$server" "$name" CAA +noall +answer | awk '$4 == "CAA"')
if [ -n "$caa" ]; then
echo "relevant CAA set found at $name:"
echo "$caa" | awk '{$1=$2=$3=$4=""; print " " $0}'
exit 0
fi
echo "no CAA at $name, climbing"
case "$name" in *.*) name=${name#*.} ;; *) name="" ;; esac
done
echo "no CAA anywhere: any CA may issue"
$ ./caa-lookup.sh staging-api.bookstore.example 192.0.2.20
no CAA at staging-api.bookstore.example, climbing
relevant CAA set found at bookstore.example:
0 issue "letsencrypt.org"
0 iodef "mailto:security@bookstore.example"
0 issue "digicert.com"
0 issuewild ";"
$ ./caa-lookup.sh www.google.com 1.1.1.1
no CAA at www.google.com, climbing
relevant CAA set found at google.com:
0 issue "pki.goog"
$ ./caa-lookup.sh www.example.org 1.1.1.1
no CAA at www.example.org, climbing
no CAA at example.org, climbing
no CAA at org, climbing
no CAA anywhere: any CA may issue
Yani apex'e koyduğun CAA, altındaki bütün isimleri kapsar. Bir alt isme farklı bir kural gerekiyorsa (diyelim yalnızca api için başka bir CA), o isme kendi CAA kaydını koyarsın ve arama orada durur. CNAME'li isimlerde ise ayrıntı var: api bir CNAME olduğu için CA'nın resolver'ı CAA sorgusunda o CNAME'i izler ve hedefte (azurewebsites.net tarafında) bir CAA varsa onu kullanır. Hedefte yoksa tırmanma senin zone'unda, bookstore.example'dan devam eder.
Doğrulama TXT'leri ve Zone'un Bakımı
Bookstore'un zone'unda şimdilik bir Search Console TXT'si var. Bir yıl sonra bu sayı genelde ona çıkar: analytics aracı, e-posta sağlayıcısı, bir SaaS destek aracı, Microsoft 365, Apple, Atlassian, Facebook domain doğrulaması... Her biri apex'e bir TXT ekletir. Zararsız görünür ama iki sorun yaratır. Apex'e sorulan TXT cevabı büyür; birçok resolver ve bazı ağlar büyük UDP (bağlantısız taşıma protokolü) cevaplarında sorun yaşar ve TCP'ye düşmek gerekir. Daha önemlisi, kimsenin kime ait olduğunu bilmediği kayıtları silmeye kimse cesaret edemez.
Kural basit: her doğrulama kaydının yanına sahibini ve amacını yaz. Zone'u kod olarak tutuyorsan (dördüncü yazının konusu) bu bir yorum satırı; panel kullanıyorsan sağlayıcının "comment" alanı. Silerken dikkat: Google Search Console doğrulama kaydını periyodik olarak yeniden kontrol eder ve kayıt silinirse doğrulama düşer. Yani "doğrulandı, artık silebilirim" çoğu servis için yanlış. Silinecek olanlar, artık kullanılmayan servislere ait olanlar.
Dangling CNAME ve Subdomain Takeover
Şimdi promo satırına dönelim. Geçen yıl kampanya için bir App Service uygulaması açıldı, promo.bookstore.example ona CNAME ile bağlandı. Kampanya bitince uygulama silindi, DNS kaydı unutuldu. Bu kayda dangling CNAME denir: var olmayan bir şeye işaret ediyor. Risk şu: bookstore-promo-2025 adı Azure'da artık boşta ve herhangi biri o adla yeni bir uygulama açabilir. Açtığı anda promo.bookstore.example onun sitesini göstermeye başlar. Bookstore'un adı altında, Bookstore'un domain'inde sahte bir kampanya sayfası. Domain'e bağlı cookie'ler ve CSP (Content Security Policy; tarayıcıya hangi kaynaklardan içerik yüklenebileceğini söyleyen header) kuralları da işin içine girince etki bir phishing sayfasından fazlası olabilir.
Zone'daki bütün CNAME'lerin hedefini kontrol eden bir script:
#!/bin/sh
# Kullanım: find-dangling-cnames.sh <zone-adı> <zone-dosyası> <resolver>
zone=$1; file=$2; resolver=$3
dump=$(named-checkzone -D -o - "$zone" "$file" 2>/dev/null)
echo "$dump" | awk '$4 == "CNAME" {print $1, $5}' |
while read -r name target; do
# kendi zone'umuzdaki hedefler zone'un kendisinden kontrol edilir
case "$target" in
*"$zone.") echo "$dump" | awk -v t="$target" '$1 == t {f=1} END {exit !f}' && status=NOERROR || status=NXDOMAIN ;;
*) status=$(dig @"$resolver" "$target" A +noall +comments | grep -o 'status: [A-Z]*' | cut -d' ' -f2) ;;
esac
asuid=$(echo "$dump" | awk -v n="asuid.$name" '$1 == n && $4 == "TXT" {print "yes"}')
case "$status" in
NOERROR) echo "OK $name -> $target" ;;
NXDOMAIN) echo "DANGLING $name -> $target (verification TXT: ${asuid:-no})" ;;
*) echo "CHECK $name -> $target ($status)" ;;
esac
done
$ ./find-dangling-cnames.sh bookstore.example bookstore.example.zone 1.1.1.1
DANGLING api.bookstore.example. -> bookstore-api.azurewebsites.net. (verification TXT: yes)
DANGLING promo.bookstore.example. -> bookstore-promo-2025.azurewebsites.net. (verification TXT: no)
DANGLING staging-api.bookstore.example. -> bookstore-api-staging.azurewebsites.net. (verification TXT: yes)
OK www.bookstore.example. -> bookstore.example.
Laboratuvarda hiçbir App Service uygulaması gerçekten yok; bu yüzden üç Azure hedefi de public DNS'te NXDOMAIN dönüyor. Bu bile öğretici: api ve staging-api'nin yanında asuid TXT'si var. Başka bir abonelikte o adla uygulama açan biri, domain'i kendi uygulamasına eklemeye çalıştığında App Service bu doğrulama ID'sini kontrol eder ve eşleşmediği için reddeder. promo'nun ise böyle bir koruması yok. Gerçek bir sistemde api ve staging-api satırları OK olurdu, promo ise aynen bu şekilde kalırdı.
NXDOMAIN kontrolü her platformda işe yaramaz. Bazı platformlar alt domain'lerinin hepsine wildcard ile cevap verir:
$ dig @1.1.1.1 bookstore-docs-2019.github.io A +noall +answer
bookstore-docs-2019.github.io. 3600 IN A 185.199.108.153
bookstore-docs-2019.github.io. 3600 IN A 185.199.109.153
bookstore-docs-2019.github.io. 3600 IN A 185.199.110.153
bookstore-docs-2019.github.io. 3600 IN A 185.199.111.153
Böyle bir hesap yok, ama isim çözülüyor. GitHub Pages gibi platformlarda dangling kaydı DNS değil, HTTP seviyesinde yakalarsın: sayfa platformun "burada site yok" cevabını mı dönüyor? En sağlam çözüm ise süreç: bir cloud kaynağını silerken ona işaret eden DNS kaydını aynı değişiklikte sil. Sıra da önemli: önce DNS kaydını sil, sonra kaynağı. Ters sırada, arada kalan sürede isim sahipsiz kalır. Azure DNS alias record'ları bu sırayı kendiliğinden sağlar, çünkü kaynak silinince kayıt da boşalır.
Üretimde Dikkat
TTL'i amaca göre seç. Bookstore'un zone'unda varsayılan 3600 saniye: değişiklik bir saat içinde yayılır, resolver'lar da gereksiz yere sorgulamaz. Çoğu sağlayıcının panelde önerdiği 300 saniyelik TTL her zaman daha iyi değil. Authoritative sunucuya giden sorgu sayısını ve kullanıcıların cache miss oranını artırır, sağlayıcı sorgu başına ücret alıyorsa faturayı da. Kısa TTL'e planlı bir değişiklikten önce, geçici olarak geç; nasıl yapılacağı dördüncü yazıda.
AAAA kaydını yalnızca o adreste gerçekten bir şey dinliyorsa ekle. IPv6 adresi çalışmayan bir AAAA kaydı, IPv6 bağlantısı olan kullanıcılarda gecikmeye ve bazı istemcilerde hataya yol açar. Tarayıcıların Happy Eyeballs (IPv6 ve IPv4'ü paralel deneyip ilk başarılı olanı kullanma) davranışı bunu çoğu zaman gizler, ama API'yi çağıran bir mobil uygulama veya bir sunucu tarafı HttpClient aynı toleransı göstermeyebilir. Ekledikten sonra curl -6 https://bookstore.example ile dene.
Zone'u düzenli olarak tara. find-dangling-cnames.sh gibi bir kontrol, haftada bir çalışan bir job'da ucuz bir sigorta. Azure kullanıyorsan Microsoft'un dangling DNS'i bulmak için yayımladığı araç ve Defender for Cloud'un ilgili önerileri de var; ama kendi zone'unu en iyi sen bilirsin.
CAA'yı certificate envanteriyle birlikte yönet. Yeni bir platform veya CA eklendiğinde ilk iş CAA'ya bakmak. Container Apps, App Service ve Front Door'un managed certificate'ları için DigiCert, Certbot ve Caddy için Let's Encrypt; listeyi ekipte biri değiştirdiğinde yenileme günü kimsenin haberi olmadan düşen bir certificate'la karşılaşmamak için.
Sık Düşülen Tuzaklar
Redirect'i DNS'te aramak: "www'yu apex'e yönlendir" isteği DNS ile çözülmez. Bazı registrar'ların "URL forwarding" özelliği aslında kendi web sunucularına bir A kaydı koyup oradan HTTP redirect verir; HTTPS'te certificate sorunu çıkarabilir ve trafiğin bir kısmı üçüncü bir tarafın sunucusundan geçer.
Ara CNAME'i unutmak: api'yi önce Traffic Manager'a, oradan App Service'e bağlamak DNS açısından geçerli. Ama Container Apps'in managed certificate'ı gibi doğrudan CNAME bekleyen servisler bu zincirde certificate veremez. CNAME zincirini her zaman uçtan uca, dig +trace veya bir public resolver'la takip et.
CAA'yı DigiCert'süz koymak: "Bütün certificate'larımız Let's Encrypt'ten" diye CAA'ya yalnızca letsencrypt.org yazmak, aynı domain'in altındaki bir App Service managed certificate'ının yenilemesini kırar. Kırılma CAA'yı eklediğin gün değil, yenileme günü ortaya çıkar.
Staging'i iç içe isimlendirmek: api.staging.bookstore.example gibi iki seviyeli isimler *.bookstore.example wildcard certificate'ının kapsamı dışında kalır. Ya her seviye için ayrı certificate alırsın ya da isimleri düz tutarsın.
Silinen kaynağın DNS kaydını bırakmak: promo hikâyesi. Bir kaynağı silmek için açılan her iş kaydında "DNS kaydı silindi mi?" maddesi olsun.
Küçük Bir Deneme
★☆☆ Kendi domain'lerinden birinde (veya iyi bildiğin bir sitede) caa-lookup.sh'ı çalıştır. CAA var mı? Yoksa, kullandığın CA'ları listeleyip doğru CAA kümesini yaz.
★★☆ Laboratuvarda api için kendi CAA kaydını ekle (yalnızca digicert.com). caa-lookup.sh artık nerede duruyor? Apex'teki letsencrypt.org izni api için hâlâ geçerli mi?
★★★ find-dangling-cnames.sh'ı genişlet: NXDOMAIN'e ek olarak, hedef çözülüyorsa curl ile HTTP isteği at ve github.io, azurewebsites.net gibi bilinen platformların "burada uygulama yok" cevaplarını tanı. Script'i bir CI/CD job'ı olarak haftada bir çalıştır.
Bookstore'un web ve API kayıtları hazır. Ama zone'un en kırılgan kısmına henüz dokunmadık: e-posta. Sipariş onayı ve parola sıfırlama mail'leri spam'e düşüyorsa sorun çoğu zaman uygulamada değil DNS'tedir. Bir sonraki yazıda MX ve SPF'i, DKIM (mail'i domain adına imzalayan anahtar kaydı) ve DMARC (doğrulama başarısız olursa ne yapılacağını söyleyen politika) kayıtlarını kuruyor ve büyük e-posta sağlayıcılarının toplu gönderici kurallarına bakıyoruz.