Rsync ile E-posta Bildirimi: Hata Uyarı Sistemi Nasıl Kurulur

Yedekleme işleri sessiz sedasız çalışırken her şey güzel görünür. Asıl sorun, bir şeyler ters gittiğinde haberdar olamamaktır. Rsync scriptiniz gece yarısı hata verdi, disk doldu, hedef sunucuya bağlanılamadı — ve siz sabah gelip her şeyin yolunda olduğunu sanıyorsunuz. İşte bu yazıda tam da bu senaryoyu çözüyoruz: rsync ile entegre, akıllı bir e-posta bildirim sistemi kuruyoruz.

Neden E-posta Bildirimi Şart?

Cron job olarak çalışan rsync scriptleri genellikle gözden kaçar. Log dosyası var mı? Belki. Ama o log dosyasını her sabah kontrol eden var mı? Büyük ihtimalle hayır. Monitoring sistemleri bu işi çözüyor elbette, ama her ortamda Nagios, Zabbix veya Prometheus kurmak mümkün olmayabiliyor. Basit, güvenilir ve kurulumu beş dakika süren bir çözüme ihtiyaç var.

E-posta bildirim sistemi üç temel senaryoyu kapsamalı:

  • Başarısız yedeklemeler: Rsync sıfır dışı bir exit code döndürdüğünde
  • Kısmi başarılar: Yedekleme tamamlandı ama bazı dosyalar atlandı
  • Başarılı yedeklemeler: İsteğe bağlı olarak, her şey yolundaysa da haber ver

Biz burada hepsini ele alacağız ve üzerine disk doluluk kontrolü, yedekleme boyutu anomali tespiti gibi ekstralar da koyacağız.

Temel Araçlar ve Gereksinimler

Başlamadan önce sistemde nelerin kurulu olması gerektiğine bakalım.

Mail gönderimi için seçenekler:

  • mailx / mail: En basit yöntem, sistemde genellikle hazır gelir
  • sendmail: Klasik MTA, yapılandırması karmaşık olabilir
  • msmtp: Harici SMTP sunucusu için hafif ve kolay yapılandırılır
  • ssmtp: Eski ama hala çalışan basit SMTP relay

Kurumsal ortamlarda genellikle dahili bir SMTP relay bulunur. Ev veya küçük ortamlarda Gmail SMTP veya benzeri bir servis kullanılır. Biz her iki senaryoyu da göstereceğiz.

msmtp Kurulumu ve Yapılandırması

# Ubuntu/Debian
sudo apt-get install msmtp msmtp-mta mailutils

# CentOS/RHEL/Rocky Linux
sudo dnf install msmtp mailx

Gmail SMTP için yapılandırma dosyası oluşturalım:

cat > /etc/msmtprc << 'EOF'
# Varsayılan değerler
defaults
auth           on
tls            on
tls_trust_file /etc/ssl/certs/ca-certificates.crt
logfile        /var/log/msmtp.log

# Gmail hesabı
account        gmail
host           smtp.gmail.com
port           587
from           [email protected]
user           [email protected]
password       BURAYA_UYGULAMA_SIFRESI

# Varsayılan hesap
account default : gmail
EOF

chmod 600 /etc/msmtprc

Gmail kullanıyorsanız hesap ayarlarından “Uygulama Şifresi” oluşturmanız gerekiyor. Normal hesap şifrenizi buraya yazmayın.

Test edelim:

echo "Test mesajı" | mail -s "Msmtp Test" [email protected]

Temel Rsync Bildirim Scripti

Önce işlevsel ama basit bir script yazalım, sonra üzerine katman katman özellik ekleyelim.

#!/bin/bash
# /usr/local/bin/rsync-backup.sh
# Temel rsync yedekleme scripti e-posta bildirimi ile

