Rsync ile Sembolik Link ve İzin Koruma: Eksiksiz Yedekleme Rehberi
Yedekleme işlerinde en çok canımı sıkan şey şudur: Gece boyunca çalışan bir rsync işi sabah tamamlanmış görünür, her şey yolunda gibi gözükür, sonra bir felaket anında yedeği geri yüklemeye çalışırsın ve fark edersin ki sembolik linkler kaybolmuş, dosya izinleri alt üst olmuş, sahiplik bilgileri uçup gitmiş. Yedek var ama işe yaramıyor. Bu yazıda rsync’in sembolik link ve izin koruma mekanizmalarını derinlemesine ele alacağız çünkü bu detaylar production ortamında gerçekten hayat kurtarır.
Neden Sembolik Linkler ve İzinler Bu Kadar Önemli?
Linux sistemlerinde sembolik linkler sadece bir kolaylık değil, çoğu zaman sistemin işleyişinin kritik bir parçasıdır. /lib ile /usr/lib arasındaki linkler, /etc/alternatives altındaki uygulama yönlendirmeleri, web sunucusunun sites-enabled dizinindeki konfigürasyon linkleri… Bunlardan herhangi biri kaybolduğunda sistem davranışı beklenmedik şekilde değişir.
İzinler konusunda da durum benzer. Bir web uygulamasının dizininde 755 yerine 777 ya da 644 yerine 600 görünce ne anlama geldiğini sistem yöneticisi olarak çok iyi biliyorsunuzdur. Yedekten geri dönüş sırasında bu izinler bozulursa güvenlik açıkları doğar ya da uygulamalar çalışmaz hale gelir.
Rsync bu konuda son derece yetenekli bir araç, ama doğru parametrelerle kullanılmazsa sessiz sedasız hata yapar. Yani hata vermez, işlemi tamamlar, ama kritik bilgileri atmış olur.
Rsync’in Temel Sembolik Link Davranışı
Rsync, sembolik linklerle karşılaştığında birkaç farklı şekilde davranabilir. Hangi parametreyi kullanmadığınıza göre sonuçlar dramatik biçimde değişir.
Varsayılan davranışı görmek için basit bir test yapalım:
# Test ortamı oluştur
mkdir -p /tmp/test_kaynak/dizin1
echo "orijinal dosya" > /tmp/test_kaynak/dizin1/dosya.txt
ln -s /tmp/test_kaynak/dizin1/dosya.txt /tmp/test_kaynak/link_dosya
ln -s /tmp/test_kaynak/dizin1 /tmp/test_kaynak/link_dizin
# Parametresiz rsync (sembolik linkler yoksayılır)
rsync -r /tmp/test_kaynak/ /tmp/test_hedef/
ls -la /tmp/test_hedef/
Bu komutun çıktısına bakınca sembolik linklerin hedefe kopyalanmadığını ya da link hedefinin içeriğinin kopyalandığını göreceksiniz. İşte burada ilk tehlike noktası ortaya çıkıyor.
Sembolik Link Parametreleri
Rsync’in sembolik linklerle ilgili dört temel parametresi vardır:
- -l veya –links: Sembolik linkleri olduğu gibi kopyalar, yani linkin kendisini taşır, hedefini değil
- -L veya –copy-links: Sembolik linkin gösterdiği dosyanın içeriğini kopyalar, linki değil
- –copy-unsafe-links: Sadece kaynak ağacının dışına işaret eden linklerin içeriğini kopyalar
- –safe-links: Kaynak ağacının dışına işaret eden linkleri atlar
Production ortamında çoğunlukla -l parametresi istediğimiz şeydir çünkü sistemin orijinal yapısını korumak istiyoruz. Ama bazı durumlarda -L daha mantıklı olabilir, bunu ilerleyen bölümlerde örneklerle göreceğiz.
# Sembolik linkleri koruyarak kopyalama
rsync -rl /tmp/test_kaynak/ /tmp/test_hedef_2/
ls -la /tmp/test_hedef_2/
# Sonuç: link_dosya ve link_dizin linker olarak kopyalanır
# lrwxrwxrwx 1 root root link_dosya -> /tmp/test_kaynak/dizin1/dosya.txt
Burada dikkat etmeniz gereken önemli bir nokta var: Link hedefi mutlak bir yola işaret ediyorsa ve siz yedeği farklı bir konuma geri yüklüyorsanız, linkler kırık hale gelir. Bu yüzden göreceli sembolik linkler production ortamında her zaman tercih edilmelidir.
İzin ve Sahiplik Koruma
Rsync’in izin koruma davranışı da varsayılan olarak istediğimiz şeyi yapmayabilir. Özellikle farklı kullanıcılar arasında ya da farklı sistemler arasında yedekleme yapıyorsanız.
İzin Parametreleri
- -p veya –perms: Dosya izinlerini (chmod değerlerini) korur
- -o veya –owner: Dosya sahibini korur (genellikle root yetkisi gerektirir)
- -g veya –group: Grup bilgisini korur
- -A veya –acls: POSIX ACL’leri korur
- -X veya –xattrs: Genişletilmiş öznitelikleri korur
# İzin ve sahiplik korumalı tam yedekleme
rsync -rlptog /kaynak/dizin/ /hedef/dizin/
# Daha okunabilir haliyle
rsync
--recursive
--links
--perms
--times
--owner
--group
/kaynak/dizin/
/hedef/dizin/
Burada -t parametresini de eklediğime dikkat edin. Zaman damgalarını korumak da kritik önem taşır çünkü birçok uygulama dosyaların değiştirilme zamanına bakarak karar verir.
-a Parametresinin Gerçek Anlamı
Çoğu rsync dökümanında -a (archive modu) önerisi görürsünüz. Peki bu parametre tam olarak ne yapar?
# -a parametresinin açılımı
rsync -a /kaynak/ /hedef/
# Yukarıdaki komut şuna eşdeğerdir:
rsync -rlptgoD /kaynak/ /hedef/
-a parametresi şunları içerir:
- -r: Özyinelemeli kopyalama
- -l: Sembolik linkleri koru
- -p: İzinleri koru
- -t: Zaman damgalarını koru
- -g: Grup bilgisini koru
- -o: Sahip bilgisini koru (root gerektirir)
- -D: Cihaz dosyalarını ve özel dosyaları koru
Görüldüğü gibi -a oldukça kapsamlı ama ACL ve genişletilmiş öznitelikleri içermiyor. SELinux veya AppArmor kullanan sistemlerde bu eksiklik önemli sorunlara yol açabilir.
# SELinux etiketlerini de koruyan tam yedek
rsync -aAX /kaynak/ /hedef/
# Verbose çıktı ile ne kopyalandığını takip et
rsync -aAXv /kaynak/ /hedef/ 2>&1 | tee /var/log/yedek_$(date +%Y%m%d).log
Gerçek Dünya Senaryosu 1: Web Sunucusu Yedeklemesi
Diyelim ki Nginx üzerinde çalışan bir web sunucunuzun tam yedeğini alıyorsunuz. Bu senaryoda /etc/nginx dizininin doğru şekilde yedeklenmesi kritik.
#!/bin/bash
# /usr/local/bin/nginx_yedek.sh
KAYNAK="/etc/nginx"
HEDEF="/backup/nginx/$(date +%Y%m%d_%H%M%S)"
LOG="/var/log/nginx_yedek.log"
mkdir -p "$HEDEF"
rsync -aAXv
--delete
--backup
--backup-dir="/backup/nginx/onceki_$(date +%Y%m%d)"
"$KAYNAK/"
"$HEDEF/"
>> "$LOG" 2>&1
if [ $? -eq 0 ]; then
echo "$(date): Nginx yedekleme basarili - $HEDEF" >> "$LOG"
else
echo "$(date): HATA - Nginx yedekleme basarisiz!" >> "$LOG"
# Alarm gonder
mail -s "Nginx Yedek Hatasi" [email protected] < "$LOG"
fi
Bu script’i çalıştırdığınızda /etc/nginx/sites-enabled altındaki sembolik linkler korunur. Geri yüklemede de linkler aynı şekilde oluşturulur. --delete parametresi hedefte artık bulunmayan dosyaları siler, bu sayede yedek gerçek sistemin birebir kopyası olur.
Gerçek Dünya Senaryosu 2: Kullanıcı Ev Dizinleri
Birden fazla kullanıcının ev dizinini yedeklemek bambaşka bir tablo ortaya çıkarır. Her kullanıcının farklı UID/GID’i vardır ve bunların korunması şarttır.
#!/bin/bash
# /usr/local/bin/ev_dizin_yedek.sh
KAYNAK="/home"
UZAK_SUNUCU="yedek-sunucu.sirket.com"
UZAK_HEDEF="/backup/home"
SSH_KEY="/root/.ssh/yedek_rsa"
# Numeric IDs kullan, isim çözümlemesine güvenme
rsync -aAXv
--numeric-ids
--delete
--exclude=".cache"
--exclude=".local/share/Trash"
--exclude="*.tmp"
-e "ssh -i $SSH_KEY -p 22022"
"$KAYNAK/"
"${UZAK_SUNUCU}:${UZAK_HEDEF}/"
Burada –numeric-ids parametresi çok önemli. Kullanıcı adı tabanlı eşleşme yerine numerik UID/GID kullanır. İki sunucuda aynı kullanıcı adları olsa bile UID’ler farklı olabilir. Sayısal ID’leri korumak, geri yükleme sırasında sahiplik bilgilerinin doğru kalmasını sağlar.
Sorunlu Durumlar ve Çözümleri
Sorun 1: Döngüsel Sembolik Linkler
Sembolik linkler döngü oluşturabilir ve rsync bu durumda sonsuza kadar çalışabilir.
# Tehlikeli durum örneği
mkdir /tmp/dongu_test
ln -s /tmp/dongu_test /tmp/dongu_test/kendim
# Bu komut sorun çıkarır
# rsync -rL /tmp/dongu_test/ /tmp/hedef/ # YAPMAYIN
# Güvenli çözüm: link hedeflerini kopyalamak yerine linkleri koru
rsync -rl /tmp/dongu_test/ /tmp/hedef/
Sorun 2: Kırık Sembolik Linkler
Hedefi olmayan sembolik linkler rsync tarafından farklı şekillerde ele alınabilir.
# Kırık link oluştur
ln -s /var/olmayan/yol /tmp/kirik_link
# Varsayılan davranışı test et
rsync -rl /tmp/test_kirik/ /tmp/hedef_kirik/ --verbose
# Kırık linkleri de kopyalamak için
rsync -rl /tmp/test_kirik/ /tmp/hedef_kirik/ --keep-dirlinks
# Kırık linkleri atlamak için özel filtre
rsync -rl
--filter="exclude *"
--filter="include */"
/tmp/test_kirik/
/tmp/hedef_kirik/
Sorun 3: Root Olmayan Kullanıcıyla Çalışma
Bazen root yetkisi olmadan yedekleme yapmanız gerekebilir. Bu durumda sahiplik bilgisi korunamaz.
# Root olmayan kullanıcı için güvenli yedekleme
# -o ve -g parametreleri atlanır
rsync -rlptv
--no-owner
--no-group
/kaynak/dizin/
/hedef/dizin/
# Alternatif: chmod koruması ile en azından izinleri koru
rsync -rlpv
/kaynak/dizin/
/hedef/dizin/
2>&1 | grep -v "chown|Operation not permitted"
Gelişmiş: ACL ve Genişletilmiş Öznitelik Yedeklemesi
Modern Linux sistemlerinde sadece standart Unix izinleri yetmez. Özellikle kurumsal ortamlarda POSIX ACL’ler ve SELinux/AppArmor etiketleri kritik öneme sahip.
# ACL bilgisini kontrol et
getfacl /var/www/html/
# Genişletilmiş öznitelikleri kontrol et
getfattr -d /var/www/html/index.php
# Tam koruma ile yedekleme
rsync -aAXv
--numeric-ids
--delete
--stats
/var/www/html/
/backup/www_html/
# İstatistikler şunu gösterir:
# Number of files transferred
# Total file size
# Total transferred file size
# Literal data / Matched data
ACL yedeklemesinin düzgün çalışması için hem kaynak hem hedef dosya sisteminin ACL desteğini aktif etmesi gerekir. Bunu kontrol etmek için:
# Dosya sistemi mount seçeneklerini kontrol et
mount | grep acl
# ya da
tune2fs -l /dev/sda1 | grep "Default mount"
# Eğer acl mount seçeneği yoksa /etc/fstab'a ekle
# UUID=xxxx /var ext4 defaults,acl 0 2
İzleme ve Doğrulama
Yedekleme bittikten sonra doğrulama yapmak en az yedekleme kadar önemlidir. Rsync’in --checksum parametresi bu konuda yardımcı olur ama dikkatli kullanın, çok yavaştır.
#!/bin/bash
# Yedek doğrulama scripti
# /usr/local/bin/yedek_dogrula.sh
KAYNAK="/etc"
HEDEF="/backup/etc_son"
echo "=== Sembolik Link Kontrolu ==="
# Kaynaktaki linkleri say
KAYNAK_LINK=$(find "$KAYNAK" -type l | wc -l)
# Hedefteki linkleri say
HEDEF_LINK=$(find "$HEDEF" -type l | wc -l)
echo "Kaynak link sayisi: $KAYNAK_LINK"
echo "Hedef link sayisi: $HEDEF_LINK"
if [ "$KAYNAK_LINK" -ne "$HEDEF_LINK" ]; then
echo "UYARI: Link sayilari eslesmiyor!"
# Hangi linkler eksik?
diff
<(find "$KAYNAK" -type l -printf "%Pn" | sort)
<(find "$HEDEF" -type l -printf "%Pn" | sort)
fi
echo ""
echo "=== Izin Kontrolu ==="
# Kritik dosyaların izinlerini karşılaştır
rsync -anv --itemize-changes
"$KAYNAK/"
"$HEDEF/"
| grep "^[^.]*p"
| head -20
echo ""
echo "=== Kırık Link Kontrolu ==="
find "$HEDEF" -type l ! -exec test -e {} ; -print
Bu script’i yedekleme işleminden hemen sonra çalıştırırsanız, sorunları erken tespit edersiniz.
Cron ile Otomatikleştirme ve Log Yönetimi
Tüm bu bilgileri bir araya getiren, production ortamında kullanabileceğiniz kapsamlı bir yedekleme scripti:
#!/bin/bash
# /usr/local/bin/tam_sistem_yedek.sh
# Cron: 0 2 * * * /usr/local/bin/tam_sistem_yedek.sh
set -euo pipefail
KAYNAK_DIZINLER=("/etc" "/var/www" "/home" "/opt/uygulamalar")
HEDEF_TABAN="/mnt/yedek_disk"
TARIH=$(date +%Y%m%d_%H%M%S)
LOG_DOSYA="/var/log/rsync_yedek_${TARIH}.log"
HATA_SAYISI=0
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_DOSYA"
}
yedekle() {
local kaynak="$1"
local dizin_adi=$(basename "$kaynak")
local hedef="${HEDEF_TABAN}/${dizin_adi}"
log "Basliyor: $kaynak -> $hedef"
rsync -aAXv
--numeric-ids
--delete
--delete-excluded
--exclude="*.pid"
--exclude="*.sock"
--exclude="/proc"
--exclude="/sys"
--exclude="/dev"
--exclude="/run"
--stats
--log-file="${LOG_DOSYA}"
"${kaynak}/"
"${hedef}/"
local rsync_cikis=$?
if [ $rsync_cikis -eq 0 ]; then
log "BASARILI: $kaynak yedeklendi"
elif [ $rsync_cikis -eq 24 ]; then
log "UYARI: $kaynak - Bazi dosyalar transfer sirasinda silindi (rsync 24)"
else
log "HATA: $kaynak yedeklenemedi! Cikis kodu: $rsync_cikis"
HATA_SAYISI=$((HATA_SAYISI + 1))
fi
}
# Ana yedekleme döngüsü
for dizin in "${KAYNAK_DIZINLER[@]}"; do
if [ -d "$dizin" ]; then
yedekle "$dizin"
else
log "UYARI: $dizin mevcut degil, atlaniyor"
fi
done
# Sonuç raporu
if [ $HATA_SAYISI -eq 0 ]; then
log "Tum yedeklemeler basariyla tamamlandi"
else
log "DIKKAT: $HATA_SAYISI dizin yedeklenemedi!"
mail -s "Yedek Hatasi - $(hostname)" [email protected] < "$LOG_DOSYA"
fi
# Eski logları temizle (30 günden eski)
find /var/log -name "rsync_yedek_*.log" -mtime +30 -delete
Geri Yükleme Senaryosu
Yedekleme kadar önemli olan geri yükleme sürecini de pratikte test etmek gerekir. İşte güvenli bir geri yükleme scripti:
#!/bin/bash
# /usr/local/bin/geri_yukle.sh
YEDEK_KAYNAK="/mnt/yedek_disk/etc"
GERI_YUKLE_HEDEF="/etc"
TARIH=$(date +%Y%m%d_%H%M%S)
# Önce mevcut durumun yedeğini al (güvenlik önlemi)
echo "Mevcut durumun anlık yedeği alınıyor..."
rsync -aAX "${GERI_YUKLE_HEDEF}/" "/tmp/etc_onceki_${TARIH}/"
echo "Geri yükleme başlatılıyor..."
rsync -aAXv
--numeric-ids
--delete
--dry-run
"${YEDEK_KAYNAK}/"
"${GERI_YUKLE_HEDEF}/"
echo ""
echo "Yukarıdaki değişiklikler uygulanacak. Devam etmek istiyor musunuz? (evet/hayir)"
read -r onay
if [ "$onay" = "evet" ]; then
rsync -aAXv
--numeric-ids
--delete
"${YEDEK_KAYNAK}/"
"${GERI_YUKLE_HEDEF}/"
echo "Geri yükleme tamamlandı."
else
echo "Geri yükleme iptal edildi."
fi
–dry-run parametresi burada son derece değerlidir. Gerçekten neyin değişeceğini önce görmek, felaket anında panikle yanlış karar vermekten sizi korur.
Sonuç
Rsync ile düzgün bir yedekleme stratejisi oluşturmak, doğru parametreleri bilmekten geçiyor. Özetleyecek olursam:
- -a parametresi iyi bir başlangıç noktası ama tek başına yeterli değil
- ACL ve SELinux kullanan sistemlerde mutlaka -A ve -X ekleyin
- Farklı sistemler arasında yedekleme yaparken –numeric-ids kullanın
- Geri yükleme öncesi mutlaka –dry-run ile test edin
- Sembolik linklerin döngüsel ya da kırık olmadığını düzenli kontrol edin
- Her yedekleme işleminin ardından doğrulama scripti çalıştırın
En iyi yedekleme sistemi, hiç test edilmemiş yedekleme sistemi değildir. Ayda en az bir kez geri yükleme senaryonuzu test edin. Çünkü felaket anında “sanırım çalışır” demek için zamanınız olmaz.
