PowerDNS ile Yük Dengeleme ve Yedeklilik: Master-Slave DNS Replikasyonu Kurulumu
DNS altyapısı çökerse ne olur? Web siteniz, e-postanız, iç ağ servislerinizin tamamı birkaç dakika içinde erişilemez hale gelir. Tek bir DNS sunucusuna bağımlı olmak, özellikle üretim ortamlarında kabul edilemez bir risk. İşte bu yüzden PowerDNS ile master-slave replikasyonu kurarak hem yük dengeleme hem de yedeklilik sağlamak, sağlam bir altyapının olmazsa olmazlarından biri.
Bu yazıda gerçek bir senaryo üzerinden gideceğiz: İki sunuculu bir PowerDNS kurulumu yapacağız, master sunucuda yapılan değişiklikler otomatik olarak slave’e aktarılacak ve herhangi bir sunucu çökerse diğeri devreye girecek. Hem küçük ekipler hem de kurumsal yapılar için uygulanabilir bir mimari.
Ortam ve Ön Gereksinimler
Yazı boyunca şu ortamı kullanacağız:
- Master DNS (ns1): 192.168.1.10 – Ubuntu 22.04 LTS
- Slave DNS (ns2): 192.168.1.20 – Ubuntu 22.04 LTS
- PowerDNS Authoritative Server: 4.7.x
- Backend: MySQL (her iki sunucuda ayrı veritabanı)
Başlamadan önce her iki sunucuda da şu paketleri yükleyelim:
# Her iki sunucuda çalıştırın
apt update && apt upgrade -y
apt install -y pdns-server pdns-backend-mysql mysql-server
Güvenlik duvarı kurallarını da baştan ayarlayalım. DNS standart olarak 53 numaralı portu kullanır, ama PowerDNS’in API’si için 8081’e de ihtiyacımız olacak:
# Her iki sunucuda
ufw allow 53/tcp
ufw allow 53/udp
ufw allow 8081/tcp # PowerDNS API
# ns1 üzerinde ns2'nin AXFR isteklerine izin ver
ufw allow from 192.168.1.20 to any port 53
Master Sunucuda MySQL Kurulumu
ns1 sunucusunda önce veritabanını hazırlayalım. PowerDNS, zone verilerini MySQL’de tutacak:
# ns1 üzerinde
mysql -u root -p <<EOF
CREATE DATABASE powerdns CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'pdns'@'localhost' IDENTIFIED BY 'GucluBirSifre123!';
GRANT ALL PRIVILEGES ON powerdns.* TO 'pdns'@'localhost';
FLUSH PRIVILEGES;
EOF
Şimdi PowerDNS’in beklediği tablo şemasını oluşturalım. Bu şemayı PowerDNS’in kendi dokümantasyonundan alıyoruz:
# ns1 üzerinde
mysql -u pdns -p powerdns < /usr/share/doc/pdns-backend-mysql/schema.mysql.sql
# Tablo oluşturuldu mu kontrol et
mysql -u pdns -p powerdns -e "SHOW TABLES;"
Çıktıda comments, cryptokeys, domainmetadata, domains, records, supermasters, tsigkeys tablolarını görmeniz gerekiyor. Eğer şema dosyası farklı bir yerdeyse şunu deneyin:
find / -name "schema.mysql.sql" 2>/dev/null
Master PowerDNS Konfigürasyonu
ns1 üzerinde /etc/powerdns/pdns.conf dosyasını düzenleyelim:
# ns1 - /etc/powerdns/pdns.conf
cat > /etc/powerdns/pdns.conf <<'EOF'
# Temel ayarlar
setuid=pdns
setgid=pdns
# Dinleme adresi - sadece kendi IP'si ve localhost
local-address=0.0.0.0
local-port=53
# Backend
launch=gmysql
gmysql-host=127.0.0.1
gmysql-port=3306
gmysql-dbname=powerdns
gmysql-user=pdns
gmysql-password=GucluBirSifre123!
gmysql-dnssec=yes
# Master modu aktif
master=yes
slave=no
# API ayarları (web arayüzü ve otomasyon için)
api=yes
api-key=cokGizliApiAnahtari456
webserver=yes
webserver-address=0.0.0.0
webserver-port=8081
webserver-allow-from=192.168.1.0/24
# AXFR için slave sunucunun IP'sine izin ver
allow-axfr-ips=192.168.1.20/32
# Loglama
loglevel=5
log-dns-queries=yes
# Notify ayarları - slave'lere değişiklik bildirimi
also-notify=192.168.1.20
EOF
Servisi başlatalım:
systemctl enable pdns
systemctl start pdns
systemctl status pdns
Slave Sunucuda MySQL ve PowerDNS Kurulumu
ns2 üzerinde de benzer şekilde ilerleriz, ama bu sefer slave konfigürasyonu yapıyoruz. Önemli bir nokta: slave’in kendi yerel veritabanı var, master ile paylaşmıyor. Zone transferi üzerinden senkronize olacak:
# ns2 üzerinde
mysql -u root -p <<EOF
CREATE DATABASE powerdns CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'pdns'@'localhost' IDENTIFIED BY 'SlaveGucluSifre789!';
GRANT ALL PRIVILEGES ON powerdns.* TO 'pdns'@'localhost';
FLUSH PRIVILEGES;
EOF
mysql -u pdns -p powerdns < /usr/share/doc/pdns-backend-mysql/schema.mysql.sql
ns2 için /etc/powerdns/pdns.conf:
# ns2 - /etc/powerdns/pdns.conf
cat > /etc/powerdns/pdns.conf <<'EOF'
setuid=pdns
setgid=pdns
local-address=0.0.0.0
local-port=53
launch=gmysql
gmysql-host=127.0.0.1
gmysql-port=3306
gmysql-dbname=powerdns
gmysql-user=pdns
gmysql-password=SlaveGucluSifre789!
gmysql-dnssec=yes
# Slave modu
master=no
slave=yes
# Slave ne sıklıkla zone kontrolü yapsın (saniye)
slave-cycle-interval=60
# API
api=yes
api-key=cokGizliApiAnahtari456
webserver=yes
webserver-address=0.0.0.0
webserver-port=8081
webserver-allow-from=192.168.1.0/24
loglevel=5
EOF
systemctl enable pdns
systemctl start pdns
Supermaster Kaydı ve İlk Zone Oluşturma
PowerDNS’in master-slave mekanizmasının güzel yanı şu: Master’da bir zone oluşturduğunuzda ve slave’i “supermaster” olarak tanımladığınızda, slave otomatik olarak zone’u öğrenir ve transfer eder.
ns2’deki MySQL’e master’ı supermaster olarak tanımlayalım:
# ns2 üzerinde
mysql -u pdns -p powerdns <<EOF
INSERT INTO supermasters (ip, nameserver, account)
VALUES ('192.168.1.10', 'ns1.sirketim.com', 'admin');
EOF
Şimdi ns1 üzerinde ilk zone’umuzu oluşturalım. Bunun için PowerDNS API’sini kullanabiliriz:
# ns1 üzerinde - Zone oluştur
curl -s -X POST http://localhost:8081/api/v1/servers/localhost/zones
-H "X-API-Key: cokGizliApiAnahtari456"
-H "Content-Type: application/json"
-d '{
"name": "sirketim.com.",
"kind": "Native",
"nameservers": ["ns1.sirketim.com.", "ns2.sirketim.com."]
}'
Ama bekleyin, burada “Native” yerine “Master” kullanmamız gerekiyor çünkü replikasyon istiyoruz:
# Zone türünü Master olarak güncelle
curl -s -X PUT http://localhost:8081/api/v1/servers/localhost/zones/sirketim.com.
-H "X-API-Key: cokGizliApiAnahtari456"
-H "Content-Type: application/json"
-d '{"kind": "Master"}'
DNS Kayıtlarını Ekleme
Zone hazır, şimdi gerçek kayıtları ekleyelim. Hem API hem de pdnsutil aracını kullanabiliriz:
# ns1 üzerinde - pdnsutil ile kayıt ekleme
pdnsutil add-record sirketim.com @ SOA "ns1.sirketim.com. hostmaster.sirketim.com. 2024010101 3600 900 604800 300"
pdnsutil add-record sirketim.com @ NS "ns1.sirketim.com."
pdnsutil add-record sirketim.com @ NS "ns2.sirketim.com."
pdnsutil add-record sirketim.com ns1 A "192.168.1.10"
pdnsutil add-record sirketim.com ns2 A "192.168.1.20"
pdnsutil add-record sirketim.com @ A "203.0.113.50"
pdnsutil add-record sirketim.com www A "203.0.113.50"
pdnsutil add-record sirketim.com mail MX "10 mail.sirketim.com."
pdnsutil add-record sirketim.com mail A "203.0.113.51"
# Zone'u doğrula
pdnsutil check-zone sirketim.com
Eğer API üzerinden toplu kayıt eklemek isterseniz:
curl -s -X PATCH http://localhost:8081/api/v1/servers/localhost/zones/sirketim.com.
-H "X-API-Key: cokGizliApiAnahtari456"
-H "Content-Type: application/json"
-d '{
"rrsets": [
{
"name": "blog.sirketim.com.",
"type": "A",
"ttl": 3600,
"changetype": "REPLACE",
"records": [{"content": "203.0.113.52", "disabled": false}]
}
]
}'
Zone Transfer Doğrulama
Zone’u oluşturduktan sonra slave’in bunu alıp almadığını kontrol edelim:
# ns1 üzerinde - slave'e notify gönder
pdns_control notify sirketim.com
# ns2 üzerinde - zone'un gelip gelmediğini kontrol et
pdnsutil list-all-zones
# Zone içeriğini sorgula
dig @192.168.1.20 sirketim.com SOA
dig @192.168.1.20 sirketim.com NS
dig @192.168.1.20 www.sirketim.com A
Eğer transfer gerçekleşmediyse ns2’nin log’larına bakın:
# ns2 üzerinde
journalctl -u pdns -f
tail -f /var/log/syslog | grep pdns
Manuel AXFR testi yapabilirsiniz:
# Herhangi bir makineden
dig @192.168.1.10 sirketim.com AXFR
Eğer “Transfer failed” hatası alırsanız, ns1’deki allow-axfr-ips ayarına ns2’nin IP’sinin eklendiğinden emin olun.
Slave Zone Durumunu İzleme
PowerDNS’in içinde zone’ların transfer durumunu izleyebileceğiniz yararlı sorgular var:
# ns2'de MySQL'e bağlanıp slave zone bilgilerini gör
mysql -u pdns -p powerdns <<EOF
SELECT
d.name as zone_adi,
d.type as tur,
d.last_check as son_kontrol,
d.notified_serial as bildirilen_seri,
FROM_UNIXTIME(d.last_check) as son_kontrol_tarihi
FROM domains d
WHERE d.type = 'SLAVE';
EOF
PowerDNS kontrolcüsü ile de durum sorgusu yapabilirsiniz:
# ns1 üzerinde
pdns_control list
pdns_control show *
# Belirli bir zone'un slave'lere iletilip iletilmediği
pdns_control notify-host sirketim.com 192.168.1.20
TSIG ile Güvenli Zone Transfer
Üretim ortamında AXFR işlemlerini açık yapmak güvenlik riski oluşturur. TSIG (Transaction Signature) kullanarak transferleri şifreleyelim:
# ns1 üzerinde - TSIG anahtarı oluştur
pdnsutil generate-tsig-key transfer-key hmac-sha256
# Oluşturulan anahtarı görüntüle
pdnsutil list-tsig-keys
# Zone'a TSIG anahtarını bağla
pdnsutil set-meta sirketim.com TSIG-ALLOW-AXFR transfer-key
pdnsutil set-meta sirketim.com NOTIFY-DNSKEY transfer-key
ns2 üzerinde aynı anahtarı tanımlamamız gerekiyor. ns1’den anahtarın değerini alıp ns2’ye aktarın:
# ns1'de anahtarı MySQL'den çek
mysql -u pdns -p powerdns -e "SELECT name, algorithm, secret FROM tsigkeys WHERE name='transfer-key';"
# ns2'de aynı anahtarı ekle
mysql -u pdns -p powerdns <<EOF
INSERT INTO tsigkeys (name, algorithm, secret)
VALUES ('transfer-key', 'hmac-sha256', 'BURAYA_NS1DEN_ALINAN_SECRET_DEGERI');
EOF
# ns2'de zone'a TSIG bağla
pdnsutil set-meta sirketim.com AXFR-MASTER-TSIG transfer-key
Gerçek Dünya Senaryosu: Otomatik Failover
Peki bir sunucu çökerse ne olur? ns2 hâlâ çalışıyor olacak ve elindeki son zone kopyasını sunmaya devam edecek. Ama ns1 tekrar ayağa kalktığında replikasyonun devam etmesi gerekiyor.
Bunun için basit bir monitoring scripti yazalım:
# /usr/local/bin/dns-health-check.sh
#!/bin/bash
MASTER_IP="192.168.1.10"
SLAVE_IP="192.168.1.20"
TEST_ZONE="sirketim.com"
ALERT_EMAIL="[email protected]"
LOG_FILE="/var/log/dns-health.log"
check_dns() {
local server=$1
local result
result=$(dig @$server $TEST_ZONE SOA +short +time=2 2>/dev/null)
if [ -z "$result" ]; then
return 1
fi
return 0
}
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
if ! check_dns $MASTER_IP; then
echo "[$timestamp] UYARI: Master DNS ($MASTER_IP) yanit vermiyor!" >> $LOG_FILE
echo "Master DNS sunucusu yanit vermiyor. Slave $SLAVE_IP devrede." |
mail -s "DNS MASTER ARIZA" $ALERT_EMAIL
else
echo "[$timestamp] Master DNS saglikli" >> $LOG_FILE
fi
if ! check_dns $SLAVE_IP; then
echo "[$timestamp] UYARI: Slave DNS ($SLAVE_IP) yanit vermiyor!" >> $LOG_FILE
echo "Slave DNS sunucusu yanit vermiyor." |
mail -s "DNS SLAVE ARIZA" $ALERT_EMAIL
else
echo "[$timestamp] Slave DNS saglikli" >> $LOG_FILE
fi
# SOA seri numaralarini karsilastir
master_serial=$(dig @$MASTER_IP $TEST_ZONE SOA +short | awk '{print $3}')
slave_serial=$(dig @$SLAVE_IP $TEST_ZONE SOA +short | awk '{print $3}')
if [ "$master_serial" != "$slave_serial" ]; then
echo "[$timestamp] UYARI: Serial uyusmazligi! Master: $master_serial, Slave: $slave_serial" >> $LOG_FILE
fi
Bu scripti cron’a ekleyelim:
chmod +x /usr/local/bin/dns-health-check.sh
crontab -e
# Şu satırı ekle:
# */5 * * * * /usr/local/bin/dns-health-check.sh
Yük Dengeleme İçin Round Robin DNS
PowerDNS ile basit bir yük dengeleme yapmak için round-robin A kayıtları kullanabilirsiniz. Örneğin web sunucularınız 3 farklı IP’ye sahipse:
# ns1 üzerinde
pdnsutil add-record sirketim.com www A "203.0.113.50"
pdnsutil add-record sirketim.com www A "203.0.113.51"
pdnsutil add-record sirketim.com www A "203.0.113.52"
# Zone'u yenile
pdnsutil increase-serial sirketim.com
# Verify - her sorguda farklı IP gelmeli
dig @192.168.1.10 www.sirketim.com A
dig @192.168.1.10 www.sirketim.com A
dig @192.168.1.10 www.sirketim.com A
PowerDNS varsayılan olarak round-robin rotasyonu yapar. pdns.conf‘a şunu ekleyerek bunu kontrol edebilirsiniz:
# /etc/powerdns/pdns.conf'a ekle
# Query yanıtlarında kayıt sıralamasını karıştır
shuffle=yes
Serial Yönetimi ve Zone Güncelleme
SOA serial numarası, slave’lerin “yeni bir şey var mı?” diye kontrol ettiği değer. Her zone değişikliğinde artması gerekiyor. pdnsutil bunu otomatik yapıyor ama elle de yönetebilirsiniz:
# Mevcut serial'i gör
pdnsutil show-zone sirketim.com | grep Serial
# Serial'i artır (slave'leri tetikler)
pdnsutil increase-serial sirketim.com
# Tüm slave'lere notify gönder
pdns_control notify sirketim.com
# Slave'in aldığı serial'i kontrol et
dig @192.168.1.20 sirketim.com SOA
Üretimde genellikle tarih tabanlı serial kullanılır (YYYYMMDDNN formatı). 2024010101 = 2024 yılı, 1 Ocak, 1. değişiklik. Eğer günde birden fazla değişiklik yaparsanız son iki haneyi artırmanız yeterli.
Performans Ayarları
Yoğun trafik altında DNS sunucunuzun performansını artırmak için birkaç ayar:
# /etc/powerdns/pdns.conf'a ekle (her iki sunucuda)
# Thread sayısı - CPU çekirdek sayısına göre ayarla
receiver-threads=4
distributor-threads=4
# Önbellek ayarları
cache-ttl=60
query-cache-ttl=20
negquery-cache-ttl=60
# Max eş zamanlı sorgu
max-queue-length=5000
max-tcp-connections=1000
# Paket tamponu
socket-buffer-size=1048576
Ayarlar sonrası servisi yeniden başlatın:
systemctl restart pdns
# Performans istatistiklerini gör
pdns_control show *
curl -s http://localhost:8081/api/v1/servers/localhost/statistics
-H "X-API-Key: cokGizliApiAnahtari456" | python3 -m json.tool
Sık Karşılaşılan Sorunlar
Zone transfer çalışmıyor: allow-axfr-ips kontrolü yapın, güvenlik duvarı 53 portunu açık mı bakın, TSIG kullanıyorsanız anahtarların eşleştiğini doğrulayın.
Slave zone’u almıyor: ns2’deki supermasters tablosunda ns1’in IP’si kayıtlı mı kontrol edin. slave=yes ve master=no ayarlarının doğru olduğuna emin olun.
SOA serial güncellenmedi: pdnsutil increase-serial komutunu çalıştırın ve ardından pdns_control notify ile slave’leri bilgilendirin.
API erişim hatası: webserver-allow-from ayarına istek yapan IP’nin dahil edildiğini kontrol edin.
Sonuç
PowerDNS ile master-slave replikasyonu kurmanın teknik kısımlarını adım adım gördük. Tek bir noktadan yönetim (master), otomatik senkronizasyon (notify + AXFR), TSIG ile güvenli transfer ve basit monitoring ile sağlam bir DNS altyapısı elde ettiniz.
Bu yapıyı daha da genişletmek isterseniz ikinci bir slave eklemek sadece aynı adımları tekrarlamaktan ibaret. ns1’deki also-notify ve allow-axfr-ips direktiflerine yeni slave’in IP’sini ekleyin, yeni sunucuda supermasters kaydını oluşturun, konfigürasyonu yapın ve hazır.
Genel tavsiyem: Üretim ortamına geçmeden önce bu yapıyı bir test ortamında en az bir hafta çalıştırın. Kasıtlı olarak master’ı durdurun ve slave’in doğru yanıt verdiğini gözlemleyin. Master’ı tekrar başlatın ve replikasyonun devam ettiğini doğrulayın. DNS altyapısı, “kuruldu ve unutuldu” değil sürekli izlenen bir bileşen olmalı.