# --- Yapılandırma ---
KAYNAK="/var/www /home /etc"
HEDEF="/mnt/backup/gunluk"
UZAK_HEDEF="[email protected]:/backup/sunucu1"
LOG_DOSYASI="/var/log/rsync-backup.log"
HATA_LOG="/var/log/rsync-backup-error.log"
BILDIRIM_EMAIL="[email protected]"
SUNUCU_ADI=$(hostname -f)
TARIH=$(date '+%Y-%m-%d %H:%M:%S')
TARIH_KISA=$(date '+%Y%m%d_%H%M%S')

# --- Rsync Parametreleri ---
RSYNC_OPTS="-avz --delete --stats --human-readable 
            --exclude='*.tmp' 
            --exclude='*.log' 
            --exclude='/proc/*' 
            --exclude='/sys/*' 
            --log-file=${LOG_DOSYASI}"

# --- Fonksiyonlar ---
email_gonder() {
    local KONU="$1"
    local MESAJ="$2"
    echo -e "$MESAJ" | mail -s "$KONU" "$BILDIRIM_EMAIL"
}

# --- Yedekleme Başlıyor ---
echo "[$TARIH] Yedekleme başladı" >> "$LOG_DOSYASI"
BASLANGIC_ZAMANI=$(date +%s)

# Rsync çalıştır, hata çıktısını ayır
rsync $RSYNC_OPTS "$KAYNAK" "$UZAK_HEDEF" 2>"$HATA_LOG"
EXIT_CODE=$?

BITIS_ZAMANI=$(date +%s)
SURE=$((BITIS_ZAMANI - BASLANGIC_ZAMANI))

# --- Sonucu Değerlendir ---
if [ $EXIT_CODE -eq 0 ]; then
    echo "[$TARIH] Yedekleme başarıyla tamamlandı. Süre: ${SURE}s" >> "$LOG_DOSYASI"
    # Başarı bildirimi (isteğe bağlı, yoğun ortamlarda kapatılabilir)
    email_gonder 
        "[BASARILI] $SUNUCU_ADI Yedekleme - $TARIH" 
        "Yedekleme başarıyla tamamlandı.nnSunucu: $SUNUCU_ADInTarih: $TARIHnSüre: ${SURE} saniyenKaynak: $KAYNAKnHedef: $UZAK_HEDEF"
else
    HATA_MESAJI=$(cat "$HATA_LOG")
    echo "[$TARIH] HATA! Exit code: $EXIT_CODE" >> "$LOG_DOSYASI"
    email_gonder 
        "[HATA] $SUNUCU_ADI Yedekleme Başarısız - $TARIH" 
        "HATA: Yedekleme başarısız oldu!nnSunucu: $SUNUCU_ADInTarih: $TARIHnExit Code: $EXIT_CODEnKaynak: $KAYNAKnHedef: $UZAK_HEDEFnnHata Detayı:n$HATA_MESAJI"
fi

Bu script çalışıyor ama henüz kaba. Şimdi gerçek dünyada işe yarayacak şekilde geliştirelim.

Rsync Exit Code’larını Anlamak

Rsync farklı hata durumlarında farklı exit code’lar döndürür. Bu kodları yorumlamak, anlamlı hata mesajları göndermenizi sağlar.

rsync_hata_acikla() {
    local KOD=$1
    case $KOD in
        0)  echo "Başarılı" ;;
        1)  echo "Syntax hatası veya kullanım hatası" ;;
        2)  echo "Protokol uyumsuzluğu" ;;
        3)  echo "Kaynak veya hedef dosya seçim hatası" ;;
        4)  echo "İstenen aksiyon desteklenmiyor" ;;
        5)  echo "Başlatma hatası" ;;
        6)  echo "Log yazma hatası" ;;
        10) echo "Hata - Soket I/O hatası" ;;
        11) echo "Hata - Dosya I/O hatası" ;;
        12) echo "Hata - Rsync protokol veri akış hatası" ;;
        13) echo "Hata - Teşhis kodu için program hatası" ;;
        14) echo "Hata - IPC kodu hatası" ;;
        20) echo "Sinyal alındı, işlem sonlandırıldı" ;;
        21) echo "Waitpid() çağrısında hata" ;;
        22) echo "Bellek tahsis hatası" ;;
        23) echo "Kısmi transfer - bazı dosyalar aktarılamadı" ;;
        24) echo "Kısmi transfer - bazı kaynak dosyalar kayboldu" ;;
        25) echo "Silme limiti aşıldı" ;;
        30) echo "Timeout - veri gönderme/alma zaman aşımı" ;;
        35) echo "Timeout - bağlantı zaman aşımı" ;;
        255) echo "SSH bağlantı hatası" ;;
        *)  echo "Bilinmeyen hata kodu: $KOD" ;;
    esac
}

