Ubuntu’da Rsync ile Otomatik Yedekleme Sistemi Kurulumu

Yedekleme konusu sysadminlerin kafasının en çok şiştiği konulardan biridir. “Yedek aldım mı? Ne zaman aldım? Gerçekten çalıştı mı?” soruları gece uyutmaz. Ben de yıllar içinde onlarca farklı yedekleme çözümü denedim ve sonunda şu sonuca vardım: rsync + cron + biraz bash scripti, kurumsal yedekleme yazılımlarının büyük çoğunluğundan daha güvenilir ve daha anlaşılır bir çözüm sunuyor. Bu yazıda sıfırdan, production’da kullanabileceğiniz bir otomatik yedekleme sistemi kuracağız.

Rsync Nedir ve Neden Bu Kadar Güçlü?

Rsync, “remote sync” kelimelerinin kısaltmasıdır ve dosyaları yerel ya da uzak sistemler arasında senkronize etmek için kullanılır. Ama onu gerçekten güçlü kılan şey, delta transfer algoritması. Rsync, dosyanın tamamını kopyalamak yerine sadece değişen bloklarını transfer eder. Bu, özellikle büyük dosyalar için muazzam bir bant genişliği ve zaman tasarrufu anlamına gelir.

Temel avantajları şöyle sıralayabilirim:

  • İnkremental yedekleme: Sadece değişen dosyaları kopyalar
  • Hardlink desteği: --link-dest seçeneği ile disk alanını verimli kullanır
  • SSH tüneli: Şifreli transfer, güvenli uzak yedekleme
  • Checksums: Veri bütünlüğünü garanti eder
  • Bant genişliği limiti: Üretim trafiğini etkilemeden çalışır
  • Kısmi transfer: Kesilen transferi kaldığı yerden devam ettirir

Kurulum ve Temel Kontroller

Ubuntu’da rsync genellikle önceden yüklü gelir, ama kontrol edelim:

rsync --version
# Yoksa:
sudo apt update && sudo apt install rsync -y

SSH ile uzak sunucuya yedekleme yapacaksanız, hedef sunucuda da rsync kurulu olmalı. Bunu atlayan çok kişi var, sonra saatlerce hata ayıklıyorlar.

Senaryo 1: Yerel Disk Yedeklemesi

Diyelim ki web sunucunuzun /var/www dizinini, bağlı bir harici diske yedeklemek istiyorsunuz. Harici disk /mnt/backup olarak mount edilmiş durumda.

rsync -avz --progress /var/www/ /mnt/backup/www/

Bu komuttaki parametreler:

  • -a: Archive modu, dosya izinlerini, zaman damgalarını, sembolik linkleri korur
  • -v: Verbose, ne yapıldığını gösterir
  • -z: Transfer sırasında sıkıştırma uygular
  • –progress: Transfer ilerlemesini gösterir

Dikkat edin: /var/www/ sonundaki slash önemli. Slash varsa dizinin içeriği kopyalanır, yoksa dizinin kendisi kopyalanır. Bu farkı anlamayan sysadminler yanlış yerde yedek bulur kendini.

Senaryo 2: Snapshot Tarzı Yedekleme (Rotasyonlu)

Production ortamında en çok kullandığım yöntem budur. --link-dest parametresi sayesinde her gün tam yedek alıyormuş gibi görünür, ama disk alanı olarak sadece değişen dosyalar yer kaplar. Bu harika bir özellik.

#!/bin/bash
# snapshot_backup.sh

SOURCE="/var/www/"
BACKUP_ROOT="/mnt/backup/snapshots"
DATE=$(date +%Y-%m-%d)
LATEST="$BACKUP_ROOT/latest"
DEST="$BACKUP_ROOT/$DATE"

# Hedef dizini oluştur
mkdir -p "$DEST"

# Önceki yedeği referans alarak snapshot al
rsync -avz --delete 
    --link-dest="$LATEST" 
    "$SOURCE" 
    "$DEST/"

# 'latest' sembolik linkini güncelle
rm -f "$LATEST"
ln -s "$DEST" "$LATEST"

echo "Yedekleme tamamlandı: $DEST"

--delete parametresi, kaynak dosyada silinmiş dosyaları hedeften de siler. Bunu kullanmak isteyip istemediğinizi iyi düşünün. Eğer birisi yanlışlıkla dosya sildiyse ve siz fark etmeden yedek çalıştırdıysanız, o dosya sonraki yedekte de olmayacak. Bu yüzden rotasyonlu sistemi şart koşuyorum.

Senaryo 3: SSH Üzerinden Uzak Sunucu Yedeklemesi

Gerçek dünya senaryolarında çoğu zaman yedekleri uzak bir sunucuya göndermeniz ya da uzak sunucudan çekmeniz gerekir. Önce SSH anahtar tabanlı kimlik doğrulamayı ayarlayalım:

# Yedekleme sunucusunda anahtar çifti oluştur
ssh-keygen -t ed25519 -C "backup@yedek-sunucu" -f ~/.ssh/backup_key

# Public anahtarı kaynak sunucuya kopyala
ssh-copy-id -i ~/.ssh/backup_key.pub [email protected]

Şimdi uzak sunucudan yedek çekelim (pull yöntemi). Bu yöntemi tercih ediyorum çünkü yedekleme sunucusu kontrolü elinde tutuyor:

#!/bin/bash
# remote_backup.sh

REMOTE_USER="backupuser"
REMOTE_HOST="uretim-sunucu.sirket.com"
REMOTE_SOURCE="/var/www/"
LOCAL_DEST="/backup/uretim/$(date +%Y-%m-%d_%H-%M)/"
SSH_KEY="/root/.ssh/backup_key"
LOG_FILE="/var/log/backup/rsync_$(date +%Y-%m-%d).log"

mkdir -p "$LOCAL_DEST"
mkdir -p "$(dirname $LOG_FILE)"

echo "=== Yedekleme başladı: $(date) ===" >> "$LOG_FILE"

rsync -avz 
    --delete 
    --exclude='*.tmp' 
    --exclude='*.log' 
    --exclude='.git/' 
    --exclude='node_modules/' 
    -e "ssh -i $SSH_KEY -p 22 -o StrictHostKeyChecking=no" 
    "$REMOTE_USER@$REMOTE_HOST:$REMOTE_SOURCE" 
    "$LOCAL_DEST" >> "$LOG_FILE" 2>&1

EXIT_CODE=$?

if [ $EXIT_CODE -eq 0 ]; then
    echo "=== Yedekleme BAŞARILI: $(date) ===" >> "$LOG_FILE"
else
    echo "=== Yedekleme BAŞARISIZ (exit code: $EXIT_CODE): $(date) ===" >> "$LOG_FILE"
fi

--exclude parametreleri ile gereksiz dosyaları yedek dışında bırakabilirsiniz. node_modules klasörlerini yedeklememek, özellikle Node.js projelerinde disk alanından ciddi tasarruf sağlar.

Otomatik Rotasyon: Eski Yedekleri Temizleme

Yedek alan ama temizlemeyi unutanlar, bir gün dolu disk alarmıyla karşılaşır. Bunu otomatize edelim:

#!/bin/bash
# cleanup_backups.sh

BACKUP_ROOT="/mnt/backup/snapshots"
GUNLUK_SAKLA=7      # Son 7 günü sakla
HAFTALIK_SAKLA=4    # Son 4 haftayı sakla
AYLIK_SAKLA=3       # Son 3 ayı sakla

echo "Eski yedekler temizleniyor..."

# 7 günden eski, 4 haftadan genç yedekleri sil (haftalık olanlar hariç)
find "$BACKUP_ROOT" -maxdepth 1 -type d -name "20*" | sort | while read dir; do
    dir_date=$(basename "$dir")
    dir_epoch=$(date -d "$dir_date" +%s 2>/dev/null)
    now_epoch=$(date +%s)
    age_days=$(( (now_epoch - dir_epoch) / 86400 ))

    if [ $age_days -gt $GUNLUK_SAKLA ] && [ $age_days -le 30 ]; then
        # Pazartesi yedeklerini sakla (haftalık yedek gibi)
        day_of_week=$(date -d "$dir_date" +%u 2>/dev/null)
        if [ "$day_of_week" != "1" ]; then
            echo "Siliniyor: $dir ($age_days gün önce)"
            rm -rf "$dir"
        fi
    elif [ $age_days -gt 30 ]; then
        # Ayın 1'ine ait yedekleri sakla
        day_of_month=$(date -d "$dir_date" +%d 2>/dev/null)
        if [ "$day_of_month" != "01" ]; then
            echo "Siliniyor: $dir ($age_days gün önce)"
            rm -rf "$dir"
        fi
    fi
done

echo "Temizlik tamamlandı."
df -h "$BACKUP_ROOT"

Cron ile Otomatikleştirme

Script’leri hazırladık, şimdi bunları zamanlanmış görevlere bağlayalım:

# Crontab düzenlemek için
crontab -e

# Şu satırları ekleyin:
# Her gece saat 02:00'de yedek al
0 2 * * * /usr/local/bin/snapshot_backup.sh

# Her gece 04:00'de eski yedekleri temizle
0 4 * * * /usr/local/bin/cleanup_backups.sh

# Uzak sunucu yedeği her gece 03:00'de
0 3 * * * /usr/local/bin/remote_backup.sh

Script’lerinizin çalıştırılabilir olduğundan emin olun:

chmod +x /usr/local/bin/snapshot_backup.sh
chmod +x /usr/local/bin/cleanup_backups.sh
chmod +x /usr/local/bin/remote_backup.sh

E-posta ile Bildirim Sistemi

Yedekleme çalıştı, ama başarılı mıydı? Bunu takip etmek için basit bir bildirim mekanizması ekleyelim. Ben mailutils kullanıyorum:

sudo apt install mailutils -y

Ana yedekleme scriptinizi şu şekilde bildirim özelliğiyle güncelleyin:

#!/bin/bash
# backup_with_notification.sh

SUNUCU_ADI=$(hostname)
YONETICI_EMAIL="[email protected]"
LOG_FILE="/var/log/backup/backup_$(date +%Y-%m-%d).log"
SOURCE="/var/www/"
DEST="/mnt/backup/$(date +%Y-%m-%d)/"

mkdir -p "$DEST" "$(dirname $LOG_FILE)"

# Yedeklemeyi çalıştır ve çıktıyı logla
rsync -avz --delete "$SOURCE" "$DEST" > "$LOG_FILE" 2>&1
EXIT_CODE=$?

# Transfer istatistiklerini al
TRANSFER_STATS=$(tail -5 "$LOG_FILE")
DISK_USAGE=$(df -h /mnt/backup | tail -1 | awk '{print $5}')

if [ $EXIT_CODE -eq 0 ]; then
    KONU="[BASARILI] $SUNUCU_ADI Gecelelik Yedek - $(date +%d.%m.%Y)"
    MESAJ="Yedekleme başarıyla tamamlandı.nnSunucu: $SUNUCU_ADInZaman: $(date)nHedef: $DESTnDisk Doluluk: $DISK_USAGEnnTransfer Özeti:n$TRANSFER_STATS"
else
    KONU="[KRITIK HATA] $SUNUCU_ADI Yedek BASARISIZ - $(date +%d.%m.%Y)"
    MESAJ="DİKKAT: Yedekleme başarısız oldu!nnSunucu: $SUNUCU_ADInZaman: $(date)nHata Kodu: $EXIT_CODEnnLog:n$(cat $LOG_FILE)"
fi

echo -e "$MESAJ" | mail -s "$KONU" "$YONETICI_EMAIL"

Prodüksiyon ortamında bu script’i çalıştırmadan önce mail komutunu test edin. SMTP ayarlarının doğru yapılandırılmış olması gerekiyor.

Bant Genişliği Yönetimi

Üretim saatlerinde yedekleme yapmanız gerekiyorsa, bant genişliğini sınırlamak kritik önem taşır:

# Maksimum 10 MB/s ile sınırla
rsync -avz --bwlimit=10240 /var/www/ /mnt/backup/www/

# Bant genişliği kullanımını izle
watch -n 1 'iftop -i eth0 -t -s 10 2>/dev/null | head -20'

--bwlimit değeri kilobayt/saniye cinsinden girilir. 10240 = 10 MB/s demektir.

Rsync Daemon Modu ile Gelişmiş Kurulum

Büyük ortamlarda rsync daemon olarak çalıştırmak, SSH overhead’ını ortadan kaldırır ve daha hızlı transfer sağlar. Yedekleme sunucusunda /etc/rsyncd.conf oluşturun:

# /etc/rsyncd.conf

uid = nobody
gid = nogroup
use chroot = yes
max connections = 4
syslog facility = local5
pid file = /var/run/rsyncd.pid

[webbackup]
    path = /backup/web
    comment = Web Sunucusu Yedekleri
    read only = no
    list = yes
    auth users = backupuser
    secrets file = /etc/rsyncd.secrets
    hosts allow = 192.168.1.0/24
    hosts deny = *

Parola dosyasını oluşturun:

echo "backupuser:guclu_parola_buraya" > /etc/rsyncd.secrets
chmod 600 /etc/rsyncd.secrets

# Daemon'ı başlat
sudo systemctl enable rsync
sudo systemctl start rsync

İstemci tarafında kullanımı:

rsync -avz /var/www/ rsync://backupuser@yedek-sunucu/webbackup/

Yedek Bütünlüğünü Doğrulama

Yedek aldınız, güzel. Peki geri yüklenebilir mi? Bu soruyu periyodik olarak sormanız ve test etmeniz şart:

#!/bin/bash
# verify_backup.sh

YEDEK_DIZIN="/mnt/backup/snapshots/latest"
TEST_DOSYA="/tmp/backup_verify_$(date +%s).txt"

echo "Yedek bütünlüğü doğrulanıyor..."

# Rastgele 5 dosya seç ve checksum karşılaştır
find "$YEDEK_DIZIN" -type f | shuf -n 5 | while read dosya; do
    if [ -f "$dosya" ]; then
        CHECKSUM=$(md5sum "$dosya" | awk '{print $1}')
        echo "OK: $dosya ($CHECKSUM)"
    else
        echo "HATA: Dosya bulunamadı: $dosya"
    fi
done

# Toplam dosya sayısı ve disk kullanımını raporla
DOSYA_SAYISI=$(find "$YEDEK_DIZIN" -type f | wc -l)
DISK_KULLANIM=$(du -sh "$YEDEK_DIZIN" | awk '{print $1}')

echo ""
echo "Toplam dosya sayısı: $DOSYA_SAYISI"
echo "Disk kullanımı: $DISK_KULLANIM"
echo "Doğrulama tamamlandı: $(date)"

Ben bu script’i ayda bir cron’a ekliyorum ve sonuçları e-posta ile alıyorum. Gerçek bir geri yükleme testi yapamamasanız da, en azından yedek klasörünün var olduğunu ve dosyaların erişilebilir olduğunu doğrular.

Sık Yapılan Hatalar ve Çözümleri

Yıllar içinde gördüğüm en yaygın sorunları ve çözümlerini paylaşayım:

“Yeterli disk alanı yok” hatası: Yedek almadan önce disk kontrolü ekleyin. Basit ama hayat kurtarır:

GEREKEN_ALAN_GB=50
BOSTA_ALAN=$(df -BG /mnt/backup | tail -1 | awk '{print $4}' | tr -d 'G')

if [ "$BOSTA_ALAN" -lt "$GEREKEN_ALAN_GB" ]; then
    echo "KRITIK: Yetersiz disk alanı! Mevcut: ${BOSTA_ALAN}GB" | 
    mail -s "[KRITIK] Yedekleme Disk Dolmak Uzere" [email protected]
    exit 1
fi

Sembolik link sorunları: Rsync sembolik linkleri varsayılan olarak link olarak kopyalar. Eğer linkin işaret ettiği dosyayı kopyalamak istiyorsanız --copy-links veya -L kullanın.

İzin hataları: Root olmayan bir kullanıcıyla yedekleme yapıyorsanız ve sistem dosyalarını yedeklemeniz gerekiyorsa, ya sudo yetkisi verin ya da rsync’i --rsync-path="sudo rsync" ile çalıştırın.

Encoding sorunları: Türkçe karakter içeren dosya adlarında sorun yaşıyorsanız:

export LANG=tr_TR.UTF-8
export LC_ALL=tr_TR.UTF-8
rsync -avz --iconv=UTF-8,UTF-8 /kaynak/ /hedef/

Log Yönetimi ve İzleme

Rsync loglarını merkezi bir yerde tutun ve düzenli olarak kontrol edin:

# /etc/rsyslog.d/rsync.conf
local5.*    /var/log/rsync.log

# Log dosyasını izlemek için
tail -f /var/log/backup/backup_$(date +%Y-%m-%d).log

# Son 7 günün başarısız yedeklerini bul
grep -r "BASARISIZ|error|failed" /var/log/backup/ --include="*.log" | tail -20

Logrotate ile Log Temizliği

Loglar da zamanla büyür, bunu da otomatize edelim:

# /etc/logrotate.d/rsync-backup
/var/log/backup/*.log {
    daily
    rotate 30
    compress
    delaycompress
    missingok
    notifempty
    create 644 root root
}

Sonuç

Bu yazıda temel rsync kullanımından başlayıp, snapshot yedekleme, uzak sunucu senkronizasyonu, otomatik rotasyon, e-posta bildirimleri ve log yönetimine kadar production kalitesinde bir yedekleme sistemi kurduk. Tüm bu script’leri /usr/local/bin/ altında toplayın, cron’larını tanımlayın ve ilk hafta her gün logları kontrol edin.

Şunu net söyleyeyim: En iyi yedekleme sistemi, test edilmiş yedekleme sistemidir. Geri yükleme drillı yapmayan, yedek sağlamlığını doğrulamayan bir sistem, yedek almıyor demektir. Her ay en az bir kez test ortamında gerçek geri yükleme yapın.

Rsync’in --dry-run seçeneği, komutu gerçekten çalıştırmadan neyin kopyalanacağını gösterir. Yeni bir script yazmak ya da mevcut birini değiştirmek istediğinizde her zaman önce dry-run yapın. Bu küçük alışkanlık, beni birçok kez kurtardı.

Son olarak, 3-2-1 kuralını hatırlatmak isterim: 3 kopya veri, 2 farklı ortam, 1 off-site yedek. Rsync ile kurduğunuz bu sistem, bu stratejinin önemli bir parçası olabilir ama tek başına yeterli değildir. Off-site yedek için bu sistemi uzak bir konumdaki sunucuyla birleştirin ya da bulut depolamayı devreye alın.

Bir yanıt yazın

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