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.