Exit code 23 özellikle dikkat etmeniz gereken bir durum. Yedekleme tamamlandı görünüyor ama bazı dosyalar aktarılamadı. İzinler, kilitli dosyalar, bozuk filesystem gibi durumlarda oluşur.

Gelişmiş Bildirim Sistemi

Şimdi production ortamına uygun, kapsamlı bir script yazalım. Bu script disk kontrolü, yedek boyut anomali tespiti ve HTML e-posta desteği içeriyor.

#!/bin/bash
# /usr/local/bin/rsync-smart-backup.sh
# Gelişmiş rsync yedekleme ve bildirim sistemi

set -euo pipefail

# ============================================
# YAPILANDIRMA
# ============================================
SUNUCU_ADI=$(hostname -f)
KAYNAK_DIZINLER=("/var/www/html" "/home" "/etc" "/opt/uygulama")
UZAK_HEDEF="[email protected]:/backup/${SUNUCU_ADI}"
SSH_KEY="/root/.ssh/backup_rsa"
SSH_PORT="22"

# Log ayarları
LOG_DIR="/var/log/rsync-backup"
LOG_DOSYASI="${LOG_DIR}/backup-$(date '+%Y%m%d').log"
HATA_LOG="${LOG_DIR}/error-$(date '+%Y%m%d').log"
ISTATISTIK_LOG="${LOG_DIR}/stats-$(date '+%Y%m%d_%H%M%S').log"

# E-posta ayarları
BILDIRIM_EMAIL="[email protected]"
BILDIRIM_EMAIL_CC="[email protected]"
GONDEREN="[email protected]"
HATA_DURUMUNDA_BILDIR=true
BASARI_DURUMUNDA_BILDIR=false   # Çok fazla mail gelmesini önler
KISMI_HATA_BILDIR=true

# Eşik değerleri
MIN_YEDEK_BOYUTU_MB=100         # Yedek bu değerden küçükse uyar
DISK_DOLU_ESIK=85               # Disk doluluk yüzdesi eşiği
SURE_ESIK_DAKIKA=120            # Bu süreden uzun sürerse uyar
ONCEKI_BOYUT_SAPMA_YUZDESI=30   # Önceki yedeğe göre boyut farkı eşiği

# Durum dosyası (önceki yedek boyutunu saklar)
DURUM_DOSYASI="/var/lib/rsync-backup/son-durum.dat"

# ============================================
# FONKSIYONLAR
# ============================================

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_DOSYASI"
}

hata_log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] HATA: $1" | tee -a "$LOG_DOSYASI" "$HATA_LOG"
}

dizin_hazirla() {
    mkdir -p "$LOG_DIR"
    mkdir -p "$(dirname "$DURUM_DOSYASI")"
}

disk_kontrol() {
    local HEDEF_IP="${UZAK_HEDEF%%:*}"
    local HEDEF_YOLU="${UZAK_HEDEF##*:}"
    
    # Uzak disk kullanımını kontrol et
    local DISK_KULLANIM
    DISK_KULLANIM=$(ssh -i "$SSH_KEY" -p "$SSH_PORT" -o ConnectTimeout=10 
        "${HEDEF_IP}" "df -h ${HEDEF_YOLU} | tail -1 | awk '{print $5}'" 2>/dev/null | tr -d '%')
    
    if [ -n "$DISK_KULLANIM" ] && [ "$DISK_KULLANIM" -gt "$DISK_DOLU_ESIK" ]; then
        echo "UYARI: Hedef disk %${DISK_KULLANIM} dolu (eşik: %${DISK_DOLU_ESIK})"
        return 1
    fi
    return 0
}

