Otomatik Zamanlı Yedekleme: Rclone ile Cron Kullanımı
Yedekleme konusunda herkesin teoride hemfikir olduğu ama pratikte ihmal ettiği bir gerçek var: Manuel yedekleme, eninde sonunda unutulur. Bir gün meşgul olursunuz, bir gün “yarın yaparım” dersiniz ve tam o gece disk çöker. İşte bu yüzden otomasyon şart. Bu yazıda Rclone ve Cron kombinasyonunu kullanarak nasıl sağlam, otomatik ve zamanlı bir yedekleme sistemi kurulacağını adım adım anlatacağım.
Rclone Nedir ve Neden Kullanıyoruz?
Rclone, bulut depolama servisleriyle yerel dosya sistemi arasında köprü kuran açık kaynaklı bir komut satırı aracıdır. Google Drive, S3, Backblaze B2, SFTP, WebDAV, OneDrive ve daha onlarca servisi destekler. Benim onu sevmemin asıl sebebi şu: Rsync’in mantığını buluta taşıyor. Değişen dosyaları tespit ediyor, gereksiz veri transferini engelliyor ve şifreleme desteğiyle hassas verilerinizi güvende tutuyor.
Cron ise bildiğimiz eski dost. Linux sistemlerde görevleri zamanlı çalıştırmak için onlarca yıldır kullanılan araç. İkisini bir araya getirince “her gece 02:00’de yedek al, eski yedekleri temizle, hata varsa mail at” gibi senaryolar gayet temiz bir şekilde hayata geçiyor.
Kurulum
Rclone Kurulumu
Debian/Ubuntu tabanlı sistemlerde:
sudo apt update && sudo apt install rclone -y
Eğer repolardaki sürüm eski kalıyorsa (ki sık sık kalır), resmi kurulum scriptini tercih edin:
curl https://rclone.org/install.sh | sudo bash
RHEL/CentOS/Rocky Linux için:
sudo dnf install rclone -y
# veya
curl https://rclone.org/install.sh | sudo bash
Kurulumu doğrulayalım:
rclone version
Remote Yapılandırması
Rclone’un kalbi rclone config komutu. Burada uzak depolama servisini tanımlıyoruz. Ben bu örnekte Backblaze B2 kullanacağım çünkü fiyat/performans oranı açısından sunucu yedeklemeleri için oldukça mantıklı. Siz Google Drive veya S3 de kullanabilirsiniz, mantık aynı.
rclone config
Komut sizi interaktif bir sihirbaza götürür:
nyazıp Enter’a basarak yeni remote oluşturun- İsim verin, örneğin:
b2-backup - Servis listesinden uygun numarayı seçin (B2 için genellikle 5 veya 6, listeye göre değişir)
- Application Key ID ve Application Key bilgilerinizi girin
- Diğer ayarları varsayılan bırakıp ilerleyin
Yapılandırma dosyası ~/.config/rclone/rclone.conf altında saklanır. Root kullanıcısı için bu yol /root/.config/rclone/rclone.conf olur ki cron job’larınızda bunu aklınızda tutmanız gerekiyor.
Bağlantıyı test edelim:
rclone lsd b2-backup:
Bu komut B2 hesabınızdaki bucket’ları listeler. Çıktı geliyorsa yapılandırma doğrudur.
Temel Rclone Komutları
Otomasyon yazmadan önce hangi komutu ne zaman kullanacağımızı bilmemiz lazım.
rclone copy: Kaynak’tan hedefe sadece yeni veya değişen dosyaları kopyalar. Hedefteki fazladan dosyalara dokunmaz.
rclone sync: Kaynağı referans alarak hedefi senkronize eder. Kaynakta olmayan dosyaları hedeftensiler. Dikkatli kullanın.
rclone move: Dosyaları taşır, kaynaktan siler.
rclone check: İki lokasyon arasındaki farkları listeler, bir şey kopyalamaz. Test için ideal.
Yedekleme için genellikle rclone copy veya rclone sync kullanırız. Benim tavsiyem çoğu senaryo için copy kullanmak ve eski yedeklerin silinmesini ayrı bir mantıkla yönetmek.
Yedekleme Script’i Yazmak
Sadece rclone copy komutunu cron’a eklemek çalışır ama production ortamında bu yeterli değil. Loglama, hata yönetimi, lock dosyası (aynı anda iki yedek başlamasın diye) ve bildirim mekanizması olmadan gerçek anlamda güvenilir bir sistem kuramazsınız.
İşte temel bir yedekleme script’i:
#!/bin/bash
# =============================================
# Rclone Otomatik Yedekleme Script'i
# =============================================
# Degiskenler
BACKUP_SOURCE="/var/www /home /etc"
BACKUP_DEST="b2-backup:sunucu-yedek-$(hostname)"
LOG_DIR="/var/log/rclone"
LOG_FILE="$LOG_DIR/backup_$(date +%Y%m%d_%H%M%S).log"
LOCK_FILE="/tmp/rclone_backup.lock"
RETENTION_DAYS=30
EMAIL="[email protected]"
# Log dizini yoksa olustur
mkdir -p "$LOG_DIR"
# Lock kontrolu - ayni anda iki yedek baslamasin
if [ -f "$LOCK_FILE" ]; then
echo "$(date): HATA - Baska bir yedekleme sureci calisiyor. Cikiliyor." | tee -a "$LOG_FILE"
exit 1
fi
# Lock dosyasi olustur
touch "$LOCK_FILE"
# Script bitince lock'u temizle (hata da olsa)
trap "rm -f $LOCK_FILE" EXIT
echo "$(date): Yedekleme basliyor..." | tee -a "$LOG_FILE"
echo "Kaynak: $BACKUP_SOURCE" | tee -a "$LOG_FILE"
echo "Hedef: $BACKUP_DEST" | tee -a "$LOG_FILE"
echo "========================================" | tee -a "$LOG_FILE"
# Yedekleme islemi
BACKUP_EXIT_CODE=0
for SOURCE_DIR in $BACKUP_SOURCE; do
if [ -d "$SOURCE_DIR" ]; then
echo "$(date): $SOURCE_DIR yedekleniyor..." | tee -a "$LOG_FILE"
rclone copy "$SOURCE_DIR" "$BACKUP_DEST$SOURCE_DIR"
--log-level INFO
--log-file "$LOG_FILE"
--transfers 4
--checkers 8
--retries 3
--low-level-retries 10
--stats 60s
--exclude "*.tmp"
--exclude ".cache/**"
--exclude "node_modules/**"
EXIT_CODE=$?
if [ $EXIT_CODE -ne 0 ]; then
echo "$(date): HATA - $SOURCE_DIR yedeklenirken sorun olustu. Exit code: $EXIT_CODE" | tee -a "$LOG_FILE"
BACKUP_EXIT_CODE=$EXIT_CODE
else
echo "$(date): $SOURCE_DIR basariyla yedeklendi." | tee -a "$LOG_FILE"
fi
else
echo "$(date): UYARI - $SOURCE_DIR dizini bulunamadi, atlanıyor." | tee -a "$LOG_FILE"
fi
done
# Sonuc bildirimi
if [ $BACKUP_EXIT_CODE -ne 0 ]; then
echo "$(date): Yedekleme HATALARLA tamamlandi." | tee -a "$LOG_FILE"
echo "Yedekleme hata ile tamamlandi. Log: $LOG_FILE" | mail -s "HATA: $(hostname) Yedekleme Basarisiz" "$EMAIL"
else
echo "$(date): Yedekleme basariyla tamamlandi." | tee -a "$LOG_FILE"
fi
echo "========================================" | tee -a "$LOG_FILE"
Script’i kaydedin ve çalıştırılabilir yapın:
sudo chmod +x /usr/local/bin/rclone_backup.sh
Script’i Test Etmek
Cron’a eklemeden önce script’i elle çalıştırıp test edin. Bu adımı atlamak, haftalarca hatalı çalışan bir sistemin farkında olmamak anlamına gelir.
# Once dry-run ile test edin (gercekten kopyalamaz, ne yapacagini gosterir)
rclone copy /var/www b2-backup:test-bucket/var/www --dry-run --log-level INFO
# Gercek test
sudo /usr/local/bin/rclone_backup.sh
# Log'u kontrol edin
tail -50 /var/log/rclone/backup_*.log
Dry-run çıktısını inceleyin. Yanlış dizinler mi var, exclude kuralları doğru çalışıyor mu, bağlantı kuruluyor mu? Bunların hepsini bu aşamada yakalayın.
Cron Job Kurulumu
Artık asıl konuya gelebiliriz. Cron için iki yöntem var: crontab -e ile kullanıcı bazlı cron, ya da /etc/cron.d/ altına dosya koymak. Production sunucularda ikincisini tercih ediyorum çünkü versiyon kontrolüne almak daha kolay ve hangi kullanıcıyla çalıştığı açıkça görülüyor.
Cron syntax’ını hatırlayalım. Format şu şekilde: dakika, saat, ayın günü, ay, haftanın günü.
# /etc/cron.d/rclone-backup dosyasi icin format:
# dk saat gun ay haftanin-gunu kullanici komut
# Her gece 02:30'da calistir
30 2 * * * root /usr/local/bin/rclone_backup.sh
# Her pazar 03:00'te haftalik yedek
0 3 * * 0 root /usr/local/bin/rclone_weekly_backup.sh
# Her saatte bir incremental yedek (kritik sistemler icin)
0 * * * * root /usr/local/bin/rclone_hourly.sh
Dosyayı oluşturalım:
sudo nano /etc/cron.d/rclone-backup
İçine şunu yazın:
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
[email protected]
# Gunluk yedekleme - her gece 02:30
30 2 * * * root /usr/local/bin/rclone_backup.sh >> /var/log/rclone/cron.log 2>&1
# Eski log temizleme - her pazartesi sabah 05:00
0 5 * * 1 root find /var/log/rclone -name "*.log" -mtime +30 -delete
Dosya izinlerini ayarlayın:
sudo chmod 644 /etc/cron.d/rclone-backup
Versiyon Bazlı Yedekleme
Flat yapıda yedek almak güzel ama “3 gün önceki halini geri yükle” diyemiyorsunuz. Bunun için tarih bazlı bir dizin yapısı kurabilirsiniz.
#!/bin/bash
# Tarih bazli yedekleme
TIMESTAMP=$(date +%Y/%m/%d)
BACKUP_SOURCE="/var/www/html"
BACKUP_DEST="b2-backup:sunucu-arsiv/$TIMESTAMP"
LOG_FILE="/var/log/rclone/versioned_$(date +%Y%m%d).log"
echo "$(date): Versiyonlu yedek basliyor - $TIMESTAMP" | tee -a "$LOG_FILE"
rclone copy "$BACKUP_SOURCE" "$BACKUP_DEST"
--log-level INFO
--log-file "$LOG_FILE"
--transfers 4
--retries 3
if [ $? -eq 0 ]; then
echo "$(date): Versiyonlu yedek tamamlandi: $BACKUP_DEST" | tee -a "$LOG_FILE"
else
echo "$(date): HATA: Versiyonlu yedek basarisiz!" | tee -a "$LOG_FILE"
exit 1
fi
# 90 gunden eski arsivreri temizle
echo "$(date): Eski arsivler temizleniyor..." | tee -a "$LOG_FILE"
rclone delete "b2-backup:sunucu-arsiv"
--min-age 90d
--log-level INFO
--log-file "$LOG_FILE"
Bu yapıyla b2-backup:sunucu-arsiv/2024/01/15/ gibi bir hiyerarşi elde edersiniz. Belirli bir güne ait yedeği geri yüklemek istediğinizde tam olarak nereye bakacağınızı bilirsiniz.
Şifreli Yedekleme
Hassas veriler söz konusuysa yedekleri şifrelemeden buluta göndermek ciddi bir güvenlik açığı. Rclone’un crypt remote özelliği tam da bunun için:
# Once crypt remote olusturun
rclone config
# n ile yeni remote
# Isim: b2-backup-encrypted
# Tip: crypt
# Remote: b2-backup:sunucu-sifrelenmis
# Filename encryption: standard
# Directory name encryption: true
# Sifre tanimlayın (cok iyi bir yere kaydedin!)
Yapılandırma tamamlandıktan sonra şifreli remote’u normal gibi kullanırsınız:
rclone copy /etc/nginx b2-backup-encrypted:nginx-config
--log-level INFO
--transfers 2
# Kontrol
rclone ls b2-backup-encrypted:nginx-config
# Dosyalar normal görünür
# B2 tarafinda ise sifreli isimler gorunur
rclone ls b2-backup:sunucu-sifrelenmis
# Anlamsiz karakter dizileri
Önemli Uyarı: Şifreleme parolasını kaybeders eniz yedeklerinize bir daha erişemezsiniz. Parolayı birden fazla güvenli yerde saklayın, bir parola yöneticisinde, bir fiziksel ortamda.
Yedek Durumunu İzlemek
Sistem çalışıyor ama gerçekten çalışıyor mu? Bu soruyu yanıtlamak için basit bir izleme mekanizması ekleyelim.
#!/bin/bash
# Yedek saglik kontrolu
BACKUP_DEST="b2-backup:sunucu-yedek-$(hostname)"
ALERT_EMAIL="[email protected]"
MAX_AGE_HOURS=26 # 24 saat yedek almaliyiz, 2 saat tolerans
echo "=== Yedek Saglik Kontrolu - $(date) ==="
# Son degistirilen dosyanin tarihini kontrol et
LAST_MODIFIED=$(rclone lsl "$BACKUP_DEST" --max-depth 3 2>/dev/null | sort -k2,2 -k3,3 | tail -1)
if [ -z "$LAST_MODIFIED" ]; then
echo "KRITIK: Hedef remote'da hic dosya bulunamadi!"
echo "Yedek bulunamadi veya bos! Kontrol edin." | mail -s "KRITIK: $(hostname) Yedek Yok" "$ALERT_EMAIL"
exit 2
fi
echo "Son dosya bilgisi: $LAST_MODIFIED"
# Remote boyutunu raporla
echo ""
echo "Toplam yedek boyutu:"
rclone size "$BACKUP_DEST" 2>/dev/null
echo ""
echo "Son 10 degistirilen dosya:"
rclone lsl "$BACKUP_DEST" --max-depth 5 2>/dev/null | sort -k2,2 -k3,3 | tail -10
Bu script’i de cron’a ekleyebilirsiniz, örneğin her sabah 08:00’de çalışsın ve siz işe geldiğinizde durumu göresiniz.
# /etc/cron.d/rclone-backup dosyasina ekle
0 8 * * * root /usr/local/bin/rclone_health_check.sh | mail -s "$(hostname) Gunluk Yedek Raporu" [email protected]
Gerçek Dünya Senaryosu: Web Sunucusu Yedekleme
Bir web sunucusunda çalıştığımızı varsayalım. Nginx config’leri, web dosyaları ve veritabanı dumpları var. İşte pratik bir senaryo:
#!/bin/bash
# Web sunucusu kapsamli yedekleme
HOSTNAME=$(hostname -s)
DATE=$(date +%Y%m%d)
BACKUP_ROOT="b2-backup:web-sunucu-$HOSTNAME"
LOG_FILE="/var/log/rclone/web_backup_$DATE.log"
TEMP_DIR="/tmp/db_dumps"
mkdir -p "$TEMP_DIR"
mkdir -p "/var/log/rclone"
echo "$(date): Web sunucusu yedeklemesi baslıyor..." | tee -a "$LOG_FILE"
# 1. MySQL/MariaDB dump
if command -v mysqldump &>/dev/null; then
echo "$(date): Veritabanlari dump ediliyor..." | tee -a "$LOG_FILE"
mysql -N -e "show databases;" 2>/dev/null | grep -v "information_schema|performance_schema|sys" | while read DB; do
DUMP_FILE="$TEMP_DIR/${DB}_${DATE}.sql.gz"
mysqldump --single-transaction --routines --triggers "$DB" 2>/dev/null | gzip > "$DUMP_FILE"
if [ $? -eq 0 ]; then
echo "$(date): $DB dump alindi: $DUMP_FILE" | tee -a "$LOG_FILE"
else
echo "$(date): HATA: $DB dump alinamadi!" | tee -a "$LOG_FILE"
fi
done
# Dump'lari buluta yukle
rclone copy "$TEMP_DIR" "$BACKUP_ROOT/databases/$DATE"
--log-level INFO
--log-file "$LOG_FILE"
--transfers 2
fi
# 2. Nginx config ve web dosyalari
rclone copy /etc/nginx "$BACKUP_ROOT/configs/nginx"
--log-level INFO --log-file "$LOG_FILE" --transfers 2
rclone copy /var/www/html "$BACKUP_ROOT/webroot"
--log-level INFO --log-file "$LOG_FILE"
--transfers 4
--exclude "*.log"
--exclude "cache/**"
--exclude "tmp/**"
--exclude "*.tmp"
# 3. SSL sertifikalari (sifreli remote kullanin!)
rclone copy /etc/letsencrypt "$BACKUP_ROOT/ssl"
--log-level INFO
--log-file "$LOG_FILE"
--transfers 2
# Gecici dosyalari temizle
rm -rf "$TEMP_DIR"
echo "$(date): Web sunucusu yedeklemesi tamamlandi." | tee -a "$LOG_FILE"
Sık Yapılan Hatalar
PATH sorunu: Cron kısıtlı bir PATH ile çalışır. Script’inizin en üstüne PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin ekleyin, yoksa rclone bulunamıyor hatası alırsınız.
Konfigürasyon dosyası yolu: Cron, root olarak çalışıyorsa ve siz rclone’u normal kullanıcı olarak kurduysanız, konfigürasyon dosyası farklı yerde olabilir. RCLONE_CONFIG=/root/.config/rclone/rclone.conf şeklinde ortam değişkeni set edin ya da root kullanıcısı için ayrıca rclone config çalıştırın.
Büyük dosya transferleri: --transfers değerini bant genişliğinize göre ayarlayın. Çok yüksek ayarlarsanız sunucunuzu felç edebilirsiniz. Gece çalışan yedekler için 4-8 arası makul.
Bant genişliği sınırlama: Yedekleme gündüz çalışıyorsa veya bant genişliği kısıtlıysa --bwlimit 10M gibi bir limit koyun.
Zaman dilimi: Cron sistem saatiyle çalışır. timedatectl ile zaman diliminizin doğru ayarlı olduğundan emin olun. Aksi hâlde yedek tam olmaması gereken saatte başlayabilir.
Sonuç
Rclone ve Cron kombinasyonu, minimal karmaşıklıkla maksimum güvenilirlik sağlayan bir çift. Ticari yedekleme araçlarına para ödemeden, kurumsal düzeyde bir yedekleme sistemi kurabiliyorsunuz.
Özetlemek gerekirse:
- Rclone’u kurun ve remote’unuzu yapılandırın
- Kapsamlı bir shell script yazın (lock dosyası, loglama, hata yönetimi ile)
/etc/cron.d/altına cron job ekleyin- Script’i elle test edin, dry-run kullanın
- Log’ları düzenli kontrol edin veya sağlık kontrolü script’i ekleyin
- Hassas veriler için
cryptremote kullanın
Son olarak ve bu gerçekten önemli: Yedek aldığınızı sanmak ile gerçekten yedeklemiş olmak farklı şeyler. Ayda en az bir kez yedekten geri yükleme testi yapın. Geri yükleyemediğiniz bir yedek, yedek değildir.
