Unbound DNS Sunucusu Ubuntu ve Debian’a Kurulum Rehberi
Bir süredir BIND9 ile uğraşan sistem yöneticileri biliyor: büyük altyapılarda BIND muhteşemdir, ama küçük-orta ölçekli ortamlarda, özellikle sadece recursive resolver ihtiyacı varsa, beraberinde getirdiği karmaşıklık gereksiz bir yük oluşturabilir. İşte tam bu noktada Unbound devreye giriyor. NLnet Labs tarafından geliştirilen bu hafif, güvenlik odaklı DNS resolver, özellikle DNSSEC doğrulama ve önbellekleme konularında ciddi avantajlar sunuyor. Bu yazıda Ubuntu ve Debian üzerinde Unbound’u sıfırdan kurup production-ready hale getireceğiz.
Neden Unbound?
Şunu açıkça söyleyeyim: Unbound her ortam için değil. Authoritative DNS sunucusu ihtiyacınız varsa yanlış araçsınız. Ama şu senaryolar için gerçekten biçilmiş kaftan:
- Kurumsal ağda dahili DNS çözümleyici (recursive resolver) olarak
- Pi-hole veya benzeri reklam engelleyicilerle entegrasyon
- DNSSEC doğrulaması zorunlu olan ortamlar
- DNS-over-TLS veya DNS-over-HTTPS ihtiyacı olan yapılar
- Yüksek önbellekleme performansı istenen küçük-orta datacenter kurulumları
Özellikle bir müşteri projesinde, şirketin tüm DNS trafiğini dışa bağımlı genel resolver’lardan (8.8.8.8 gibi) kurtarıp kendi altyapısında çözümlemek istediğinde Unbound bu işi oldukça temiz çözdü. Hafıza kullanımı minimal, yapılandırması anlaşılır, güvenlik açısından varsayılan ayarlar zaten makul seviyede.
Kurulum Öncesi Hazırlık
Sistem Gereksinimlerini Kontrol Etme
Ubuntu 20.04, 22.04, 24.04 ve Debian 11, 12 için kurulum adımları büyük ölçüde aynı. Önce mevcut DNS durumunu kontrol edelim:
# Mevcut DNS servisini kontrol et
systemctl status systemd-resolved
netstat -tulpn | grep :53
ss -tulpn | grep :53
Çoğu modern Ubuntu kurulumunda systemd-resolved 53 portunu dinliyor. Unbound ile çakışma yaşamamak için bunu düzgünce yönetmek gerekiyor. Bunu atlayan kurulumlar sonradan “port already in use” hatasiyla karşılaşıyor.
systemd-resolved ile Çakışmayı Önleme
# systemd-resolved'ın stub listener'ını devre dışı bırak
sudo mkdir -p /etc/systemd/resolved.conf.d/
sudo tee /etc/systemd/resolved.conf.d/nostublistener.conf > /dev/null <<EOF
[Resolve]
DNSStubListener=no
DNS=127.0.0.1
EOF
# Servisi yeniden başlat
sudo systemctl restart systemd-resolved
# /etc/resolv.conf symlink'ini güncelle
sudo ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf
Bu adım özellikle Ubuntu 20.04 ve sonrasında kritik. Debian kurulumlarında genellikle sorun daha az çıkıyor, ama kontrol etmekte fayda var.
Unbound Kurulumu
Paket Kurulumu
# Paket listelerini güncelle
sudo apt update
# Unbound ve yardımcı araçları kur
sudo apt install -y unbound unbound-anchor dns-root-data
# Kurulumu doğrula
unbound -V
unbound-anchor paketi DNSSEC için root trust anchor dosyasını yönetiyor. dns-root-data ise root zone verilerini içeriyor ve root hints dosyasını sisteme sağlıyor. Bu ikisini atlamayın.
Servis Durumunu Kontrol Etme
sudo systemctl status unbound
sudo systemctl enable unbound
İlk kurulumdan sonra servis hata verebilir, çünkü varsayılan yapılandırma dosyası çok minimal. Asıl konfigürasyon adımından sonra düzelecek.
Ana Yapılandırma Dosyası
Unbound’un ana yapılandırma dosyası /etc/unbound/unbound.conf ve bu dosyanın include ettiği /etc/unbound/unbound.conf.d/ dizini. Ben production ortamlarda her zaman modüler yapıyı tercih ediyorum: ana conf dosyasına dokunmadan, unbound.conf.d/ altında özel dosyalar oluşturuyorum.
Temel Resolver Yapılandırması
sudo tee /etc/unbound/unbound.conf.d/resolver.conf > /dev/null <<'EOF'
server:
# Dinlenecek arayüz ve port
interface: 0.0.0.0
port: 53
# IPv6 kullanmıyorsak devre dışı bırak
do-ipv6: no
do-ip4: yes
do-udp: yes
do-tcp: yes
# Erişim kontrolü - sadece yerel ağdan gelen sorgulara izin ver
access-control: 127.0.0.0/8 allow
access-control: 10.0.0.0/8 allow
access-control: 172.16.0.0/12 allow
access-control: 192.168.0.0/16 allow
access-control: 0.0.0.0/0 refuse
# DNSSEC doğrulama
auto-trust-anchor-file: "/var/lib/unbound/root.key"
# Root hints dosyası
root-hints: "/usr/share/dns/root.hints"
# Önbellekleme ayarları
cache-min-ttl: 300
cache-max-ttl: 86400
cache-max-negative-ttl: 30
# Performans ayarları
num-threads: 2
msg-cache-slabs: 4
rrset-cache-slabs: 4
infra-cache-slabs: 4
key-cache-slabs: 4
rrset-cache-size: 256m
msg-cache-size: 128m
# Gizlilik ve güvenlik
hide-identity: yes
hide-version: yes
harden-glue: yes
harden-dnssec-stripped: yes
use-caps-for-id: yes
# Log ayarları
verbosity: 1
log-queries: no
log-replies: no
logfile: "/var/log/unbound/unbound.log"
# Unwanted reply threshold
unwanted-reply-threshold: 10000
EOF
Birkaç parametreye dikkat çekmek istiyorum:
- use-caps-for-id: DNS 0x20 encoding olarak bilinen teknik. Sorgulardaki harfleri rastgele büyük/küçük yaparak cache poisoning saldırılarını zorlaştırıyor.
- harden-dnssec-stripped: DNSSEC imzalı bir zone’dan imzasız cevap gelirse reddet. Bunu aktif tutun.
- cache-max-negative-ttl: 30: NXDOMAIN cevaplarını 30 saniyeden fazla cache’leme. Uzun negative caching bazı ortamlarda sorun çıkarabiliyor.
Log Dizinini Oluşturma
sudo mkdir -p /var/log/unbound
sudo chown unbound:unbound /var/log/unbound
Yapılandırmayı Doğrulama ve Servisi Başlatma
# Yapılandırma sözdizimini kontrol et
sudo unbound-checkconf
# Servisi yeniden başlat
sudo systemctl restart unbound
sudo systemctl status unbound
# DNS çözümlemesini test et
dig @127.0.0.1 google.com
dig @127.0.0.1 google.com +dnssec
unbound-checkconf hiçbir çıktı vermeden dönerse yapılandırma dosyası sözdizimi doğrudur. Hata varsa satır numarasıyla birlikte bildiriyor, oldukça kullanışlı.
DNSSEC Doğrulamasını Yapılandırma
DNSSEC Unbound’un en güçlü yanlarından biri. Root key’i güncel tutmak için unbound-anchor aracını kullanıyoruz:
# Root trust anchor dosyasını oluştur/güncelle
sudo unbound-anchor -a /var/lib/unbound/root.key
sudo chown unbound:unbound /var/lib/unbound/root.key
# DNSSEC doğrulamasını test et
# Bu sorgu SERVFAIL dönmemeli
dig @127.0.0.1 sigok.verteiltesysteme.net +dnssec
# Bu sorgu SERVFAIL dönmeli (kasıtlı bozuk DNSSEC)
dig @127.0.0.1 sigfail.verteiltesysteme.net +dnssec
İkinci komutun SERVFAIL dönmesi aslında doğru davranış: Unbound DNSSEC doğrulaması başarısız olduğunda sorguyu reddediyor. Bu tam olarak istediğimiz şey.
Root key otomatik güncelleme için bir cron görevi veya systemd timer ayarlamak iyi pratik:
sudo tee /etc/cron.weekly/unbound-anchor > /dev/null <<'EOF'
#!/bin/bash
/usr/sbin/unbound-anchor -a /var/lib/unbound/root.key
chown unbound:unbound /var/lib/unbound/root.key
systemctl reload unbound
EOF
sudo chmod +x /etc/cron.weekly/unbound-anchor
Dahili Alan Adları için Local Zone Tanımlama
Bu kısım özellikle kurumsal ortamlarda çok işe yarıyor. Diyelim ki sirket.local gibi dahili bir domain var ve bu domain için özel DNS kayıtları tanımlamak istiyorsunuz:
sudo tee /etc/unbound/unbound.conf.d/local-zones.conf > /dev/null <<'EOF'
server:
# Dahili zone tanımı
local-zone: "sirket.local." static
# A kayıtları
local-data: "webserver.sirket.local. IN A 192.168.1.10"
local-data: "dbserver.sirket.local. IN A 192.168.1.20"
local-data: "mailserver.sirket.local. IN A 192.168.1.30"
local-data: "vpn.sirket.local. IN A 192.168.1.40"
# PTR kayıtları (reverse DNS)
local-data-ptr: "192.168.1.10 webserver.sirket.local"
local-data-ptr: "192.168.1.20 dbserver.sirket.local"
local-data-ptr: "192.168.1.30 mailserver.sirket.local"
local-data-ptr: "192.168.1.40 vpn.sirket.local"
EOF
local-zone tiplerine dikkat:
- static: Zone’da tanımlanmayan kayıtlar için NXDOMAIN dönülür
- transparent: Tanımlanmayan kayıtlar için upstream’e sorulur
- redirect: Tüm sorgular belirtilen adrese yönlendirilir
Reklam engelleme amacıyla tüm domaine yönlendirme yapmak için redirect kullanılabilir, ama bu konu ayrı bir yazıyı hak ediyor.
Belirli Domain’leri Forward Etme
Bazı durumlarda belirli domain’leri farklı DNS sunucularına yönlendirmek gerekiyor. Örneğin şirket VPN üzerindeyken corp.example.com sorgularını şirket DNS’ine göndermek:
sudo tee /etc/unbound/unbound.conf.d/forward-zones.conf > /dev/null <<'EOF'
# Belirli domain'ler icin forward
forward-zone:
name: "corp.example.com."
forward-addr: 10.0.0.53
forward-first: no
# Tüm diğer sorgular için upstream DNS (opsiyonel)
# Bu olmadan Unbound root sunuculardan recursive çözümleme yapar
# forward-zone:
# name: "."
# forward-addr: 1.1.1.1@853#cloudflare-dns.com
# forward-tls-upstream: yes
EOF
Dikkat: Eğer root zone için forward-zone tanımlarsanız Unbound artık tam recursive çözümleme yapmaz, sorguları o sunucuya iletir. Bu durumda DNSSEC doğrulamasının davranışı değişir. Root zone forward etmek yerine Unbound’u tam recursive resolver olarak kullanmanızı öneririm, zira bu en güvenli ve gizlilik dostu seçenek.
DNS-over-TLS (DoT) Yapılandırması
Gelen sorgular için DoT desteği veya upstream sorgularını TLS üzerinden göndermek için:
sudo tee /etc/unbound/unbound.conf.d/tls.conf > /dev/null <<'EOF'
server:
# DoT için port 853'ü dinle
interface: 0.0.0.0@853
# TLS sertifika dosyaları (Let's Encrypt veya kendi CA'nızdan)
tls-service-key: "/etc/ssl/private/dns-server.key"
tls-service-pem: "/etc/ssl/certs/dns-server.crt"
# DoT erişim kontrolü
access-control: 192.168.0.0/16 allow
EOF
Sertifika dosyaları hazır değilse bu bölümü şimdilik atlayıp yalnızca temel kurulumu tamamlayabilirsiniz.
Performans İzleme ve İstatistikler
Unbound’un yerleşik istatistik özelliği var. Bunu etkinleştirmek için:
sudo tee /etc/unbound/unbound.conf.d/stats.conf > /dev/null <<'EOF'
server:
statistics-interval: 0
extended-statistics: yes
statistics-cumulative: no
remote-control:
control-enable: yes
control-interface: 127.0.0.1
control-port: 8953
control-use-cert: yes
server-key-file: "/etc/unbound/unbound_server.key"
server-cert-file: "/etc/unbound/unbound_server.pem"
control-key-file: "/etc/unbound/unbound_control.key"
control-cert-file: "/etc/unbound/unbound_control.pem"
EOF
# Kontrol sertifikalarını oluştur
sudo unbound-control-setup
# Servisi yeniden başlat
sudo systemctl restart unbound
# İstatistikleri görüntüle
sudo unbound-control stats_noreset
unbound-control ile yapabileceğiniz bazı faydalı komutlar:
- sudo unbound-control status: Servis durumu ve temel bilgiler
- sudo unbound-control stats: Anlık istatistikler (cache hit/miss, sorgu sayıları)
- sudo unbound-control flush google.com: Belirli bir domain’i cache’den sil
- sudo unbound-control flush_zone sirket.local: Tüm zone’u cache’den temizle
- sudo unbound-control reload: Yapılandırmayı yeniden yükle (servisi durdurmadan)
- sudo unbound-control dump_cache: Mevcut cache içeriğini döktür
Güvenlik Duvarı Ayarları
Unbound’u bir DNS sunucusu olarak ağa açıyorsanız güvenlik duvarı kurallarını da ayarlamak gerekiyor:
# UFW kullanıyorsanız
sudo ufw allow 53/udp
sudo ufw allow 53/tcp
sudo ufw allow 853/tcp # DNS-over-TLS kullanıyorsanız
# iptables kullanıyorsanız
sudo iptables -A INPUT -p udp --dport 53 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 53 -j ACCEPT
# Kuralları kalıcı hale getir
sudo netfilter-persistent save
Yaygın Sorunlar ve Çözümleri
Servis başlamıyor, “Address already in use” hatası: 53 portunu başka bir servis kullanıyor demektir. Yukarıda anlatılan systemd-resolved adımlarını kontrol edin.
sudo ss -tulpn | grep :53
sudo lsof -i :53
DNSSEC doğrulaması SERVFAIL veriyor ama domain var: Root key güncel olmayabilir. sudo unbound-anchor -a /var/lib/unbound/root.key komutunu çalıştırın.
Dahili zone çalışmıyor: Yapılandırma sözdizimini sudo unbound-checkconf ile kontrol edin ve nokta (.) karakterlerine dikkat edin. Zone isimleri trailing dot ile bitmelidir: sirket.local.
Yüksek gecikme: Önbellekleme çalışmıyor olabilir. sudo unbound-control stats | grep cache çıktısında cache hit oranını kontrol edin. Düşük bir oran için rrset-cache-size ve msg-cache-size değerlerini artırın.
# Hızlı tanılama scripti
echo "=== Servis Durumu ===" && systemctl is-active unbound
echo "=== Port Kontrolü ===" && ss -tulpn | grep :53
echo "=== Temel Sorgu Testi ===" && dig @127.0.0.1 google.com | grep "Query time"
echo "=== DNSSEC Testi ===" && dig @127.0.0.1 +dnssec sigok.verteiltesysteme.net | grep -E "RRSIG|SERVFAIL|status"
echo "=== Cache Istatistikleri ===" && unbound-control stats_noreset | grep -E "cache.(hits|miss)"
Logrotate Yapılandırması
Log dosyasının şişmesini önlemek için logrotate ayarlayalım:
sudo tee /etc/logrotate.d/unbound > /dev/null <<'EOF'
/var/log/unbound/unbound.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
postrotate
/usr/sbin/unbound-control log_reopen
endscript
}
EOF
Sonuç
Unbound, doğru yapılandırıldığında ciddi bir altyapı katmanı oluşturuyor. Anlattığım adımları izleyerek kurduğunuzda elinizde şunlar var: DNSSEC doğrulaması yapan, önbellekleme ile gecikmeyi düşüren, erişim kontrolü ile dışarıya kapalı, dahili zone desteğiyle kurumsal ortama uygun bir recursive DNS resolver.
Production’a almadan önce şu kontrol listesini geçin:
unbound-checkconftemiz dönüyor mudig @127.0.0.1 google.combaşarılı yanıt veriyor mu- DNSSEC testi doğru çalışıyor mu
- Firewall kuralları doğru mu
access-controlyalnızca yerel ağa açık mı- Log rotasyon ayarı yapıldı mı
- Root key otomatik güncelleme tanımlandı mı
Ölçek büyüdükçe, birden fazla Unbound sunucusu arasında yük dağıtımı veya anycast yapılandırmaları gibi konulara girmek gerekebilir. Ama tek site, birkaç yüz kullanıcılı bir ortam için bu yapılandırma fazlasıyla yeterli ve uzun süre bakım gerektirmeden çalışır.
