أحمد حايس
الرئيسيةمن أناالدوراتالمدونةالعروض
أحمد حايس

دورات عربية متخصصة في التقنية والبرمجة والذكاء الاصطناعي.

المنصة مبنية على الوضوح، التطبيق، والنتيجة النافعة: شرح مرتب يساعدك تفهم الأدوات، تكتب كودًا أفضل، وتستخدم الذكاء الاصطناعي بوعي داخل العمل الحقيقي.

تعلم أسرعوصول مباشر للدورات والمسارات من الموبايل.
تنقل أوضحالروابط الأساسية والدعم في مكان واحد بدون تشتيت.

المنصة

  • الرئيسية
  • من أنا
  • الدورات
  • العروض
  • المدونة

الدعم

  • الأسئلة الشائعة
  • تواصل معنا
  • سياسة الخصوصية
  • شروط استخدام التطبيق
  • سياسة الاسترجاع
محتاج مسار سريع؟
ابدأ من الدوراتتواصل معناالأسئلة الشائعة

© 2026 أحمد حايس. جميع الحقوق محفوظة.

الرئيسيةالدوراتالعروضالمدونةالدخول

أتمتة النسخ الاحتياطي لـ PostgreSQL إلى Cloudflare R2 بـ 1.5 سنت/GB شهريًا

📅 ٢٠ أبريل ٢٠٢٦⏱ 6 دقائق قراءة
أتمتة النسخ الاحتياطي لـ PostgreSQL إلى Cloudflare R2 بـ 1.5 سنت/GB شهريًا
لو قاعدة البيانات بتاعتك سقطت دلوقتي، هتحتاج كام ساعة ترجّع آخر نسخة سليمة؟ لو إجابتك "مش متأكد"، المقال ده بيعطيك سكربت جاهز بياخد نسخة يوميًا من PostgreSQL، بيرفعها على Cloudflare R2 بتكلفة 1.5 سنت لكل GB شهريًا، وبيتأكد إن الملف سليم قبل ما يقولك "تمام".

خوادم قاعدة بيانات داخل data center مع إضاءة زرقاء، تمثل أتمتة النسخ الاحتياطي لـ PostgreSQL

أتمتة النسخ الاحتياطي لـ PostgreSQL إلى Cloudflare R2

المشكلة باختصار

أغلب المشاريع الصغيرة والمتوسطة عندها backup strategy من اتنين: إما cronjob بيعمل pg_dump على نفس السيرفر (وده بيموت مع السيرفر لو وقع)، أو خدمة مُدارة بتاخد 30 دولار شهريًا على قاعدة 10GB. الطريقتين غلط. الأولى هشة، والتانية مبالَغ فيها.

الحل اللي هنبنيه: سكربت bash واحد، بينسخ القاعدة، بيضغطها، بيشفّرها، بيرفعها على bucket في Cloudflare R2، بيتحقق من الـ checksum، وبيبعت تنبيه لو في مشكلة. التكلفة الكاملة لقاعدة 10GB مع 30 نسخة يومية محفوظة: أقل من 5 دولار شهريًا.

يعني إيه "نسخة احتياطية" أصلاً؟ — مثال للمبتدئ

تخيّل إنك بتكتب كراسة مذكرات كل يوم. في آخر اليوم بتصوّرها بالموبايل وبتبعت الصور لنفسك على Google Drive. لو الكراسة ضاعت، مش مشكلة، الصور موجودة. ده بالظبط اللي بيحصل مع الـ backup:

  • الكراسة = قاعدة البيانات الحيّة (PostgreSQL).
  • صورة الكراسة = ملف الـ dump (snapshot للحظة معينة).
  • Google Drive = Cloudflare R2 (storage بعيد عن السيرفر الأصلي).

علميًا: pg_dump بيطلع ملف فيه كل الـ DDL (هيكل الجداول) والـ DML (البيانات نفسها) في صيغة يقدر pg_restore يعيدها كاملة. الملف ده consistent snapshot — حتى لو القاعدة شغالة وبيتكتب فيها أثناء الـ dump، النتيجة بتبقى متسقة على لحظة بداية العملية.

ليه Cloudflare R2 بالذات؟