boyut_anomali_kontrol() {
    local MEVCUT_BOYUT=$1
    
    if [ ! -f "$DURUM_DOSYASI" ]; then
        log "İlk çalışma, boyut referansı oluşturuluyor: ${MEVCUT_BOYUT}MB"
        echo "$MEVCUT_BOYUT" > "$DURUM_DOSYASI"
        return 0
    fi
    
    local ONCEKI_BOYUT
    ONCEKI_BOYUT=$(cat "$DURUM_DOSYASI")
    
    if [ "$ONCEKI_BOYUT" -eq 0 ]; then
        echo "$MEVCUT_BOYUT" > "$DURUM_DOSYASI"
        return 0
    fi
    
    local FARK_YUZDESI
    FARK_YUZDESI=$(echo "scale=0; (($MEVCUT_BOYUT - $ONCEKI_BOYUT) * 100) / $ONCEKI_BOYUT" | bc 2>/dev/null || echo "0")
    FARK_YUZDESI=${FARK_YUZDESI#-}  # Mutlak değer
    
    echo "$MEVCUT_BOYUT" > "$DURUM_DOSYASI"
    
    if [ "$FARK_YUZDESI" -gt "$ONCEKI_BOYUT_SAPMA_YUZDESI" ]; then
        echo "UYARI: Yedek boyutu anomalisi tespit edildi! Önceki: ${ONCEKI_BOYUT}MB, Mevcut: ${MEVCUT_BOYUT}MB (fark: %${FARK_YUZDESI})"
        return 1
    fi
    return 0
}

html_email_olustur() {
    local DURUM=$1
    local KONU_DETAY=$2
    local ICERIK=$3
    local SURE=$4
    local BOYUT=$5
    local EXIT_CODE=$6
    
    local RENK
    case $DURUM in
        "BASARILI") RENK="#28a745" ;;
        "HATA")     RENK="#dc3545" ;;
        "UYARI")    RENK="#ffc107" ;;
        *)          RENK="#6c757d" ;;
    esac
    
    cat << HTML
Content-Type: text/html; charset=UTF-8
Subject: [$DURUM] $SUNUCU_ADI Yedekleme - $KONU_DETAY
From: Yedekleme Sistemi <$GONDEREN>
To: $BILDIRIM_EMAIL
Cc: $BILDIRIM_EMAIL_CC

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"></head>
<body style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
<div style="background-color: ${RENK}; color: white; padding: 20px; border-radius: 5px 5px 0 0;">
    <h2 style="margin: 0;">Yedekleme Raporu: $DURUM</h2>
    <p style="margin: 5px 0 0 0;">${SUNUCU_ADI} - $(date '+%d.%m.%Y %H:%M')</p>
</div>
<div style="background-color: #f8f9fa; padding: 20px; border: 1px solid #dee2e6;">
    <table style="width: 100%; border-collapse: collapse;">
        <tr><td style="padding: 5px; font-weight: bold;">Sunucu:</td><td>${SUNUCU_ADI}</td></tr>
        <tr><td style="padding: 5px; font-weight: bold;">Tarih:</td><td>$(date '+%d.%m.%Y %H:%M:%S')</td></tr>
        <tr><td style="padding: 5px; font-weight: bold;">Süre:</td><td>${SURE} saniye</td></tr>
        <tr><td style="padding: 5px; font-weight: bold;">Boyut:</td><td>${BOYUT}</td></tr>
        <tr><td style="padding: 5px; font-weight: bold;">Exit Code:</td><td>${EXIT_CODE}</td></tr>
        <tr><td style="padding: 5px; font-weight: bold;">Hedef:</td><td>${UZAK_HEDEF}</td></tr>
    </table>
