Unbound ile DNS over HTTPS (DoH) Yapılandırması

Klasik DNS’in üzerinden geçen her sorgu düz metin olarak gidiyor, bu herkesçe bilinen bir gerçek. ISP’ler logluyor, ağ cihazları izliyor, kötü niyetli aktörler manipüle ediyor. DNS over HTTPS bu soruna şifreli bir tünel açarak çözüm getiriyor. Peki ya kendi Unbound sunucunuzu DoH istemcisi olarak yapılandırmak istediğinizde? İşte burada işler biraz karmaşıklaşıyor.

Bu yazıda Unbound’u hem DoH forwarder hem de yerel çözümleyici olarak nasıl çalıştıracağınızı anlatacağım. Kurumsal ağda veya ev lab ortamında fark etmez, adımlar büyük ölçüde aynı.

DoH Nedir ve Unbound ile İlişkisi Nereye Oturur

DNS over HTTPS, DNS sorgularını standart HTTPS trafiği içinde taşır. Port 443 üzerinden çalışır, dolayısıyla firewall’lardan kolayca geçer ve trafik analizi yapılması son derece zorlaşır. RFC 8484 ile standartlaşmış bu protokol, artık Cloudflare, Google, Quad9 gibi sağlayıcılar tarafından yaygın olarak destekleniyor.

Unbound tarafında ise durum şöyle: Unbound kendi başına bir DoH sunucusu olarak çalışabilir (istemciler Unbound’a HTTPS üzerinden sorgu gönderir), ya da Unbound upstream’e DoH kullanarak bağlanabilir. Bu iki senaryo birbirinden farklı yapılandırma gerektiriyor. Çoğu yazıda bunlar birbirine karıştırılıyor, dikkatli olun.

Biz bugün ağırlıklı olarak şu senaryoya odaklanacağız: İç ağdaki cihazlar klasik DNS ile Unbound’a bağlanır, Unbound ise upstream’e DoH kullanarak iletir. Buna “DoH proxy” veya “DoH forwarder” diyebilirsiniz.

Ortam ve Ön Gereksinimler

Yazı boyunca kullandığım ortam:

  • Debian 12 (Bookworm) üzerinde Unbound 1.17+
  • Upstream DoH sağlayıcısı olarak Cloudflare (1.1.1.1) ve Quad9
  • Yerel ağ: 192.168.10.0/24

Unbound sürümünüzü kontrol edin:

unbound -V

Çıktıda TCP Fast Open, TLS ve HTTPS desteğinin olduğundan emin olun. Eski sürümlerde DoH desteği sınırlı veya hiç yok.

apt update && apt install unbound unbound-anchor -y

Kurulum sonrası servis durumunu kontrol edelim:

systemctl status unbound
unbound-checkconf /etc/unbound/unbound.conf

Temel Unbound Yapılandırması

Başlamadan önce mevcut yapılandırmayı yedekleyelim:

cp /etc/unbound/unbound.conf /etc/unbound/unbound.conf.bak

/etc/unbound/unbound.conf.d/ altında modüler yapılandırma kullanmak daha sağlıklı. Şimdi ana yapılandırma dosyasını açalım ve temel server: bloğunu düzenleyelim:

cat > /etc/unbound/unbound.conf.d/main.conf << 'EOF'
server:
    # Temel ayarlar
    verbosity: 1
    num-threads: 2
    interface: 0.0.0.0
    port: 53
    do-ip4: yes
    do-ip6: no
    do-udp: yes
    do-tcp: yes

    # Performans ayarları
    so-rcvbuf: 1m
    so-sndbuf: 1m
    msg-cache-size: 64m
    rrset-cache-size: 128m
    cache-min-ttl: 300
    cache-max-ttl: 86400
    prefetch: yes
    prefetch-key: yes

    # Güvenlik
    hide-identity: yes
    hide-version: yes
    harden-glue: yes
    harden-dnssec-stripped: yes
    harden-referral-path: yes
    use-caps-for-id: yes

    # Erişim kontrolü
    access-control: 127.0.0.0/8 allow
    access-control: 192.168.10.0/24 allow
    access-control: 0.0.0.0/0 refuse

    # DNSSEC
    auto-trust-anchor-file: "/var/lib/unbound/root.key"
EOF

Bu temel yapılandırma DoH olmadan da çalışır. Şimdi asıl meseleye girelim.

DoH Upstream Forwarder Yapılandırması