التخزين السحابي ليه 3 تكاليف: الـ storage شهريًا، الـ requests، والـ egress (بتدفع لما تنزّل الملف برّه). الـ egress هو اللي بيوجع في AWS S3 — حوالي 9 سنت لكل GB.

R2 بيلغي الـ egress بالكامل. لما تيجي تسترجع نسخة احتياطية حجمها 10GB من S3، بتدفع 0.90 دولار مرة واحدة. من R2، بتدفع صفر. ده مش فرق صغير في سيناريو كارثة لما بتسترجع يوميًا عشرة نسخ لحد ما تلاقي السليمة.

  • Storage: 1.5 سنت لكل GB شهريًا (أرخص من S3 Standard بحوالي 35%).
  • Egress: صفر.
  • API: S3-compatible، يعني أي tool بيشتغل مع S3 هيشتغل مع R2 من غير تغيير يُذكر.

السكربت الكامل — خطوة بخطوة

قبل ما تبدأ، هتحتاج 3 حاجات: postgresql-client، rclone (أداة المزامنة)، و R2 bucket متعمل + Access Key.

1) إعداد rclone للاتصال بـ R2

Bash

# ثبّت rclone
curl https://rclone.org/install.sh | sudo bash

# اعمل config جديد
rclone config
# اختر n (new remote)
# الاسم: r2
# النوع: s3
# provider: Cloudflare
# access_key_id + secret_access_key من R2 dashboard
# endpoint: https://<ACCOUNT_ID>.r2.cloudflarestorage.com

2) السكربت الأساسي

Bash

#!/bin/bash
set -euo pipefail

# الإعدادات
DB_NAME="production_db"
DB_USER="postgres"
R2_BUCKET="db-backups"
RETENTION_DAYS=30
SLACK_WEBHOOK="https://hooks.slack.com/services/xxx/yyy/zzz"

# متغيرات الوقت
TIMESTAMP=$(date +%Y-%m-%d_%H-%M-%S)
BACKUP_FILE="/tmp/${DB_NAME}_${TIMESTAMP}.dump"
CHECKSUM_FILE="${BACKUP_FILE}.sha256"

notify_fail() {
  curl -s -X POST "$SLACK_WEBHOOK" \
    -H 'Content-Type: application/json' \
    -d "{\"text\":\"❌ Backup failed: $1\"}"
  exit 1
}

# 1) خُد snapshot بصيغة custom (مضغوط + قابل للـ restore الانتقائي)
pg_dump -U "$DB_USER" -Fc -Z 9 -f "$BACKUP_FILE" "$DB_NAME" \
  || notify_fail "pg_dump failed"

# 2) تحقق إن الملف مش فاضي وإنه صالح للـ restore
pg_restore --list "$BACKUP_FILE" > /dev/null \
  || notify_fail "dump file corrupted"

# 3) احسب checksum لتوثيق السلامة
sha256sum "$BACKUP_FILE" > "$CHECKSUM_FILE"

# 4) ارفع الـ dump والـ checksum على R2
rclone copy "$BACKUP_FILE" "r2:${R2_BUCKET}/daily/" \
  || notify_fail "rclone upload failed"
rclone copy "$CHECKSUM_FILE" "r2:${R2_BUCKET}/daily/"

# 5) امسح النسخ الأقدم من 30 يوم
rclone delete --min-age "${RETENTION_DAYS}d" "r2:${R2_BUCKET}/daily/"

# 6) نظّف المحلي
rm -f "$BACKUP_FILE" "$CHECKSUM_FILE"

# 7) نجاح
curl -s -X POST "$SLACK_WEBHOOK" \
  -H 'Content-Type: application/json' \
  -d "{\"text\":\"✓ Backup OK: ${DB_NAME} ${TIMESTAMP}\"}"

3) جدولة السكربت مع cron

Bash

# نفّذ يوميًا الساعة 3 فجرًا
crontab -e
# ضيف السطر ده
0 3 * * * /usr/local/bin/pg_backup.sh >> /var/log/pg_backup.log 2>&1
شاشة terminal تعرض سكربت bash مع تدفق بيانات pg_dump و rclone لرفع النسخة الاحتياطية إلى Cloudflare R2

التحقق من أن النسخة فعلًا سليمة

