Arşivleme İşlemlerini Otomatikleştirme: cron ve tar ile Zamanlanmış Yedekleme Kurulumu

Yedekleme işi hep “yarın yaparım” denen şeylerden biridir. Ta ki bir şeyler gidene kadar. Ben bu işi yıllardır yapıyorum ve en acı dersleri hep yedekleme olmayan ortamlarda yaşadım. Artık her yeni sunucu kurduğumda ilk yaptığım şeylerden biri otomatik arşivleme kurmak. Bu yazıda cron ve tar ikilisini kullanarak nasıl sağlam bir zamanlanmış yedekleme sistemi kurabileceğinizi adım adım anlatacağım.

Temeli Anlamak: tar Neden Hala Geçerli?

Belki daha modern araçlar var, rsync var, restic var, borgbackup var. Ama tar hala işin merkezinde. Neden? Çünkü neredeyse her Linux sisteminde kurulu geliyor, bağımlılığı yok, çıktısı taşınabilir ve ne yaptığını tam olarak biliyorsunuz. Karmaşık bir yedekleme çözümü kurup sonra onu yönetmek için ayrı bir iş çıkarmak yerine, tar ile işinizi basit tutabilirsiniz.

tar komutunun temel parametrelerini hatırlayalım:

  • -c: Yeni arşiv oluşturur (create)
  • -x: Arşivi açar (extract)
  • -z: gzip sıkıştırması kullanır
  • -j: bzip2 sıkıştırması kullanır
  • -J: xz sıkıştırması kullanır
  • -v: İşlem sırasında dosyaları listeler (verbose)
  • -f: Arşiv dosyasının adını belirtir
  • -p: Dosya izinlerini korur
  • –exclude: Belirli dosya veya dizinleri dışarıda bırakır
  • -C: Hedef dizini belirtir

Basit bir arşiv oluşturma örneği:

tar -czf yedek_$(date +%Y%m%d).tar.gz /var/www/html/

Bu komut /var/www/html/ dizinini alır, gzip ile sıkıştırır ve dosya adına bugünün tarihini ekler. Basit ama etkili.

İlk Gerçek Senaryo: Web Sunucusu Yedeklemesi

Diyelim ki bir LAMP sunucunuz var. /var/www/html altında site dosyalarınız var, /etc/apache2 veya /etc/nginx altında yapılandırmalarınız var. Bunları her gece yedeklemek istiyorsunuz.

Önce yedeklerin tutulacağı dizini oluşturalım:

mkdir -p /backup/web
chmod 700 /backup/web

İzinlere dikkat edin. Yedekler içinde veritabanı şifreleri, SSL anahtarları olabilir. 700 yani sadece root okuyabilsin.

Şimdi basit bir yedekleme komutu deneyelim:

tar -czf /backup/web/web_$(date +%Y%m%d_%H%M%S).tar.gz 
    --exclude='/var/www/html/cache' 
    --exclude='/var/www/html/tmp' 
    --exclude='*.log' 
    /var/www/html/ 
    /etc/nginx/

--exclude parametrelerini özellikle belirttim. Cache ve geçici dosyaları yedeklemenin anlamı yok, sadece yer kaplar. Log dosyaları da genelde arşive girmemeli, ayrı bir log yönetimi stratejiniz olmalı.

Yedekleme Scriptini Yazmak

Tek satır komut işe yarasa da gerçek hayatta bir script yazmanız daha mantıklı. Çünkü hata kontrolü eklemek isteyeceksiniz, log tutmak isteyeceksiniz, eski yedekleri temizlemek isteyeceksiniz.

#!/bin/bash

# Yedekleme scriptini /usr/local/bin/web_backup.sh olarak kaydedin

BACKUP_DIR="/backup/web"
SOURCE_DIRS="/var/www/html /etc/nginx /etc/ssl/private"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="${BACKUP_DIR}/web_backup_${DATE}.tar.gz"
LOG_FILE="/var/log/backup/web_backup.log"
KEEP_DAYS=7

# Log dizini yoksa oluştur
mkdir -p /var/log/backup
mkdir -p "${BACKUP_DIR}"

log_message() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "${LOG_FILE}"
}

log_message "Yedekleme basliyor..."

