Çift Yedekli Sunucu
DNS Değişikliği Alt Yapısı


Cloud Flare’den API Alabilmek?


Öncelikle bir cloudflare hesabınızın olması ve Alan adınıza ait Name Server adresleriniz CloudFlare’e ait Name Server adreslerine işaret etmelidir. Zaten DNS bölgeniz Cloud Flare üzerinde ise yapmanız gerekenler.


1-Sağ üst Profil Logosu > Profile’e tıklayınız.


2-Sol Menüden API Token bölümüne geliniz.


3-Create New Token tıklayınız.


4-Açılan sayfada Edit Zone DNS (use template) kullanınız.


5-Permissions altında yapacaklarınız;


Zone - DNS - Edit sırasıyla seçiniz.

6-Zone Resources altında yapacaklarınız;


Include - Specific Zone - Alan Adınızı Seçiniz

7-Client IP Address Filtering -> Burada tüm kontrol mekanizmamızın çalıştığı sunucumuza ait IP adresini giriş yapacağız.


IS İN - IP ADRESİ

8-Continue diyerek ilerleyiniz.


9-Sizlere bir API ve API yi test edebileceğiniz curl kodu verecektir.


Dış Ağ Sunucusunda Local Ağ’dan Gelen Ping’i Görme


1- DNS , A Kaydımızı değiştirecek aynı zamanda Ping kontrolü yapacak scriptimiz. Not: Local Ağ içerisinden gelen ping Nat’lı olarak gelmektedir. Bu sebepten dolayı script içerisinde direkt olarak Ping kontrolü değil Nat’lı Ping kontrolü yapılmaktadır.


sudo nano /root/failover.sh -> failover.sh dosyamızı oluşturalım.

2- Dosya içeriğimiz aşağıdaki gibi olacaktır.


#!/bin/bash
set -x
exec >> /var/log/failover.log 2>&1
echo "----- $(date) -----"

# Cloudflare API bilgileri
API_TOKEN="CloudFlare API Kodu Buraya Gelecek”
ZONE_NAME="AlanAdınız.com”
RECORD_NAME="AlanAdınız.com"
WWW_RECORD_NAME="www.AlanAdınız.com”
IP1=“Local Ağımızın Dış IP Adresi”
IP2=“Yedek Sunucumuzun IP Adresi”
CF_API="https://api.cloudflare.com/client/v4"
PING_LOG="/var/log/ip1_ping.log"

# NAT'lı ping kontrolü
LAST_PING_TS=$(grep 'ICMP echo request' "$PING_LOG" | grep "$IP1" | tail -n 1 | awk '{print $1" "$2}' | cut -d. -f1)

if [ -z "$LAST_PING_TS" ]; then
  echo "Ping logu boş. IP1 down sayılıyor."
  TARGET_IP=$IP2
  PROXY=false
else
  LAST_PING_EPOCH=$(date -d "$LAST_PING_TS" +%s)
  NOW_EPOCH=$(date +%s)
  DIFF=$((NOW_EPOCH - LAST_PING_EPOCH))

  if [ $DIFF -gt 180 ]; then
    echo "Ping 3 dakikadır yok. IP2'ye geçiliyor."
    TARGET_IP=$IP2
    PROXY=false
  else
    echo "Ping var. IP1 aktif."
    TARGET_IP=$IP1
    PROXY=true
  fi
fi

# jq kontrolü
command -v jq >/dev/null 2>&1 || { echo >&2 "jq yüklü değil. 'apt install jq' ile kur."; exit 1; }

# Zone ID al
ZONE_ID=$(curl -s -X GET "$CF_API/zones?name=$ZONE_NAME" \
     -H "Authorization: Bearer $API_TOKEN" \
     -H "Content-Type: application/json" | jq -r '.result[0].id')

# Ana kayıt için Record ID ve IP
RECORD_ID=$(curl -s -X GET "$CF_API/zones/$ZONE_ID/dns_records?type=A&name=$RECORD_NAME" \
     -H "Authorization: Bearer $API_TOKEN" \
     -H "Content-Type: application/json" | jq -r '.result[0].id')