Unbound’un native DoH forwarding desteği 1.16 sürümüyle geldi. Ancak burada kritik bir nokta var: Unbound, DoH upstream’e bağlanmak için forward-zone içinde forward-tls-upstream kullanır ve bunu gerçek anlamda DoH (HTTPS üzerinden) değil, DNS over TLS (DoT) olarak yapar.

Gerçek DoH için iki yol var:

Yol 1: dns-over-https proxy aracı (dnsproxy, stubby, cloudflared) kullanıp Unbound’u buna yönlendirmek.

Yol 2: Unbound 1.17+ ile doğrudan https: URL yapılandırması (deneysel destek).

Her iki yolu da göstereceğim.

Yol 1: Cloudflared ile DoH Proxy

Cloudflared’ı kuruyoruz:

# ARM değilse x86_64 için
wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
dpkg -i cloudflared-linux-amd64.deb

# Servis kullanıcısı oluştur
useradd -s /usr/sbin/nologin -r -M cloudflared

Cloudflared yapılandırma dosyasını oluşturuyoruz:

mkdir -p /etc/cloudflared
cat > /etc/cloudflared/config.yml << 'EOF'
proxy-dns: true
proxy-dns-port: 5053
proxy-dns-upstream:
  - https://1.1.1.1/dns-query
  - https://1.0.0.1/dns-query
  - https://9.9.9.9/dns-query
proxy-dns-address: "127.0.0.1"
EOF

Systemd servis dosyası:

cat > /etc/systemd/system/cloudflared-proxy.service << 'EOF'
[Unit]
Description=Cloudflared DoH Proxy
After=network.target

[Service]
Type=simple
User=cloudflared
ExecStart=/usr/local/bin/cloudflared --config /etc/cloudflared/config.yml
Restart=on-failure
RestartSec=5
NoNewPrivileges=yes
ProtectSystem=strict
ReadWritePaths=/var/log/cloudflared

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable --now cloudflared-proxy
systemctl status cloudflared-proxy

Şimdi Unbound’u bu proxy’ye yönlendiriyoruz:

cat > /etc/unbound/unbound.conf.d/forward.conf << 'EOF'
forward-zone:
    name: "."
    forward-addr: 127.0.0.1@5053
    forward-first: no
EOF

Yapılandırmayı test edip servisi yeniden başlatıyoruz:

unbound-checkconf
systemctl restart unbound
dig @127.0.0.1 example.com

Yol 2: Unbound Native DoT (DNS over TLS)

Eğer DoT yeterliyse (çoğu kurumsal senaryoda yeterli), cloudflared’a gerek yok:

cat > /etc/unbound/unbound.conf.d/forward-tls.conf << 'EOF'
forward-zone:
    name: "."
    forward-tls-upstream: yes
    forward-addr: 1.1.1.1@853#cloudflare-dns.com
    forward-addr: 1.0.0.1@853#cloudflare-dns.com
    forward-addr: 9.9.9.9@853#dns.quad9.net
    forward-addr: 149.112.112.112@853#dns.quad9.net
EOF

# işaretinden sonraki kısım TLS SNI için hostname. Bu olmadan sertifika doğrulaması yapılamaz, boş bırakmayın.

TLS bağlantısı için CA sertifika dosyasını da belirtmek gerekiyor:

# server: bloğuna eklenmeli
# tls-cert-bundle: "/etc/ssl/certs/ca-certificates.crt"

main.conf dosyasındaki server: bloğuna bu satırı ekleyin.

Unbound’u DoH Sunucusu Olarak Yapılandırmak

Bu senaryo farklı: İstemciler Unbound’a HTTPS üzerinden sorgu gönderecek. Bunun için önce bir TLS sertifikasına ihtiyaç var.

Self-signed sertifika üretiyoruz (iç ağ için yeterli):

mkdir -p /etc/unbound/ssl
openssl req -x509 -nodes -days 3650 
    -newkey rsa:2048 
    -keyout /etc/unbound/ssl/unbound.key 
    -out /etc/unbound/ssl/unbound.crt 
    -subj "/CN=dns.local/O=Internal DNS/C=TR" 
    -addext "subjectAltName=DNS:dns.local,IP:192.168.10.1"

chown unbound:unbound /etc/unbound/ssl/unbound.key
chmod 600 /etc/unbound/ssl/unbound.key

Let’s Encrypt sertifikası kullanıyorsanız çok daha iyi. Aşağıdaki yapılandırmada sertifika yollarını güncelleyin.

