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ı.

Bir yanıt yazın

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