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-destseç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.