قاعدة محفورة: نسخة احتياطية ما جرّبتهاش مش نسخة احتياطية. السكربت فوق بيعمل validation أساسي بـ pg_restore --list، لكن ده مش كفاية لوحده. مرة كل أسبوع اعمل restore فعلي على قاعدة staging:

Bash

# نزّل آخر نسخة من R2
rclone copy "r2:db-backups/daily/$(rclone lsf r2:db-backups/daily/ --files-only | sort | tail -1)" /tmp/

# ارجعها لـ DB جديد
createdb staging_restore_test
pg_restore -d staging_restore_test /tmp/production_db_*.dump

# شغّل استعلام تحقّق
psql staging_restore_test -c "SELECT COUNT(*) FROM users;"

لو العدد قريب من قاعدة الإنتاج، النسخة سليمة. لو صفر أو رقم غريب، عندك مشكلة في الـ dump لازم تتصلح فورًا.

الأرقام الفعلية — before/after

  • قاعدة 10GB (قبل الضغط): الـ dump بصيغة -Fc -Z 9 بيطلع حوالي 2.1GB. توفير 79% في الحجم.
  • التكلفة الشهرية: 30 نسخة × 2.1GB = 63GB × 0.015$ = 0.95 دولار.
  • زمن الـ dump: على VM بـ 4 CPU + 8GB RAM، حوالي 90 ثانية لقاعدة 10GB (على NVMe).
  • زمن الرفع على R2: من سيرفر في أوروبا، متوسط 40 ثانية لـ 2.1GB.
  • زمن الاسترجاع الكامل في كارثة: تنزيل + pg_restore = حوالي 4 دقائق.

trade-offs صريحة

المكاسب: تكلفة أقل بـ 85% من S3 مع egress، RTO (Recovery Time Objective) ممتاز لمشروع متوسط، مفيش vendor lock-in لأن R2 متوافق مع S3 API.

التكاليف: pg_dump single-threaded على صيغة custom — يعني لو قاعدتك 500GB، هياخد ساعات. لازم تحوّل لـ directory format مع -j N لاستخدام parallel. كمان، الـ dump بياخد lock خفيف (ACCESS SHARE) على الجداول، مش هيعطّل الكتابة لكن هيزوّد I/O. لو عندك replica، شغّل الـ dump من عليها مش من الـ primary.

الافتراض هنا إن حجم قاعدتك ≤ 100GB وإنك بتحتاج RPO (Recovery Point Objective) ≤ 24 ساعة. تحت ده، الطريقة ممتازة. فوق ده، تحتاج حل مختلف.

متى لا تستخدم هذه الطريقة

  • قواعد أكبر من 500GB: استخدم pgBackRest أو WAL-G مع incremental backups بدل full daily dumps.
  • RPO أقل من ساعة: pg_dump مش كفاية. تحتاج continuous archiving مع WAL shipping.
  • متطلبات compliance صارمة (HIPAA, PCI-DSS): R2 لسه مش معتمد في كل الـ frameworks. راجع مع الـ auditor.
  • قاعدة multi-terabyte مع كتابة مستمرة: الـ dump هيطوّل لدرجة إن الـ snapshot ممكن يبقى قديم وقت ما بيخلص.

الخطوة التالية

انسخ السكربت، غيّر الـ 3 متغيرات في الأول (DB_NAME, R2_BUCKET, SLACK_WEBHOOK)، شغّله يدويًا مرة للتأكد، وبعدين ضيفه على cron. في نهاية اليوم الأول، روح R2 dashboard وشوف الملف موجود فعلًا. في نهاية الأسبوع، اعمل restore test على staging. لو الاستعلام رجّع العدد المتوقع، إنت بقيت في أمان فعلي.

المصادر

  • Cloudflare R2 — Pricing documentation
  • PostgreSQL Documentation — pg_dump reference
  • rclone — Cloudflare R2 configuration guide
  • Microsoft Learn — Best Practices for pg_dump and pg_restore
  • Stormatics — PostgreSQL Backup Best Practices
]]>

هل استفدت من المقال؟

اطّلع على المزيد من المقالات والدروس المجانية من نفس المسار المعرفي.

تصفّح المدونة