</div>
<div style="background-color: #ffffff; padding: 20px; border: 1px solid #dee2e6; border-top: 0;">
    <pre style="background: #f1f1f1; padding: 10px; overflow-x: auto; font-size: 12px;">${ICERIK}</pre>
</div>
<div style="background-color: #e9ecef; padding: 10px; text-align: center; font-size: 12px; color: #6c757d; border-radius: 0 0 5px 5px;">
    Bu mesaj otomatik olarak oluşturulmuştur. Lütfen yanıtlamayın.
</div>
</body>
</html>
HTML
}

bildirim_gonder() {
    local DURUM=$1
    local KONU_DETAY=$2
    local ICERIK=$3
    local SURE=${4:-0}
    local BOYUT=${5:-"Bilinmiyor"}
    local EXIT_CODE=${6:-0}
    
    log "E-posta bildirimi gönderiliyor: [$DURUM] $KONU_DETAY"
    
    html_email_olustur "$DURUM" "$KONU_DETAY" "$ICERIK" "$SURE" "$BOYUT" "$EXIT_CODE" | 
        sendmail -t 2>/dev/null || 
        echo -e "Durum: $DURUMnDetay: $ICERIK" | 
        mail -s "[$DURUM] $SUNUCU_ADI Yedekleme - $KONU_DETAY" 
             -c "$BILDIRIM_EMAIL_CC" "$BILDIRIM_EMAIL"
}

# ============================================
# ANA SCRIPT
# ============================================

dizin_hazirla
log "=========================================="
log "Yedekleme başlıyor: $SUNUCU_ADI"
log "Kaynak dizinler: ${KAYNAK_DIZINLER[*]}"
log "Hedef: $UZAK_HEDEF"

BASLANGIC=$(date +%s)
GENEL_EXIT_CODE=0
HATA_MESAJLARI=""
UYARI_MESAJLARI=""

# SSH bağlantı testi
log "SSH bağlantısı test ediliyor..."
if ! ssh -i "$SSH_KEY" -p "$SSH_PORT" -o ConnectTimeout=15 -o BatchMode=yes 
    "${UZAK_HEDEF%%:*}" "exit 0" 2>/dev/null; then
    hata_log "SSH bağlantısı başarısız: ${UZAK_HEDEF%%:*}"
    bildirim_gonder "HATA" "SSH Bağlantı Hatası $(date '+%d.%m.%Y %H:%M')" 
        "SSH bağlantısı kurulamadı!nHedef: ${UZAK_HEDEF%%:*}nAnahtar: $SSH_KEY" 
        "0" "N/A" "255"
    exit 1
fi

# Disk kontrolü
DISK_UYARI=$(disk_kontrol 2>&1) || UYARI_MESAJLARI+="$DISK_UYARIn"

# Her kaynak dizin için rsync çalıştır
for KAYNAK in "${KAYNAK_DIZINLER[@]}"; do
    if [ ! -d "$KAYNAK" ]; then
        log "UYARI: Kaynak dizin bulunamadı, atlanıyor: $KAYNAK"
        UYARI_MESAJLARI+="Kaynak dizin mevcut değil: $KAYNAKn"
        continue
    fi
    
    log "Yedekleniyor: $KAYNAK"
    
    rsync -avz 
        --delete 
        --stats 
        --human-readable 
        --timeout=300 
        -e "ssh -i $SSH_KEY -p $SSH_PORT -o ConnectTimeout=30" 
        --exclude='*.tmp' --exclude='*.swp' --exclude='__pycache__' 
        --exclude='node_modules/' --exclude='.git/' 
        --log-file="$ISTATISTIK_LOG" 
        "$KAYNAK" "$UZAK_HEDEF" 2>>"$HATA_LOG"
    
    RSYNC_KOD=$?
    
    if [ $RSYNC_KOD -ne 0 ] && [ $RSYNC_KOD -ne 23 ] && [ $RSYNC_KOD -ne 24 ]; then
        GENEL_EXIT_CODE=$RSYNC_KOD
        HATA_MESAJLARI+="$KAYNAK dizini yedeklenirken hata (kod: $RSYNC_KOD): $(rsync_hata_acikla $RSYNC_KOD 2>/dev/null || echo 'Hata')n"
    elif [ $RSYNC_KOD -eq 23 ] || [ $RSYNC_KOD -eq 24 ]; then
        UYARI_MESAJLARI+="$KAYNAK: Kısmi transfer (kod: $RSYNC_KOD) - bazı dosyalar aktarılamadın"
    fi