# tar ile yedekleme
if tar -czpf "${BACKUP_FILE}" 
    --exclude='/var/www/html/cache' 
    --exclude='/var/www/html/tmp' 
    --exclude='*.log' 
    ${SOURCE_DIRS} 2>> "${LOG_FILE}"; then
    
    BOYUT=$(du -sh "${BACKUP_FILE}" | cut -f1)
    log_message "BASARILI: ${BACKUP_FILE} olusturuldu. Boyut: ${BOYUT}"
else
    log_message "HATA: Yedekleme basarisiz oldu!"
    exit 1
fi

# Eski yedekleri temizle
SILINEN=$(find "${BACKUP_DIR}" -name "web_backup_*.tar.gz" 
    -mtime +${KEEP_DAYS} -delete -print | wc -l)
log_message "${SILINEN} eski yedek silindi."

log_message "Yedekleme tamamlandi."

Script’i çalıştırılabilir yapın:

chmod 750 /usr/local/bin/web_backup.sh

Bir kez elle çalıştırın ve kontrol edin:

/usr/local/bin/web_backup.sh
cat /var/log/backup/web_backup.log

cron’u Anlamak ve Doğru Kullanmak

cron daemon’u sistem başladığında çalışır ve /etc/crontab, /etc/cron.d/ ve kullanıcıların crontab dosyalarını takip eder. Bir de /etc/cron.daily, /etc/cron.weekly gibi dizinler var ama bunları iş kritik yedeklemeler için önermiyorum çünkü tam olarak ne zaman çalışacağını kontrol edemiyorsunuz.

cron zaman formatını bir kez kavrayınca unutmuyorsunuz:

  • Dakika: 0-59
  • Saat: 0-23
  • Ayın günü: 1-31
  • Ay: 1-12
  • Haftanın günü: 0-7 (0 ve 7 Pazar)

Özel değerler:

  • *: Her değer
  • ,: Birden fazla değer (1,3,5)
  • : Aralık (1-5)
  • /: Adımlama (*/5 her 5 dakikada)

Root’un crontab’ını düzenlemek için:

crontab -e

Birkaç örnek giriş:

# Her gece saat 02:30'da web yedeklemesi
30 2 * * * /usr/local/bin/web_backup.sh

# Her Pazar sabah 03:00'te haftalik tam yedek
0 3 * * 0 /usr/local/bin/full_backup.sh

# Her saat basinda veritabani yedegi
0 * * * * /usr/local/bin/db_backup.sh

# Her 6 saatte bir log arsivleme
0 */6 * * * /usr/local/bin/log_archive.sh

Bir önemli nokta: cron job’larınızın çıktısını bir yere yönlendirin. Yoksa cron mail göndermeye çalışır, bu da sistemlerde sorun yaratabilir.

30 2 * * * /usr/local/bin/web_backup.sh >> /var/log/backup/cron.log 2>&1

Artan (Incremental) Yedekleme Stratejisi

Her gece tam yedek almak disk alanını hızla bitirir. Daha akıllı bir strateji: Haftada bir tam yedek, her gün sadece değişen dosyaların yedeği.

tar ile bu mümkün. --listed-incremental parametresi bunu sağlar:

#!/bin/bash

BACKUP_DIR="/backup/incremental"
SOURCE="/var/www/html"
SNAPSHOT_FILE="/backup/.snapshot_web"
DATE=$(date +%Y%m%d)
DOW=$(date +%u)  # 1=Pazartesi, 7=Pazar

mkdir -p "${BACKUP_DIR}"

if [ "${DOW}" -eq 7 ]; then
    # Pazar: tam yedek, snapshot sifirla
    log_message "Haftalik tam yedek basliyor..."
    rm -f "${SNAPSHOT_FILE}"
    tar -czpf "${BACKUP_DIR}/full_${DATE}.tar.gz" 
        --listed-incremental="${SNAPSHOT_FILE}" 
        "${SOURCE}"
    echo "Tam yedek alindi: full_${DATE}.tar.gz"
else
    # Diger gunler: artimsal yedek
    tar -czpf "${BACKUP_DIR}/incr_${DATE}.tar.gz" 
        --listed-incremental="${SNAPSHOT_FILE}" 
        "${SOURCE}"
    echo "Artimsal yedek alindi: incr_${DATE}.tar.gz"
fi

Bu stratejiyle Pazar günü tam yedek alınır, snapshot dosyası oluşturulur. Diğer günler tar, snapshot’taki bilgiye bakarak sadece değişen dosyaları arşive ekler. Hem disk alanı hem de zaman kazanırsınız.

Veritabanını da İşin İçine Katmak

Web dosyalarını yedeklemek yetmez, veritabanını da almak gerekir. MySQL/MariaDB için mysqldump’ı tar ile birleştiren bir örnek:

#!/bin/bash

DB_USER="backup_user"
DB_PASS="guclu_bir_sifre"
DB_HOST="localhost"
BACKUP_DIR="/backup/database"
DATE=$(date +%Y%m%d_%H%M%S)
LOG_FILE="/var/log/backup/db_backup.log"

mkdir -p "${BACKUP_DIR}"

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

# Tum veritabanlarini listele (sistem databaseleri haric)
DATABASES=$(mysql -u"${DB_USER}" -p"${DB_PASS}" -h"${DB_HOST}" 
    -e "SHOW DATABASES;" 2>/dev/null | 
    grep -Ev "(Database|information_schema|performance_schema|mysql|sys)")

for DB in ${DATABASES}; do
    OUTPUT_FILE="${BACKUP_DIR}/${DB}_${DATE}.sql.gz"
    
    if mysqldump -u"${DB_USER}" -p"${DB_PASS}" -h"${DB_HOST}" 
        --single-transaction 
        --routines 
        --triggers 
        "${DB}" 2>>"${LOG_FILE}" | gzip > "${OUTPUT_FILE}"; then
        
        BOYUT=$(du -sh "${OUTPUT_FILE}" | cut -f1)
        log_message "OK: ${DB} -> ${OUTPUT_FILE} (${BOYUT})"
    else
        log_message "HATA: ${DB} yedeklenemedi!"
    fi
done

# 14 gunden eski db yedeklerini temizle
find "${BACKUP_DIR}" -name "*.sql.gz" -mtime +14 -delete

log_message "Veritabani yedeklemesi tamamlandi."

--single-transaction parametresi InnoDB tabloları için çok önemli. Yedekleme sırasında tabloları kilitlemeden tutarlı bir snapshot alıyor.

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

Yedek aldınız, güzel. Ama o yedek gerçekten açılıyor mu? Bu soruyu sormayan adminlerin dramını çok gördüm. Yedekleme scriptinize bir doğrulama adımı ekleyin:

#!/bin/bash

# Yedek dogrulama scripti
BACKUP_DIR="/backup/web"
LOG_FILE="/var/log/backup/verify.log"

log_message() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "${LOG_FILE}"
}

# Son 24 saatte olusturulan yedekleri dogrula
find "${BACKUP_DIR}" -name "*.tar.gz" -mtime -1 | while read -r BACKUP_FILE; do
    log_message "Dogrulanıyor: ${BACKUP_FILE}"
    
    # tar -t ile arsiv icerigi listele, hata cikti mi bak
    if tar -tzf "${BACKUP_FILE}" > /dev/null 2>&1; then
        DOSYA_SAYISI=$(tar -tzf "${BACKUP_FILE}" | wc -l)
        log_message "GECERLI: ${BACKUP_FILE} - ${DOSYA_SAYISI} dosya"
    else
        log_message "BOZUK ARSIV: ${BACKUP_FILE}"
        # Buraya email bildirimi eklenebilir
        echo "UYARI: ${BACKUP_FILE} arsivi bozuk!" | 
            mail -s "Yedek Dogrulama Hatasi" [email protected]
    fi
done

Bu scripti de cron’a ekleyin, yedekleme işleminden birkaç saat sonra çalışsın:

# Web yedegi her gece 02:30
30 2 * * * /usr/local/bin/web_backup.sh >> /var/log/backup/cron.log 2>&1

# Dogrulama her sabah 06:00
0 6 * * * /usr/local/bin/verify_backup.sh >> /var/log/backup/cron.log 2>&1

Uzak Sunucuya Yedek Kopyalamak

Yerel yedek güzel ama sunucu fiziksel olarak zarar görürse ne olacak? Yedeklerinizi farklı bir lokasyona kopyalamanız şart. rsync ile bu oldukça basit:

#!/bin/bash

LOCAL_BACKUP="/backup"
REMOTE_USER="backup"
REMOTE_HOST="uzak-sunucu.sirket.com"
REMOTE_DIR="/backup/sunucu1"
SSH_KEY="/root/.ssh/backup_key"
LOG_FILE="/var/log/backup/rsync.log"

log_message() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "${LOG_FILE}"
}

log_message "Uzak yedek transferi basliyor..."

if rsync -avz --delete 
    -e "ssh -i ${SSH_KEY} -o StrictHostKeyChecking=no" 
    "${LOCAL_BACKUP}/" 
    "${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_DIR}/" >> "${LOG_FILE}" 2>&1; then
    
    log_message "Transfer basarili."
else
    log_message "Transfer BASARISIZ!"
fi

SSH key oluşturup yetkisiz erişimi engellemek için:

ssh-keygen -t ed25519 -f /root/.ssh/backup_key -N ""
ssh-copy-id -i /root/.ssh/backup_key.pub [email protected]

Cron Job’ları İzlemek ve Hata Ayıklamak

Cron job çalışmıyor mu? Birkaç kontrol noktası:

Cron daemon’unun çalışıp çalışmadığını kontrol edin:

systemctl status cron
# ya da
systemctl status crond

Cron loglarını inceleyin:

grep CRON /var/log/syslog | tail -20
# RedHat tabanlı sistemlerde
grep CRON /var/log/cron | tail -20

Cron ortamının login shell’den farklı olduğunu unutmayın. PATH değişkeni eksik olabilir. Scriptlerinizin başına ekleyin:

#!/bin/bash
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

Ya da crontab’ın başına:

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

30 2 * * * /usr/local/bin/web_backup.sh

Pratik Notlar ve Sık Yapılan Hatalar

Yıllar içinde gördüğüm bazı yaygın hatalar:

Yedekleri yedeklenen sistemde tutmak: Sunucu patlarsa yedeğe ne kadar erişebilirsiniz? Mutlaka farklı bir lokasyona kopyalayın.

Yedek boyutunu takip etmemek: Disk dolunca yedekler sessizce başarısız olmaya başlar. Disk kullanımını izleyin.

Retention politikası olmamak: Sonsuza kadar yedek biriktirmek disk bitirir. Kaç günlük yedek tutacağınıza karar verin ve otomatik temizlik ekleyin.

Yedek saatini iş saatiyle çakıştırmak: Gece 02:00-04:00 genellikle en uygun saattir. Eğer cron job’larınız gündüz çalışıyorsa sunucuya yük binebilir.

Script çıktısını kontrol etmemek: “Çalışıyor mu?” sorusunun cevabı log dosyasında. Günlük log rotasyonu da ekleyin.

Logrotate için basit bir konfigürasyon:

# /etc/logrotate.d/backup
/var/log/backup/*.log {
    daily
    rotate 30
    compress
    delaycompress
    missingok
    notifempty
}

Sonuç

Cron ve tar kombinasyonu belki glamourlu değil ama güvenilir. Yıllardır binlerce sunucuda test edilmiş, davranışı öngörülebilir, sorun çıktığında debug etmesi kolay. Daha gelişmiş senaryolarda borgbackup veya restic gibi araçlara geçmek mantıklı olabilir, deduplikasyon ve şifreleme özelliklerini takdir ediyorum. Ama temel bir yedekleme altyapısı kurmak için hala tar ve cron ile başlamak en doğrusu.

Bu yazıda anlattıklarını bir araya getirirseniz elinizde şunlar olacak: Günlük web ve veritabanı yedekleri, artımlı yedekleme ile disk tasarrufu, bütünlük doğrulaması, uzak lokasyona otomatik transfer ve temiz log kaydı. Bunları kurmak için gereken süre iki-üç saat, karşılığında aldığınız gece rahat uyuma priceless.

Son bir şey: Kurduğunuz yedekleme sistemini test edin. Gerçekten bir dizini silip yedeğinden geri yükleyin. Yedeklemenin çalıştığını sadece log dosyasından değil, gerçek bir restore işlemiyle doğrulayın. Çünkü test edilmemiş yedek, yedek değildir.

Bir yanıt yazın

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