الخطوات
-
1
أنشئ مجلد النسخ الاحتياطي
احفظ النسخ الاحتياطية في مكان ليس جذر الويب. اقيّده حتى يقرأه root فقط.
bashsudo mkdir -p /home/backups sudo chmod 700 /home/backups # الملفات التي تُنشأ بداخله ترث قيود الوصول المحدودة -
2
احفظ بيانات الاعتماد بأمان في ~/.my.cnf
تمرير كلمة المرور في سطر الأوامر يضعها في قائمة العمليات — قابلة للقراءة من أي مستخدم بـ
ps aux. احفظها في~/.my.cnfعوضاً عن ذلك. في MariaDB مع مصادقة unix_socket يمكنك تخطي كلمة المرور كلياً.bash# أنشئ /root/.my.cnf (شغّل كـ root أو بـ sudo su) cat > /root/.my.cnf << "EOF" [mysqldump] user=root password=your_db_password_here EOF # قيّد الصلاحيات — root وحده يقرأ هذا الملف chmod 600 /root/.my.cnf # في MariaDB مع مصادقة unix_socket، يمكن أن يكون الملف: # [mysqldump] # user=root # (بدون سطر كلمة المرور — MariaDB تصادق عبر مستخدم النظام) -
3
اكتب سكريبت النسخ الاحتياطي
--single-transactionهو الخيار الحاسم — يلفّ جداول InnoDB في transaction حتى تكون النسخة متسقة دون قفل أي جداول.--quickيدفق الصفوف واحدة تلو الأخرى بدل تحميل الجدول بأكمله في الذاكرة أولاً.bashcat > /usr/local/bin/backup.sh << "SCRIPT" #!/bin/bash set -euo pipefail DB_NAME="myapp" BACKUP_DIR="/home/backups" DATE=$(date +%F) FILE="${BACKUP_DIR}/db_${DATE}.sql.gz" # تفريغ بدون قفل جداول، دفق إلى gzip ionice -c3 nice -n19 \ mysqldump \ --single-transaction \ --quick \ --skip-lock-tables \ "${DB_NAME}" \ | gzip -9 > "${FILE}" chmod 600 "${FILE}" # احتفظ بآخر 7 أيام فقط find "${BACKUP_DIR}" -name "*.sql.gz" -mtime +7 -delete echo "[$(date)] اكتملت النسخة الاحتياطية: ${FILE} ($(du -sh ${FILE} | cut -f1))" SCRIPT chmod +x /usr/local/bin/backup.sh -
4
اختبر السكريبت يدوياً أولاً
شغّل السكريبت يدوياً دائماً قبل جدولته. تحقق من أن ملف الإخراج موجود وحجمه أكبر من صفر.
bashsudo /usr/local/bin/backup.sh # أكّد إنشاء الملف ls -lh /home/backups/ # ألقِ نظرة على النسخة المضغوطة دون استخراجها gunzip -c /home/backups/db_$(date +%F).sql.gz | head -20 -
5
جدوِل مع crontab
شغّل النسخ الاحتياطي يومياً الساعة 02:00 كـ root. يعمل cron في بيئة بسيطة — استخدم المسارات المطلقة في كل مكان في السكريبت (منجز أعلاه بالفعل).
bash# عدّل crontab الخاص بـ root sudo crontab -e # أضف هذا السطر: 0 2 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1 # اعرض المهام المجدولة لـ root sudo crontab -l # تأكد من أن السجل يلتقط الإخراج sudo tail -f /var/log/backup.log -
6
اختبر إجراء الاستعادة
نسخة احتياطية لم تستعدها قط هي نسخة لا تملكها. اختبر على قاعدة بيانات staging لا على الإنتاج.
bash# استعادة إلى قاعدة بيانات موجودة (سيُكتب فوق جميع البيانات) gunzip < /home/backups/db_2026-05-28.sql.gz | mysql myapp # استعادة إلى قاعدة بيانات جديدة (أكثر أماناً للاختبار) mysql -e "CREATE DATABASE myapp_restore;" gunzip < /home/backups/db_2026-05-28.sql.gz | mysql myapp_restore # تحقق من وجود الجداول الرئيسية mysql myapp_restore -e "SHOW TABLES; SELECT COUNT(*) FROM users;" # احذف قاعدة البيانات الاختبارية mysql -e "DROP DATABASE myapp_restore;" -
7
انسخ النسخ الاحتياطية خارج الخادم بـ rsync
نسخة احتياطية على نفس خادم قاعدة البيانات تضيع إن مات الخادم. ادفعها إلى خادم ثانٍ عبر SSH. شغّل هذا في نفس مهمة cron بعد اكتمال التفريغ.
bash# أضف في نهاية backup.sh (بعد سطر find -delete): REMOTE_USER="backup" REMOTE_HOST="backup-server.example.com" REMOTE_DIR="/home/backups/myapp/" rsync -az --delete \ -e "ssh -i /root/.ssh/backup_key -o StrictHostKeyChecking=no" \ "${BACKUP_DIR}/" \ "${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_DIR}" echo "[$(date)] تمت المزامنة مع الخادم البعيد: ${REMOTE_HOST}:${REMOTE_DIR}" # المتطلبات المسبقة: # 1. أنشئ مفتاحاً مخصصاً: ssh-keygen -t ed25519 -f /root/.ssh/backup_key -N "" # 2. أضف المفتاح العام إلى authorized_keys الخادم البعيد # 3. أنشئ المجلد البعيد: ssh user@backup-server mkdir -p /home/backups/myapp -
8
راقب صحة النسخ الاحتياطية
الفشل الصامت هو الأسوأ. أضف فحصاً للحجم وتنبيهاً حتى تعلم خلال ساعات إن توقف النسخ الاحتياطي عن العمل.
bash# أضف إلى backup.sh بعد سطر gzip: FILE_SIZE=$(stat -c%s "${FILE}") MIN_SIZE=1024 # 1 KB حد أدنى — النسخة الصحيحة دائماً أكبر if [ "${FILE_SIZE}" -lt "${MIN_SIZE}" ]; then echo "خطأ: ملف النسخة الاحتياطية صغير بشكل مريب (${FILE_SIZE} بايت)" >&2 # أرسل تنبيهاً بالبريد (يتطلب mailutils) echo "ربما فشلت النسخة الاحتياطية. تحقق من ${FILE}" | mail -s "تنبيه: فشل النسخ الاحتياطي" admin@example.com exit 1 fi # تحقق من آخر نسخة احتياطية في أي وقت ls -lht /home/backups/ | head -3
نصائح ومحاذير
- انسخ <strong>جميع</strong> قواعد البيانات دفعة واحدة بـ <code>mysqldump --all-databases</code> إن كان الخادم يشغّل مشاريع متعددة — مهمة cron واحدة وملف واحد.
- استخدم خيارات <code>--routines --triggers --events</code> لتضمين الإجراءات المخزنة والـ triggers والأحداث المجدولة في التفريغ. إهمالها من الأخطاء الشائعة.
- فضّل <code>--set-gtid-purged=OFF</code> عند التفريغ من replica لتجنب أخطاء GTID عند الاستعادة.
- اختبر عملية الاستعادة كل ثلاثة أشهر — ليس فقط أن الملف موجود، بل أن قاعدة البيانات المستعادة تخدم تطبيقك بشكل صحيح.
- خيارات التخزين السحابي: <code>rclone copy /home/backups/ s3:mybucket/db/</code> يعمل مباشرة مع S3 وBackblaze B2 وGoogle Cloud Storage. ثبّت rclone مرة واحدة، اضبطه مرة واحدة.
خاتمة
لديك الآن نسخ احتياطي يومي مؤتمت: بيانات اعتماد محمية، بدون قفل جداول، مضغوط بـ gzip، محتفظ به 7 أيام، ومنسوخ اختيارياً خارج الخادم. والأهم، اختبرت عملية الاستعادة — وهذا ما يفرق بين استراتيجية نسخ احتياطي حقيقية وشعور زائف بالأمان. أضف تذكيراً في تقويمك لتشغيل اختبار الاستعادة مجدداً بعد 3 أشهر.