done

BITIS=$(date +%s)
TOPLAM_SURE=$((BITIS - BASLANGIC))

# Süre kontrolü
if [ $TOPLAM_SURE -gt $((SURE_ESIK_DAKIKA * 60)) ]; then
    UYARI_MESAJLARI+="Yedekleme beklenenden uzun sürdü: ${TOPLAM_SURE}s (eşik: $((SURE_ESIK_DAKIKA * 60))s)n"
fi

# Yedek boyut kontrolü
AKTARILAN_BOYUT=$(grep "Total transferred file size" "$ISTATISTIK_LOG" 2>/dev/null | 
    awk '{print $NF}' | tail -1 || echo "0M")

# Bildirim kararı
if [ $GENEL_EXIT_CODE -ne 0 ]; then
    log "Yedekleme BAŞARISIZ. Exit code: $GENEL_EXIT_CODE"
    if [ "$HATA_DURUMUNDA_BILDIR" = true ]; then
        ICERIK="Yedekleme BAŞARISIZ!nnHATALAR:n${HATA_MESAJLARI}"
        [ -n "$UYARI_MESAJLARI" ] && ICERIK+="nUYARILAR:n${UYARI_MESAJLARI}"
        ICERIK+="nnLog: $LOG_DOSYASInHata Log: $HATA_LOG"
        bildirim_gonder "HATA" "Yedekleme Başarısız $(date '+%d.%m.%Y %H:%M')" 
            "$ICERIK" "$TOPLAM_SURE" "$AKTARILAN_BOYUT" "$GENEL_EXIT_CODE"
    fi
elif [ -n "$UYARI_MESAJLARI" ]; then
    log "Yedekleme UYARI ile tamamlandı."
    if [ "$KISMI_HATA_BILDIR" = true ]; then
        bildirim_gonder "UYARI" "Yedekleme Uyarıları $(date '+%d.%m.%Y %H:%M')" 
            "Yedekleme tamamlandı ancak uyarılar var:nn${UYARI_MESAJLARI}" 
            "$TOPLAM_SURE" "$AKTARILAN_BOYUT" "0"
    fi
else
    log "Yedekleme BAŞARILI. Süre: ${TOPLAM_SURE}s"
    if [ "$BASARI_DURUMUNDA_BILDIR" = true ]; then
        bildirim_gonder "BASARILI" "$(date '+%d.%m.%Y %H:%M')" 
            "Tüm dizinler başarıyla yedeklendi." 
            "$TOPLAM_SURE" "$AKTARILAN_BOYUT" "0"
    fi
fi

log "Yedekleme işlemi tamamlandı."
exit $GENEL_EXIT_CODE

Cron ile Zamanlama ve Log Rotasyonu

# Script'i çalıştırılabilir yap
chmod +x /usr/local/bin/rsync-smart-backup.sh

# Cron job ekle - her gece 02:30'da çalıştır
crontab -e

Cron girişi:

# Rsync yedekleme - her gece 02:30
30 2 * * * /usr/local/bin/rsync-smart-backup.sh >> /var/log/rsync-backup/cron.log 2>&1

# Log rotasyonu için /etc/logrotate.d/rsync-backup dosyası oluştur

Log rotasyon yapılandırması:

cat > /etc/logrotate.d/rsync-backup << 'EOF'
/var/log/rsync-backup/*.log {
    daily
    rotate 30
    compress
    delaycompress
    missingok
    notifempty
    create 640 root adm
    dateext
    dateformat -%Y%m%d
}
EOF

Anlık Test ve Sorun Giderme

Script’i cron’a almadan önce mutlaka test edin:

# Dry-run ile test et, gerçekte kopyalama yapma
rsync -avzn --stats 
    -e "ssh -i /root/.ssh/backup_rsa" 
    /var/www/html [email protected]:/backup/test/

# Script'i debug modunda çalıştır
bash -x /usr/local/bin/rsync-smart-backup.sh

# Mail gönderilebilirliğini test et
echo "Test maili - $(date)" | mail -s "Rsync Backup Test" [email protected]

# SSH anahtarının doğru çalıştığını kontrol et
ssh -i /root/.ssh/backup_rsa -o BatchMode=yes [email protected] "echo 'SSH OK'"

Sık karşılaşılan sorunlar ve çözümleri:

  • Mail gönderilmiyor: mail.log veya syslog‘u kontrol edin. journalctl -u postfix ile MTA durumuna bakın
  • SSH bağlantı hatası: Anahtarın izinlerinin 600 olduğunu, authorized_keys‘e eklendiğini kontrol edin
  • Cron’da çalışmıyor, terminalde çalışıyor: PATH sorunu olabilir. Script’in başına PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin ekleyin
  • Exit code 23 sürekli geliyor: /proc, /sys, /run gibi sanal dosya sistemlerini exclude listesine alın

Gerçek Dünya Senaryosu: E-ticaret Sitesi Yedeklemesi

Diyelim ki WooCommerce tabanlı bir e-ticaret siteniz var. Veritabanı ayrı yedekleniyor, ama medya dosyaları, theme ve plugin dosyaları rsync ile yedekleniyor.

#!/bin/bash
# /usr/local/bin/woocommerce-backup.sh

KAYNAK_DIZINLER=("/var/www/html/wp-content/uploads" "/var/www/html/wp-content/themes" "/var/www/html/wp-content/plugins")
HEDEF="[email protected]:/backup/eticaret"
KRITIK_BOYUT_MB=500  # Uploads klasörü bu değerin altına düşerse kritik uyarı

for DIZIN in "${KAYNAK_DIZINLER[@]}"; do
    BOYUT_MB=$(du -sm "$DIZIN" 2>/dev/null | cut -f1)
    
    if [ "$DIZIN" = "/var/www/html/wp-content/uploads" ] && 
       [ "$BOYUT_MB" -lt "$KRITIK_BOYUT_MB" ]; then
        echo "KRİTİK: Uploads klasörü çok küçük! ${BOYUT_MB}MB (beklenen: min ${KRITIK_BOYUT_MB}MB)" | 
            mail -s "[KRİTİK] Uploads Boyut Anomalisi" [email protected]
    fi
done

Bu tür bir kontrol, uploads klasörünün yanlışlıkla silindiği veya mount noktasının kaybedildiği durumları erken tespit eder.

Sonuç

Rsync tek başına güçlü bir araç, ama e-posta bildirimi olmadan kör uçuş yapıyorsunuz. Anlattığımız sistemin özeti şu:

  • Exit code yorumlama ile hangi hatanın ne anlama geldiğini e-postada açıkça belirtiyorsunuz
  • Disk doluluk ve boyut anomali kontrolü ile reaktif değil proaktif davranıyorsunuz
  • HTML e-posta formatı ile mobil cihazdan bile hızlıca durumu kavrayabiliyorsunuz
  • Log rotasyonu ile disk şişmesini önlüyorsunuz
  • SSH bağlantı testi ile rsync başlamadan önce olası bağlantı sorunlarını yakalıyorsunuz

Bu sistemi bir kere kurup unutabilirsiniz. Bir şeyler ters gittiğinde e-posta sizi uyaracak. Uyarı gelmediğinde ise yedeklerinizin sağlıklı çalıştığından emin olabilirsiniz. Yedekleme sistemlerinin asıl amacı da tam olarak bu: sessizce çalışmak, ama gerektiğinde bağırabilmek.

Bir yanıt yazın

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