Şimdi Unbound’a DoH sunucu yapılandırmasını ekleyelim. Bu kısım Unbound 1.17+ gerektiriyor:

cat > /etc/unbound/unbound.conf.d/doh-server.conf << 'EOF'
server:
    # HTTPS/DoH sunucu ayarları
    https-port: 443
    tls-service-key: "/etc/unbound/ssl/unbound.key"
    tls-service-pem: "/etc/unbound/ssl/unbound.crt"
    tls-port: 853
    interface: 0.0.0.0@443
    interface: 0.0.0.0@853
    interface: 0.0.0.0@53
EOF

Port 443 için root yetkisi gerekiyor. Bunu çözmek için iki yol:

Yol A: net_bind_service capability atamak:

setcap 'cap_net_bind_service=+ep' $(which unbound)

Yol B: Systemd socket aktivasyonu veya port yönlendirme. Iptables ile 443’ü 5335’e yönlendirmek daha temiz bir yol:

iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 5335
iptables -t nat -A OUTPUT -p tcp -d localhost --dport 443 -j REDIRECT --to-port 5335
# Kalıcı için iptables-persistent
apt install iptables-persistent
netfilter-persistent save

Bu durumda Unbound’u 5335 üzerinde dinletiyor, iptables 443’ten yönlendiriyor.

DNSSEC Doğrulaması

DoH kullanıyor olsanız bile DNSSEC atlamamalısınız. İkisi birbirini tamamlar.

# Root güven çıpasını güncelle
unbound-anchor -a /var/lib/unbound/root.key -v

# Test
dig @127.0.0.1 dnssec-failed.org
# AD flag olmadan SERVFAIL dönmeli

dig @127.0.0.1 google.com +dnssec
# Yanıtta "ad" (authenticated data) flag'i görülmeli

Split-Horizon DNS ile Birleştirmek

Gerçek dünya senaryolarında iç ağ için bazı domainlerin farklı çözülmesi gerekiyor. DoH forwarding’i kullanırken split-horizon DNS’i şöyle kuruyoruz:

cat > /etc/unbound/unbound.conf.d/local-zones.conf << 'EOF'
# İç domain için yerel çözümleme
local-zone: "sirket.local." static

local-data: "dc01.sirket.local. IN A 192.168.10.10"
local-data: "dc02.sirket.local. IN A 192.168.10.11"
local-data: "fileserver.sirket.local. IN A 192.168.10.20"
local-data: "10.10.168.192.in-addr.arpa. IN PTR dc01.sirket.local."

# Bu zone için upstream'e gitme, lokal cevapla
auth-zone:
    name: "sirket.local."
    master: "192.168.10.10"
    fallback-enabled: no
    for-downstream: yes
    for-upstream: no
EOF

Peki ya bazı domainler için DoH’u bypass etmek istiyorsak? Örneğin şirket içi sistemler için DoT/DoH yerine direkt sunucuya git:

cat >> /etc/unbound/unbound.conf.d/local-zones.conf << 'EOF'

# Sadece bu zone için farklı upstream
forward-zone:
    name: "ozelzone.internal."
    forward-addr: 10.0.0.53@53
    forward-tls-upstream: no
EOF

İzleme ve Log Yapılandırması

DoH trafiğini izlemek önemli. Unbound’un log seviyesini ayarlayalım:

cat > /etc/unbound/unbound.conf.d/logging.conf << 'EOF'
server:
    verbosity: 2
    log-queries: yes
    log-replies: yes
    log-tag-queryreply: yes
    logfile: "/var/log/unbound/unbound.log"
    log-time-ascii: yes
    use-syslog: no
EOF

mkdir -p /var/log/unbound
chown unbound:unbound /var/log/unbound

Log rotasyonu için:

cat > /etc/logrotate.d/unbound << 'EOF'
/var/log/unbound/unbound.log {
    daily
    rotate 7
    compress
    delaycompress
    missingok
    notifempty
    create 640 unbound unbound
    postrotate
        systemctl kill -s HUP unbound
    endscript
}
EOF

Canlı sorguları izlemek için:

# Unbound stats
unbound-control stats_noreset | grep -E "total|cache|num.queries"

# Anlık log takibi
tail -f /var/log/unbound/unbound.log | grep -v "127.0.0.1"

# DoH üzerinden gelen sorguları say
grep "HTTPS" /var/log/unbound/unbound.log | wc -l

