KOBİ’lerde ERP ya da CRM sistemi hakkında “yedeğimiz var mı?” diye sorulduğunda cevap neredeyse her zaman “var” olur. Asıl soru başka: Sunucu bu gece çökse, bir fidye yazılımı dosyaları kilitlese ya da biri yanlışlıkla toplu güncelleme yapsa, sistemi kaç saatte ve hangi ana geri getirebilirsiniz? Bu soruya sayıyla cevap veremeyen bir işletmenin elinde yedek yoktur, umut vardır.
Bu yazının tezi şu: Yedek, geri yüklenebildiği bir provayla kanıtlanana kadar yalnızca bir dosyadır. Aşağıda bir KOBİ ERP’si için hedef belirlemeden geri yükleme provasına kadar adım adım bir yaklaşım, bir kontrol tablosu ve çalıştırarak test ettiğim küçük bir denetim betiği bulacaksınız.
Neden zor? Yedek almak kolay, geri dönmek değil
Yedek almak tek komutla başlar; zorluk, o komutun sessizce yanlış şeyi yapabilmesidir. KOBİ projelerinde sorun çoğu zaman teknik bilgisizlik değil, sorumluluğun dağınıklığıdır. Yedeği hosting firması, uygulamayı yazılımcı, veriyi muhasebe “sahiplenir”; geri yüklemeyi kimse denemez.
İkinci zorluk, ERP’nin tek bir veritabanından ibaret olmamasıdır. Fatura XML ve PDF dosyaları, teklif ekleri, ürün görselleri bir dosya deposunda; entegrasyon kullanıcıları ve şifreleme anahtarı yapılandırma dosyasında durur. Laravel’in şifreleme altyapısı uygulama anahtarına (APP_KEY) bağlıdır; veritabanını eksiksiz geri getirip anahtarı kaybederseniz şifreli alanları okuyamazsınız.
Üçüncüsü saldırganlar. ABD siber güvenlik ajansı CISA’nın #StopRansomware Rehberi, birçok fidye yazılımının erişebildiği yedekleri bulup silmeye çalıştığını, bu yüzden kritik verinin çevrim dışı ve şifreli yedeklerinin tutulması ve bu yedeklerin erişilebilirlik ve bütünlük açısından düzenli test edilmesi gerektiğini yazar. Aynı sunucuda, aynı yetkiyle duran bir yedek, saldırgan için sadece bir sonraki hedeftir.
Adım adım yaklaşım
1. Hedefi iş diliyle koyun: RPO ve RTO
NIST SP 800-34’teki tanımlarla iki sayı belirleyin. RPO (kurtarma noktası hedefi) verinin bir kesintiden sonra geri getirilmesi gereken zaman noktasıdır; yani en fazla ne kadar veri kaybını göze alabildiğiniz. RTO (kurtarma süresi hedefi) ise sistemin iş süreçlerine zarar vermeden kurtarma aşamasında kalabileceği toplam süredir.
Bu sayıları yazılımcı değil, işi yöneten kişi vermelidir. “Gecelik yedek yeter” demek, RPO’nun 24 saat olduğunu, yani bir günlük siparişi, irsaliyeyi ve tahsilatı yeniden girmeyi kabul ettiğinizi söylemektir. Satış ekibi gün içinde yüzlerce teklif giriyorsa bu kabul edilebilir olmayabilir; o zaman gecelik tam yedeğin yanına gün içi değişiklik kaydı gerekir.
2. Neyi yedeklediğinizin envanterini çıkarın
“Veritabanını yedekliyoruz” cümlesi eksik bir envanterdir. Bir KOBİ ERP’si için en az şu dört kalem listelenmelidir:
- Veritabanı: Cari, stok, sipariş, fatura, kullanıcı ve yetki tabloları.
- Dosya deposu: e-Belge XML/PDF’leri, teklif ekleri, imzalı sözleşme taramaları.
- Yapılandırma ve gizli anahtarlar:
.env,APP_KEY, entegratör ve banka API bilgileri. Bunlar ayrı ve daha sıkı korunan bir kasada tutulur; yedek arşivine düz metin olarak girmez. - Kurulum bilgisi: Sunucu paketleri, PHP sürümü, zamanlanmış görevler, kuyruk çalışanları. CISA rehberi buna kritik sistemlerin güncel “altın imajlarını” tutmak der; küçük bir işletmede bu, sunucuyu sıfırdan kuran yazılı bir betik ya da belgedir.
3. Veritabanı yedeğini tutarlı alın
MySQL’de en yaygın yöntem mysqldump‘tır. MySQL 8.4 belgelerine göre InnoDB tablolarında --single-transaction tutarlı okuma kullanır ve yedek boyunca başka istemcilerin yaptığı değişiklikler döküme karışmaz. Aynı belge, artımlı yedeğin ikili günlükte (binary log) tutulduğunu, tam yedek alınırken günlüğün kapatılıp yenisinin açılması (--flush-logs) hâlinde sonraki günlük dosyalarının yedekten sonraki tüm değişiklikleri içereceğini anlatır. RPO’yu 24 saatin altına indirmenin yolu budur.
#!/usr/bin/env bash
# Kimlik bilgileri komut satırında değil, ~/.my.cnf (chmod 600) içinde durur.
set -euo pipefail
TARIH=$(date +%F)
HEDEF="/yedek/erp-$TARIH.sql.gz"
mysqldump --single-transaction --flush-logs --source-data=2 \
--routines --events --databases erp | gzip > "$HEDEF"
sha256sum "$HEDEF" > "$HEDEF.sha256"
--source-data=2, dökümün başına hangi günlük dosyasından ve konumdan devam edileceğini yorum satırı olarak yazar; belirli bir ana dönmeniz gerektiğinde başlangıç noktanız odur. Bu seçeneklerin çalışması için sunucuda ikili günlüğün açık olması ve yedek kullanıcısının gerekli yetkilere sahip olması gerekir; kurulumunuzda önce prova ortamında deneyin.
4. 3-2-1 kuralı ve çevrim dışı kopya
Yaygın kabul gören 3-2-1 kuralı şunu söyler: Verinin en az üç kopyası, iki farklı ortamda, biri de işletme dışında olsun. Bence KOBİ için asıl kritik kısım “işletme dışında” değil, “erişilemez” olmasıdır. Ana sunucudaki bir hesabın silemeyeceği, değiştiremeyeceği bir kopya gerekir: haftalık çıkarılıp kilitli dolapta duran şifreli bir disk ya da sürüm kilitli bir nesne deposu. CISA, değiştirilemez (immutable) depolamanın her mevzuatın uyum şartını karşılamayabileceği ve yanlış yapılandırmanın maliyetli olabileceği konusunda ayrıca uyarır.
5. Yedeğe erişimi daraltın
Yedek dosyası, canlı veritabanının bütün kişisel verilerini taşır. KVKK m.12, veri sorumlusuna kişisel verilere hukuka aykırı erişimi önleme ve verinin muhafazasını sağlama yükümlülüğü verir. Kurumun Kişisel Veri Güvenliği Rehberi (Ocak 2018 baskısı) yedekleme bölümünde yedeklenen kişisel verilerin yalnızca sistem yöneticisinin erişebileceği biçimde tutulmasını, veri seti yedeklerinin ağ dışında saklanmasını ve fiziksel güvenliğin sağlanmasını önerir. ERP yetki matrisi yazısında anlattığım ilke burada da geçerli: Satış ekibinin göremediği müşteri verisini, herkesin erişebildiği bir yedek klasöründe bırakmak matrisi anlamsızlaştırır.
6. Yedeği her gün otomatik denetleyin
“Yedek görevi hata vermedi” ile “yedek sağlam” aynı şey değildir. Disk dolduğunda yarım kalan bir döküm, yanlış veritabanına bağlanan bir görev ya da sıkıştırma sırasında bozulan bir dosya sessizce birikebilir. En az üç şeyi her gün otomatik kontrol edin: son yedeğin yaşı, dosyanın bütünlüğü ve boyutunun bir önceki güne göre ani düşüşü.
Aşağıdaki Python betiği, yedek görevinin her çalışmada yazdığı bir manifest.json dosyasını okuyup bu üç kontrolü yapar ve sorun bulursa sıfırdan farklı kodla çıkar; zamanlayıcınız bu kodu bir uyarıya bağlayabilir. Betiği sağlam, eski, bozuk ve küçülmüş yedek senaryolarıyla çalıştırarak test ettim.
#!/usr/bin/env python3
"""Gecelik ERP yedeğini denetler: yaş, boyut düşüşü ve SHA-256 bütünlüğü."""
import hashlib
import json
import sys
import time
from pathlib import Path
MAKS_YAS_SAAT = 26 # gecelik yedek + 2 saat tolerans
MIN_BOYUT_ORANI = 0.80 # dünküne göre %20'den fazla küçülme şüphelidir
def sha256(dosya: Path) -> str:
h = hashlib.sha256()
with dosya.open("rb") as f:
for parca in iter(lambda: f.read(1024 * 1024), b""):
h.update(parca)
return h.hexdigest()
def denetle(klasor: Path) -> list[str]:
manifest = json.loads((klasor / "manifest.json").read_text(encoding="utf-8"))
sorunlar = []
yedekler = sorted(manifest["yedekler"], key=lambda y: y["zaman"])
son = yedekler[-1]
dosya = klasor / son["dosya"]
if not dosya.exists():
return [f"Son yedek dosyası yok: {son['dosya']}"]
yas_saat = (time.time() - dosya.stat().st_mtime) / 3600
if yas_saat > MAKS_YAS_SAAT:
sorunlar.append(f"Son yedek {yas_saat:.1f} saatlik (sınır {MAKS_YAS_SAAT})")
if sha256(dosya) != son["sha256"]:
sorunlar.append("SHA-256 tutmuyor: dosya bozulmuş ya da değiştirilmiş")
if len(yedekler) > 1:
onceki = yedekler[-2]["boyut"]
if onceki and son["boyut"] / onceki < MIN_BOYUT_ORANI:
sorunlar.append(f"Boyut düştü: {onceki} -> {son['boyut']} bayt")
return sorunlar
if __name__ == "__main__":
sonuc = denetle(Path(sys.argv[1]))
for s in sonuc:
print("UYARI:", s)
print("TAMAM" if not sonuc else f"{len(sonuc)} sorun")
sys.exit(1 if sonuc else 0)
Laravel kullanıyorsanız spatie/laravel-backup paketinin backup:monitor komutu benzer bir iş görür: MaximumAgeInDays ve MaximumStorageInMegabytes sağlık kontrolleriyle yedeğin yaşını ve toplam boyutunu izler. Paket belgeleri, izleyicinin mümkünse ayrı bir kurulumda ve ayrı bir sunucuda çalıştırılmasını önerir; yedeklenen uygulama çöktüğünde de uyarı alabilmek için bu mantıklıdır.
7. Ayda bir geri yükleme provası yapın ve süreyi ölçün
Otomatik denetim dosyanın sağlam olduğunu söyler, sistemin ayağa kalkacağını söylemez. Bunu öğrenmenin tek yolu provadır: Ayrı bir prova sunucusunda yedeği geri yükleyin, uygulamayı ona bağlayın, birkaç bilinen kaydı kontrol edin ve geçen süreyi not edin. Ölçtüğünüz süre RTO’nuzdan uzunsa, bunu kesinti gününde değil prova gününde öğrenmiş olursunuz.
#!/usr/bin/env bash
set -euo pipefail
[[ "$(hostname)" == *prova* ]] || { echo "Yalnızca prova sunucusunda çalışır"; exit 1; }
YEDEK="$1" # ör. /yedek/erp-2026-11-09.sql.gz
BASLA=$(date +%s)
sha256sum -c "$YEDEK.sha256"
mysql -e "DROP DATABASE IF EXISTS erp; CREATE DATABASE erp;"
gunzip -c "$YEDEK" | mysql
mysql -N -e "SELECT COUNT(*), MAX(created_at) FROM erp.faturalar;"
echo "Geri yükleme süresi: $(( $(date +%s) - BASLA )) sn"
Betiğin başındaki sunucu adı kontrolü bilinçli bir emniyettir: DROP DATABASE içeren bir komutun yanlış sunucuda çalışması, korunmaya çalıştığınız felaketi kendi elinizle yaratmak olur. Provada son fatura tarihini ve kayıt sayısını, aynı günün canlı sistem raporuyla karşılaştırın; bir de rastgele seçtiğiniz bir faturanın PDF’ini dosya deposundan açmayı deneyin.
Kontrol tablosu
| Bileşen | Ne yedeklenir | Önerilen sıklık | Nasıl doğrulanır |
|---|---|---|---|
| Veritabanı | Tam döküm + ikili günlük | Gecelik tam, gün içi günlük | Günlük otomatik denetim, aylık prova |
| Dosya deposu | e-Belge, ekler, taramalar | Gecelik artımlı | Provada rastgele dosya açma |
| Gizli anahtarlar | APP_KEY, API bilgileri | Her değişiklikte | Ayrı kasada; provada uygulama açılıyor mu |
| Kurulum | Sunucu betiği, zamanlanmış görevler | Her değişiklikte | Yılda bir sıfırdan kurulum provası |
| Çevrim dışı kopya | Haftalık şifreli arşiv | Haftalık | Çeyrekte bir bu kopyadan geri yükleme |
Tablodaki sıklıklar başlangıç önerisidir; asıl ölçü birinci adımda belirlediğiniz RPO ve RTO’dur.
Karşı görüş: “Bulut sağlayıcımız zaten yedekliyor”
Bu itirazın haklı bir yanı var: Yönetilen veritabanı hizmetleri otomatik anlık görüntü alır ve çoğu KOBİ’nin kendi kurabileceğinden daha sağlam bir altyapı sunar. Kanaatimce eksik kalan nokta, bu görüntülerin genellikle aynı hesapta ve aynı yetkilerle durmasıdır. Yönetici hesabı ele geçirilirse ya da faturası ödenmeyen hesap askıya alınırsa, sunucu ile yedek birlikte gider. Ayrıca sağlayıcı sunucuyu geri getirir; sizin dosya deponuzu, anahtarlarınızı ve uygulamanızın doğru çalıştığını geri getirmez. Sağlayıcı yedeğini birinci kopya sayın, tek kopya değil.
Sık yapılan hatalar
- Yedeği aynı sunucuda tutmak. Disk arızası ya da fidye yazılımı ikisini birden götürür.
- Görev başarılı göründüğü için kontrol etmemek. Sıfır baytlık dosya da “başarıyla” oluşturulmuş olabilir.
- Dosya deposunu ve anahtarı unutmak. Veritabanı döner, faturaların PDF’leri ve şifreli alanlar dönmez.
- Hiç prova yapmamak. Geri yükleme süresini ilk kez kesinti günü öğrenmek, RTO’yu tahmin etmek demektir.
- Yedek klasörünü herkese açık bırakmak. Yetki matrisinin dışına çıkan her kopya, KVKK açısından ayrı bir risk noktasıdır.
- Saklama süresini düşünmemek. Yalnızca son yedi günü tutuyorsanız, iki hafta önce başlayan sessiz bir veri bozulmasından dönemezsiniz.
Özet
KOBİ ERP’sinde yedekleme bir dosya alışkanlığı değil, ölçülen bir hedeftir. RPO ve RTO’yu iş tarafıyla birlikte koyun; veritabanı, dosya, anahtar ve kurulum envanterini çıkarın; tutarlı döküm ve ikili günlükle veri kaybını daraltın; en az bir kopyayı erişilemez tutun; yedeği her gün otomatik denetleyin ve ayda bir gerçekten geri yükleyin. Bu adımların hiçbiri pahalı değildir; pahalı olan, ilk provayı gerçek bir kesinti gününe bırakmaktır.
Sizin sisteminizde son geri yükleme provası ne zaman yapıldı ve ne kadar sürdü? Benzer bir süreç üzerinde çalışıyorsanız deneyimlerinizi paylaşın.
Kaynaklar
- CISA, #StopRansomware Guide (Eylül 2023)
- NIST CSRC Sözlük, Recovery Point Objective (kaynak: NIST SP 800-34 Rev. 1)
- NIST CSRC Sözlük, Recovery Time Objective (kaynak: NIST SP 800-34 Rev. 1)
- MySQL 8.4 Reference Manual, Establishing a Backup Policy
- KVKK, Veri Güvenliğine İlişkin Yükümlülükler (m.12)
- KVKK, Kişisel Veri Güvenliği Rehberi (Teknik ve İdari Tedbirler), Ocak 2018, bölüm 3.6
- Spatie, laravel-backup: Monitoring the health of all backups
- Laravel Documentation, Encryption