CURRENT_IP=$(curl -s -X GET "$CF_API/zones/$ZONE_ID/dns_records/$RECORD_ID" \
     -H "Authorization: Bearer $API_TOKEN" \
     -H "Content-Type: application/json" | jq -r '.result.content')

# www kaydı için Record ID ve IP
WWW_RECORD_ID=$(curl -s -X GET "$CF_API/zones/$ZONE_ID/dns_records?type=A&name=$WWW_RECORD_NAME" \
     -H "Authorization: Bearer $API_TOKEN" \
     -H "Content-Type: application/json" | jq -r '.result[0].id')

WWW_CURRENT_IP=$(curl -s -X GET "$CF_API/zones/$ZONE_ID/dns_records/$WWW_RECORD_ID" \
     -H "Authorization: Bearer $API_TOKEN" \
     -H "Content-Type: application/json" | jq -r '.result.content')

# Ana kayıt güncellemesi
if [ "$CURRENT_IP" != "$TARGET_IP" ]; then
  curl -s -X PUT "$CF_API/zones/$ZONE_ID/dns_records/$RECORD_ID" \
       -H "Authorization: Bearer $API_TOKEN" \
       -H "Content-Type: application/json" \
       --data "{\"type\":\"A\",\"name\":\"$RECORD_NAME\",\"content\":\"$TARGET_IP\",\"ttl\":120,\"proxied\":$PROXY}"
  echo "Ana DNS kaydı $TARGET_IP olarak güncellendi. Proxy durumu: $PROXY"
fi

# www kaydı güncellemesi
if [ "$WWW_CURRENT_IP" != "$TARGET_IP" ]; then
  curl -s -X PUT "$CF_API/zones/$ZONE_ID/dns_records/$WWW_RECORD_ID" \
       -H "Authorization: Bearer $API_TOKEN" \
       -H "Content-Type: application/json" \
       --data "{\"type\":\"A\",\"name\":\"$WWW_RECORD_NAME\",\"content\":\"$TARGET_IP\",\"ttl\":120,\"proxied\":$PROXY}"
  echo "www DNS kaydı $TARGET_IP olarak güncellendi. Proxy durumu: $PROXY"
fi

2.1 - Komut Dosyası içerisinde en yukarıda belirtilen IP , API , ve Alan Adı bölümlerini doldurunuz.


3- Komut Dosyamızın Devamlı Çalışması İçin Servis Oluşturalım.


sudo nano /root/failover-loop.sh -> Root içerisinde oluşturalım.

4- Devamlı Çalıştıracak Kodu Yapıştıralım.


#!/bin/bash
while true; do
  /bin/bash /root/failover.sh #-> failover.sh dosyamızı çağıracak
  sleep 10 #-> 10 Saniyede bir komut tekrarlanacak
done

5- Dosya Yetkisi Verelim.


chmod +x /root/failover-loop.sh

6- Sistem kapansa bile çalışacak olan servisimizi oluşturalım.


sudo nano /etc/systemd/system/failover.service

7- Servis kodunu yapıştıralım. CTRL + O (Kaydet) , CTRL + X (Çıkış)


[Unit]
Description=Failover DNS kontrol servisi
After=network.target

[Service]
Type=simple
ExecStart=/bin/bash /root/failover-loop.sh
Restart=always
RestartSec=5
StandardOutput=append:/var/log/failover.log
StandardError=append:/var/log/failover.log

[Install]
WantedBy=multi-user.target

8- Servisi etkinleştirelim işlem tamamlanmıştır.


sudo systemctl daemon-reexec
sudo systemctl daemon-reload
sudo systemctl enable failover.service
sudo systemctl start failover.service

9- Servis durum kontrolü > systemctl status failover.service


10- Servis LOG Kontrolü > tail -f /var/log/failover.log


E Peki Bu Kadar Log Tutuyoruz Bu Dosya Şişmezmi?


Ping kontrolü yapan sunucumuz için aynı zamanda tuttuğu logların boyutu 10mb aştıktan sonra otomatik olarak temizleyecek olan aşağıdaki işlemleri yapacağız.


1- Komut dosyası oluşturalım.


sudo nano /root/log-cleaner.sh