Sık Karşılaşılan Sorunlar ve Çözümleri

Sorun: unbound-checkconf hata veriyor, https-port tanınmıyor.

Bu Unbound sürümünüzün 1.17 altında olduğunu gösterir. Backport reposundan güncelleyin:

echo "deb http://deb.debian.org/debian bookworm-backports main" >> /etc/apt/sources.list
apt update
apt install -t bookworm-backports unbound

Sorun: Forward zone çalışıyor ama TLS doğrulaması başarısız.

CA bundle yolunu kontrol edin:

ls -la /etc/ssl/certs/ca-certificates.crt
# Unbound config'inde tls-cert-bundle doğru set edilmiş mi?
openssl s_client -connect 1.1.1.1:853 -servername cloudflare-dns.com

Sorun: Cloudflared başlatılıyor ama Unbound sorguları zaman aşımına uğruyor.

Port 5053’ün dinlenip dinlenmediğini kontrol edin:

ss -tulnp | grep 5053
# Test sorgusu
dig @127.0.0.1 -p 5053 google.com

Sorun: Port 443’te başlatma izin hatası.

Capability ya da iptables yönlendirme yollarından birini seçin. Systemd servis dosyasına AmbientCapabilities=CAP_NET_BIND_SERVICE eklemek de çalışır:

systemctl edit unbound
# [Service] altına ekle:
# AmbientCapabilities=CAP_NET_BIND_SERVICE

Performans Testi

Her şeyi kurduktan sonra performansı ölçmek önemli:

# dnsperf ile yük testi
apt install dnsperf

# Test sorgusu dosyası oluştur
cat > /tmp/queries.txt << 'EOF'
google.com A
github.com A
cloudflare.com A
stackoverflow.com A
linux.org A
EOF

# Yük testi
dnsperf -s 127.0.0.1 -d /tmp/queries.txt -l 30 -c 10

# Gecikme testi
for domain in google.com github.com cloudflare.com; do
    echo -n "$domain: "
    dig @127.0.0.1 $domain | grep "Query time"
done

Cache hit oranınızı düzenli kontrol edin. %80 üzerindeyse yapılandırmanız sağlıklı demektir:

unbound-control stats | grep "cache.hits|total.num.queries" | awk -F= '{print $1": "$2}'

Güvenlik Sertleştirmesi

DoH kurulumunu tamamladıktan sonra birkaç ek güvenlik adımı:

cat >> /etc/unbound/unbound.conf.d/main.conf << 'EOF'

    # Rate limiting
    ratelimit: 1000
    ratelimit-slip: 2
    ip-ratelimit: 100

    # Amplifikasyon saldırılarına karşı
    minimal-responses: yes
    rrset-roundrobin: yes

    # Unwanted reply thresholds
    unwanted-reply-threshold: 10000

    # QNAME minimization (gizlilik)
    qname-minimisation: yes
    qname-minimisation-strict: no
EOF

qname-minimisation özellikle önemli. DoH kullanırken upstream’e tam domain adını göndermek yerine sadece gerekli kısmı gönderir, bu upstream sağlayıcının görüş alanını daraltır.

Sonuç

Unbound ile DoH yapılandırması ilk bakışta karmaşık görünüyor, çünkü birden fazla katman var: yerel dinleyici, forwarding mekaniği, TLS sertifikaları, DNSSEC. Ama katmanları tek tek kurduğunuzda mantığı net anlaşılıyor.

Üretim ortamı için önerim şu şekilde:

  • Küçük ve orta ölçekli ortamlarda cloudflared + Unbound kombinasyonu en stabil seçenek
  • Gizlilik önceliğinizse Quad9 veya NextDNS tercih edin, Cloudflare da iyi ama ABD merkezli
  • DoH ile DoT arasında baskı altında kalmayın; ikisi de şifreli, DoT bazı kısıtlı ağlarda 853 portundan bloklanabiliyor, DoH her zaman geçer
  • DNSSEC’i kesinlikle ihmal etmeyin, DoH tek başına yeterli güvenlik sağlamaz
  • Cache ayarlarını ağınızın boyutuna göre düzenleyin, defaults çoğu zaman yeterli olmaz

Bu yazıdaki yapılandırmaları doğrudan kopyalamadan önce kendi ortamınıza göre uyarlayın: IP bloklarını, zone isimlerini, sertifika yollarını gözden geçirin. Her ortam farklı, hazır yapıştır-çalıştır DNS yapılandırması pek olmaz.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir