لو DB الإنتاج بتاعتك 10GB، وبتحتفظ بنسخة يومية لمدة 30 يوم، AWS S3 بيكلّفك حوالي 1.38 دولار شهريًا فقط في التخزين. الطريقة اللي هتلاقيها هنا بتوفّر نفس الأمان بـ 36 سنت تقريبًا شهريًا على Backblaze B2، سكربت bash واحد، و cron entry سطر واحد.
المشكلة باختصار
قاعدة البيانات هي أغلى أصل في مشروعك التقني. لو اتمسحت جدول بالخطأ، أو قرص SSD في السيرفر خرب، أو حد عمل DROP DATABASE وهو نعسان الساعة 2 صباحًا، اللي هيرجّع الموقع شغّال هو النسخة الاحتياطية فقط. مفيش حل تاني.
المشكلة إن معظم الناس بتعتمد على واحدة من تلات طرق كلها مكسورة:
- النسخة اللي مخزّنة على نفس السيرفر اللي فيه الـ DB — لو السيرفر وقع، النسخة معاه.
- نسخة يدوية على الـ laptop بتاع المطور — بتبقى قديمة بأسبوعين في أحسن الأحوال.
- managed service زي RDS بـ point-in-time recovery بـ 40 دولار زيادة شهريًا — حل كويس بس overkill لمشروع صغير.
مثال بسيط للمبتدئ — إيه هو الـ backup أصلًا
تخيّل إنك بتكتب يومياتك في دفتر مهم وحاطه على المكتب. لو البيت شبّ فيه حريق، الدفتر خلاص راح. الحل البديهي: كل يوم قبل النوم، تاخد صورة لكل صفحة بموبايلك وتبعتها لصندوق أمانات في البنك. لو البيت حصله حاجة، بتروح البنك، تاخد الصور، وترجع تكتب دفتر جديد.
الـ database backup بالظبط نفس الفكرة. الـ pg_dump هو اللي بياخد "الصورة" من قاعدة بيانات PostgreSQL، والـ Backblaze B2 هو "البنك" البعيد اللي بيخزّن الصور دي. لو السيرفر مات، بترجع تنزل آخر نسخة من B2 وبتعيد تشغيل الموقع.
ليه Backblaze B2 مش AWS S3
الفرق الوحيد الجوهري بين B2 و S3 هو السعر — ووظيفيًا الاتنين بيعملوا نفس الحاجة لحالة الاستخدام دي. الأرقام الفعلية من صفحتهم الرسمية وقت كتابة المقال:
- B2 Storage: 0.006 دولار لكل GB شهريًا.
- S3 Standard: 0.023 دولار لكل GB شهريًا.
- B2 Download/Egress: أول 3× من حجم التخزين مجاني، بعدها 0.01 دولار/GB.
- S3 Egress: 0.09 دولار/GB بعد أول 100GB مجاني شهريًا.
على DB حجمها 10GB، الـ pg_dump مضغوط بـ gzip بيطلع تقريبًا 2GB (نسبة ضغط ~5× لبيانات relational عادية). 30 نسخة يومية × 2GB = 60GB تخزين شهري. التكلفة:
- B2: 60 × 0.006 = 0.36 دولار شهريًا.
- S3 Standard: 60 × 0.023 = 1.38 دولار شهريًا.
- فرق 3.8× لنفس الوظيفة بالظبط.
الافتراض هنا إن عندك DB إنتاج صغيرة إلى متوسطة (أقل من 50GB) وبتعمل dump كامل يوميًا. لو حجم DB 500GB، الحساب بيختلف ولازم تفكر في incremental backups.
إعداد Backblaze B2 — 4 خطوات
- اعمل حساب على
backblaze.com/b2. الـ signup مجاني وبتاخد 10GB free forever. - اعمل Bucket جديد من الـ dashboard، سمّيه
pg-backups-yourapp، خليه Private (مش public). - روح على App Keys واعمل مفتاح محدود بصلاحيات
readFilesوwriteFilesعلى الـ bucket ده فقط. احتفظ بالـkeyIDوapplicationKey. - فعّل Object Lock لو عايز حماية ضد ransomware (النسخ ميتمسحش حتى لو الـ API key اتسرّق).
تثبيت وإعداد rclone
الـ rclone هو الأداة اللي بتربط السكربت بـ B2. بتشتغل على Linux/macOS/Windows بنفس الـ syntax بالظبط، وبتدعم 70+ cloud provider لو عايز تغيّر بعدين.
curl https://rclone.org/install.sh | sudo bash
rclone config
# n (new remote)
# name: b2
# Storage: Backblaze B2
# account: <your keyID>
# key: <your applicationKey>
# hard_delete: true
# y (yes this is OK)
اختبر الاتصال بأمر واحد:
rclone lsd b2:
# لازم يطبع اسم الـ bucket اللي عملته
سكربت الـ Backup الكامل
ده السكربت الفعلي اللي بشغّله على سيرفرات إنتاج. احفظه في /usr/local/bin/pg_backup.sh وخليه executable بـ chmod +x:
#!/usr/bin/env bash
set -euo pipefail
# ---- إعدادات ----
DB_NAME="production"
DB_USER="postgres"
DB_HOST="127.0.0.1"
BACKUP_DIR="/var/backups/postgres"
REMOTE="b2:pg-backups-yourapp"
RETAIN_LOCAL_DAYS=3
RETAIN_REMOTE_DAYS=30
# ---- تحضير ----
TS=$(date +%Y-%m-%d_%H-%M)
FILE="${BACKUP_DIR}/${DB_NAME}_${TS}.sql.gz"
mkdir -p "$BACKUP_DIR"
# ---- pg_dump مع ضغط gzip ----
PGPASSWORD="${PGPASSWORD}" pg_dump \
-h "$DB_HOST" -U "$DB_USER" \
--format=plain --no-owner --clean --if-exists \
"$DB_NAME" | gzip -9 > "$FILE"
SIZE=$(du -h "$FILE" | cut -f1)
echo "[dump] $FILE ($SIZE)"
# ---- رفع إلى Backblaze B2 ----
rclone copy "$FILE" "$REMOTE/daily/" \
--transfers=4 --retries=3
# ---- تنظيف النسخ المحلية الأقدم من 3 أيام ----
find "$BACKUP_DIR" -type f -name "*.sql.gz" \
-mtime +${RETAIN_LOCAL_DAYS} -delete
# ---- تنظيف النسخ البعيدة الأقدم من 30 يوم ----
rclone delete "$REMOTE/daily/" \
--min-age ${RETAIN_REMOTE_DAYS}d
echo "[ok] $(date -Iseconds) backup done"
الـ password بيتقرأ من environment variable PGPASSWORD، مش مكتوب في السكربت. اعمل ملف /etc/pg_backup.env بصلاحيات 600 وحطّه فيه.
جدولة الـ cron
عدّل الـ crontab بتاع الـ root (أو أي user عنده صلاحية قراءة الـ DB):
sudo crontab -e
# أضف السطر ده
0 3 * * * . /etc/pg_backup.env && /usr/local/bin/pg_backup.sh >> /var/log/pg_backup.log 2>&1
الوقت 3 صباحًا عشان الـ traffic قليل. && معناها السكربت ميشتغلش لو فشل تحميل الـ env file.
اختبار الـ restore — الخطوة اللي 80% بينسوها
نسخة احتياطية ما تم اختبار استرجاعها = مفيش نسخة احتياطية. مرة واحدة في الشهر على الأقل، جرّب الـ restore على DB اختبارية:
# نزّل آخر نسخة
rclone copy b2:pg-backups-yourapp/daily/production_2026-04-20_03-00.sql.gz /tmp/
# استرجع على DB اختبارية
createdb production_restore_test
gunzip -c /tmp/production_2026-04-20_03-00.sql.gz | \
psql production_restore_test
# اتأكد من عدد الجداول
psql production_restore_test -c "\dt" | wc -l
الـ Trade-offs اللي لازم تعرفها
- B2 أبطأ قليلًا في الـ upload من S3: زيادة median latency حوالي 50 إلى 100ms لكل request. مش مهم في backup يومي، مهم لو بتعمل streaming uploads من تطبيقك.
- المناطق محدودة: US West, US East, EU Central فقط. لو محتاج sovereignty في منطقة الخليج مثلًا، مش خيار.
- pg_dump بياخد قفل قصير (AccessShareLock): بيمنع عمليات DDL زي ALTER TABLE وقت الـ dump، بس ما بيمنعش reads/writes عادية.
- الـ restore بياخد وقت: DB 10GB بترجع في ~15 دقيقة على SSD عادي. مش الحل الأسرع لـ RTO قصير.
متى لا تستخدم هذه الطريقة
- لو RPO عندك أقل من ساعة: محتاج WAL archiving مع أداة زي
pgBackRestأوwal-g— مش dump يومي. - لو DB حجمها أكثر من 500GB: pg_dump هيستغرق ساعات. استخدم physical backups (pg_basebackup) + WAL streaming.
- لو بتحتاج point-in-time recovery لأي ثانية: نفس الملاحظة السابقة، الـ dump اليومي مش كافي.
- لو عندك compliance بيفرض تخزين في منطقة جغرافية محددة: اتحقق إن B2 بيدعمها قبل ما تبدأ.
مراقبة الشغل — لا تعتمد على الصمت
الـ cron مش بيقولّك لو السكربت فشل. أبسط طريقة: دمج مع Healthchecks.io بسطر واحد في آخر السكربت:
curl -fsS --retry 3 https://hc-ping.com/<your-uuid> > /dev/null
لو السكربت فشل وما وصلش للسطر ده، Healthchecks.io هيبعتلك تنبيه بعد الـ grace period اللي حدّدته. الخدمة مجانية حتى 20 job.
الخطوة التالية
افتح السيرفر الإنتاج دلوقتي، نفّذ الخطوات من قسم إعداد Backblaze، وشغّل السكربت يدويًا مرة واحدة بـ bash /usr/local/bin/pg_backup.sh. تأكد إن الملف ظهر في الـ B2 console. بعدها جرّب الـ restore على DB اختبارية. لو الخطوتين اشتغلوا، ضيف الـ cron entry وسيبه يشتغل.
مصادر
- Backblaze B2 Cloud Storage Pricing — الأسعار الرسمية.
- AWS S3 Pricing — للمقارنة.
- rclone Backblaze B2 Documentation — إعدادات rclone كاملة.
- PostgreSQL pg_dump documentation — كل الـ flags والخيارات.
- PostgreSQL Backup Chapter — استراتيجيات النسخ الاحتياطي الكاملة.
- Healthchecks.io Documentation — لمراقبة الـ cron jobs.