2- Komut dosyasına aşağıdaki kodu yazalım. CTRL + O (Kaydet) , CTRL + X (Çıkış)


#!/bin/bash
LOG_FILE="/var/log/failover.log"
MAX_SIZE_MB=10

while true; do
  if [ -f "$LOG_FILE" ]; then
    SIZE_MB=$(du -m "$LOG_FILE" | cut -f1)
    if [ "$SIZE_MB" -ge "$MAX_SIZE_MB" ]; then
      echo "[$(date)] Log boyutu $SIZE_MB MB. Temizleniyor..." >> "$LOG_FILE"
      > "$LOG_FILE"
    fi
  fi
  sleep 10
done

3- Komut dosyamıza yetki verelim.


chmod +x /root/log-cleaner.sh

4- Sistem servisimizi oluşturalım.


sudo nano /etc/systemd/system/log-cleaner.service

5- Sistem servisi kodunu yapıştıralım.


[Unit]
Description=Failover log temizleyici servis
After=network.target

[Service]
Type=simple
ExecStart=/bin/bash /root/log-cleaner.sh
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

6- Servisimizi etkinleştirelim.


sudo systemctl daemon-reexec
sudo systemctl daemon-reload
sudo systemctl enable log-cleaner.service
sudo systemctl start log-cleaner.service

7- Servis durumunu kontrol etmek için -> systemctl status log-cleaner.service İşlemimiz tamamlandı.


Local Ağ Sunucusundan Dış Ağ Ping Gönderme


1- root içerisinde ip1-ping.sh isminde bir dosya oluşturalım.


sudo nano /root/ip1-ping.sh

2- Dosya içeriğinde do-while döngüsü ile devamlı ping gönderecek olan kodu yapıştıralım.


#!/bin/bash
while true; do
  ping -c 1 45.152.243.246 > /dev/null
  sleep 10
done

2.1- CTRL + O (Kaydet) , CTRL + X ile çıkış yapalım.


3- Dosyamıza tüm yetkileri verelim.


chmod +x /root/ip1-ping.sh

4- Sunucu kapansa bile bu sistemin çalışmasını sağlamak için systemd servisi oluşturalım.


sudo nano /etc/systemd/system/ip1-ping.service

5- Servis dosyasının içeriği aşağıdaki gibi olmalıdır.


[Unit]
Description=IP1 ping gönderici servis
After=network.target

[Service]
Type=simple
ExecStart=/bin/bash /root/ip1-ping.sh
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

5.1- CTRL + O (Kaydet) , CTRL + X ile çıkış yapalım.


6- Servisimizi etkinleştirelim.


sudo systemctl daemon-reexec
sudo systemctl daemon-reload
sudo systemctl enable ip1-ping.service
sudo systemctl start ip1-ping.service

7- Servisimiz hazırdır sunucu kapanıp geri açılsa bile servis etkinleşecektir.


Kısaca Özet Yaptığımız Proje Nedir?


Yaptığımız proje evimizde bulunan bir web sunucusu bir internet kesintisi veya elektrik kesintisi yaşadığında uzak web sunucumuzda bulunan web sayfamız devreye girecektir.


Local Sunumuz A olsun ve Uzak Sunucumuzda B olsun.


2.Uzak Sunucumuz Olan Kontrol Sunucusu ise C olsun.


A sunucumuz Yani (Local) devamlı açık olduğunu bildiren bir ping gönderiyor. -> C sunucumuz kontrol sunucusu bu ping isteğini ise devamlı yakalıyor ve A sunucusunun aktif olduğunu görüp CloudFlare tarafında DNS değişikliğine gitmiyor. Ne zaman A sunucumuzdan ping kesilir ise C kontrol sunucumuz durumu algılayıp CloudFlare tarafında yedek B sunucusuna geçiş için DNS değişikliğini sağlıyor. A sunucusu Local aktif hale geldiğinde tekrardan DNS değişikliği A sunucusu olacak şekilde değişikliği sağlıyor. Bu sistem bir sayfaya gelen yükü dağıtma değildir, sayfaya ulaşılamaması durumunda yedek sunucuya geçiş yapılarak devamlılığın sağlanabilmesidir.