لماذا لا تكفي لقطات المستضيف: ثلاثة قيود ملموسة
لقطة الاستضافة مريحة، لكنها تشترك في نفس نقطة الفشل مع آلتك الافتراضية. القيد الأول: إذا حُذفت الآلة الافتراضية — خطأً، أو من قِبَل المزوّد، أو بسبب عدم سداد — تختفي اللقطات المرتبطة بها أيضًا. القيد الثاني: إذا اخترق أحد المهاجمين حساب الاستضافة الخاص بك، فيمكنه حذف اللقطات والآلة الافتراضية في ثوانٍ عبر الواجهة البرمجية (API) أو لوحة التحكم. القيد الثالث: لقطات مركز البيانات لا تختبر الاستعادة أبدًا. قد تحتوي لقطة "متّسقة" على نظام ملفات تالف أو قاعدة بيانات في حالة غير متسقة؛ ولن تعلم بذلك إلا حين تحتاجها.
ما تضمنه استراتيجية 3-2-1 وما لا تضمنه لقطة
- ثلاث نسخ: النسخة الأصلية على القرص المحلي، وأخرى في لقطات المستضيف، وثالثة خارج المزوّد على S3 — لا نقطة فشل واحدة يمكنها محو كل شيء.
- وسيطان مختلفان: قرص NVMe الخاص بخادم VPS وحاوية التخزين الكائني (object storage) لدى مزوّد آخر مفصولان فيزيائيًا ومنطقيًا.
- تشفير قبل النقل: يشفّر Restic من جهة العميل بـ AES-256؛ لا يرى مزوّد التخزين S3 إلا كتلًا بيانية مبهمة، غير قابلة للقراءة دون مفتاحك.
- اختبار الاستعادة: النسخة الاحتياطية غير المختبَرة وعدٌ لا ضمانة. يمكن لمؤقّت systemd التحقّق تلقائيًا من إمكانية استعادة ملف دليل (sentinel).
- استقلالية عن المزوّد: لا يمكن حذف حاوية B2 أو R2 الخاصة بك من لوحة تحكم مزوّد استضافة VPS.
- لقطة الاستضافة لا تشفّر قبل النقل: البيانات قابلة للقراءة من قِبَل المزوّد.
- لقطة الاستضافة لا تتحقّق أبدًا من اتّساق قواعد البيانات على مستوى التطبيق.
النسخ الثلاث موضّحة: محلية، استضافة، خارج الموقع
قاعدة 3-2-1 ليست وصفة جامدة — إنها مبدأ تنويع المخاطر.
النسخة 1 — القرص المحلي لخادم VPS. هذه خطّك الأمامي: النسخة الأصلية على محرك NVMe. تخدم الاستعادة السريعة لملف حُذف عن طريق الخطأ دون أي تأخير شبكي.
النسخة 2 — لقطات المستضيف. النسخ الاحتياطي التلقائي الذي يديره مزوّد VPS يغطّي أخطاء التهيئة والحذف العرضي على مستوى النظام. إنه شبكة الأمان الخاصة بك على الموقع.
النسخة 3 — تخزين كائني خارج الموقع، مشفّر بـ Restic. هذه هي الحلقة التي تنساها معظم الفرق، والوحيدة التي تصمد أمام الفقدان الكامل لحساب الاستضافة. يشفّر Restic البيانات قبل أي نقل، ويزيل التكرار لتقليل التكاليف، ويرسلها إلى حاوية متوافقة مع S3 لدى مزوّد طرف ثالث. هذه النسخة الثالثة هي ما يبنيه هذا الدليل.
Backblaze B2 مقابل Cloudflare R2: اختيار خادم S3
| المعيار | Backblaze B2 | Cloudflare R2 |
|---|---|---|
| التخزين | سعر عام بالغيغابايت | مجاني حتى 10 غيغابايت/شهر، ثم سعر عام بالغيغابايت |
| البيانات الصادرة (Egress) | مجاني نحو Cloudflare وشركاء CDN المختارين؛ مدفوع خارج الشركاء | مجاني بلا حدود — لا تكلفة صادرة |
| توافق S3 | API متوافقة مع S3؛ نقطة نهاية `s3.us-west-004.backblazeb2.com` | API متوافقة مع S3؛ نقطة نهاية `<account>.r2.cloudflarestorage.com` |
| متغيّر `RESTIC_REPOSITORY` | `s3:https://s3.us-west-004.backblazeb2.com/bucket-name` | `s3:https://<account>.r2.cloudflarestorage.com/bucket-name` |
| مفاتيح الوصول | B2 Application Key (Key ID + Application Key) | R2 API Token بصلاحيات Object Read & Write |
| حالة الاستخدام الموصى بها | حجم كبير مع صادرات محدودة أو من بنية تحتية Cloudflare | صادرات متكررة أو اختبارات استعادة منتظمة من أي مكان |
التنفيذ الكامل: Restic + S3 على خادم VPS
تصدير متغيّرات البيئة إلى ملف مؤمَّن
أنشئ /root/.restic-env بالمتغيّرات المطلوبة. لـ Backblaze B2:
export RESTIC_REPOSITORY="s3:https://s3.us-west-004.backblazeb2.com/your-bucket"
export RESTIC_PASSWORD="your-repository-password"
export AWS_ACCESS_KEY_ID="your-b2-key-id"
export AWS_SECRET_ACCESS_KEY="your-b2-application-key"لـ Cloudflare R2، استبدل رابط المستودع والمفاتيح:
export RESTIC_REPOSITORY="s3:https://<account-id>.r2.cloudflarestorage.com/your-bucket"
export RESTIC_PASSWORD="your-repository-password"
export AWS_ACCESS_KEY_ID="your-r2-access-key-id"
export AWS_SECRET_ACCESS_KEY="your-r2-secret-access-key"قيّد الصلاحيات فورًا: chmod 600 /root/.restic-env. يجب ألا يُودَع هذا الملف في مستودع Git أبدًا.
تهيئة مستودع Restic على S3
حمّل البيئة، ثم هيّئ المستودع المشفّر على حاويتك:
source /root/.restic-env
restic initينشئ Restic بنية المستودع ويُحكِم التشفير بكلمة مرورك. احفظ كلمة مرور المستودع خارج خادم VPS: في مدير كلمات مرور أو خزنة مشفّرة على جهاز منفصل. بدونها لا يمكن إجراء أي استعادة.
تشغيل أول نسخة احتياطية إلى S3
اختبر المسار الكامل بنسخة احتياطية يدوية:
source /root/.restic-env
restic backup /etc /var/www /opt/docker-dataلقواعد البيانات، أنشئ ملف تفريغ أولًا أو استخدم وضع stdin. مثال لـ PostgreSQL:
pg_dump -U postgres mydb | restic backup --stdin --stdin-filename mydb.sqlتحقّق من إنشاء اللقطة: restic snapshots.
تحديد سياسة الاحتفاظ
أمر forget يزيل الإشارات إلى اللقطات القديمة؛ --prune يحرّر الكتل اليتيمة فيزيائيًا من الخادم الخلفي:
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 3 --pruneمبرّر القيم. سبع نسخ يومية تغطّي أسبوعًا كاملًا — كافية لاكتشاف تلف صامت لا يظهر إلا بعد أيام. أربع نسخ أسبوعية تتيح نافذة شهر لاكتشاف مشكلة تطبيقية بطيئة. ثلاث نسخ شهرية تسمح بالاستعادة إلى حالة سابقة للربع الحالي. --prune ضروري: بدونه، تضع forget علامة حذف على اللقطات لكنها لا تحرّر المساحة في الحاوية.
التمييز بين restic check وrestic check --read-data
هاتان الأداتان لا تتحقّقان من الشيء ذاته.
restic check تتحقّق من بيانات وصف المستودع (metadata) — بنية الحزم، واتّساق الفهارس، وسلامة المؤشرات. سريعة (من ثوانٍ إلى دقائق حسب حجم المستودع). شغّلها بعد كل forget --prune.
restic checkrestic check --read-data تنزّل وتتحقّق من كل كتلة بيانات بمقارنتها بالبصمة التشفيرية الخاصة بها. بطيئة (تتناسب مع حجم المستودع) ومكلفة من حيث الصادرات إذا فاتورك المزوّد. احتفظ بها للتحقّق الشهري أو عند الشك في سلامة الحاوية.
restic check --read-dataإنشاء وحدة systemd للنسخ الاحتياطي (.service)
أنشئ /etc/systemd/system/restic-backup.service:
[Unit]
Description=Restic backup to S3
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
EnvironmentFile=/root/.restic-env
ExecStartPre=/bin/sh -c 'curl -sf --max-time 10 https://one.one.one.one > /dev/null || exit 1'
ExecStart=/usr/bin/restic backup /etc /var/www /opt/docker-data
ExecStartPost=/usr/bin/restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 3 --prune
ExecStartPost=/usr/bin/restic check
StandardOutput=journal
StandardError=journalExecStartPre يتحقّق من الاتصال بالشبكة قبل محاولة النسخ الاحتياطي — إذا كان الخادم معزولًا أو الحاوية غير متاحة، يفشل الخدمة بوضوح.
إنشاء وحدة جدولة systemd (.timer)
أنشئ /etc/systemd/system/restic-backup.timer:
[Unit]
Description=Daily timer for restic-backup.service
[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true
RandomizedDelaySec=900
[Install]
WantedBy=timers.targetPersistent=true يضمن تشغيل النسخ الاحتياطي عند بدء التشغيل التالي إذا كان الخادم مُطفَأً في الساعة 03:00. فعّل وشغّل:
systemctl daemon-reload
systemctl enable --now restic-backup.timerتحقّق من حالة المؤقّت: systemctl status restic-backup.timer والسجلات: journalctl -u restic-backup.service.
إنشاء اختبار استعادة مؤتمت مع ملف دليل
أنشئ ملف الدليل وضمّنه في نسختك الاحتياطية:
echo "sentinel-$(date +%s)" > /opt/restic-sentinel.txtأنشئ /etc/systemd/system/restic-restore-test.service:
[Unit]
Description=Restic restore test
After=network-online.target
[Service]
Type=oneshot
EnvironmentFile=/root/.restic-env
ExecStart=/bin/sh -c '
rm -rf /tmp/restic-test-restore && \
restic restore latest --target /tmp/restic-test-restore && \
test -f /tmp/restic-test-restore/opt/restic-sentinel.txt && \
echo "Restore OK" || \
(echo "FAILED sentinel restore" && exit 1)
'
StandardOutput=journal
StandardError=journalأنشئ المؤقّت الأسبوعي /etc/systemd/system/restic-restore-test.timer:
[Unit]
Description=Weekly Restic restore test
[Timer]
OnCalendar=Sun 04:00:00
Persistent=true
[Install]
WantedBy=timers.targetفعّل: systemctl enable --now restic-restore-test.timer.
أسرار Restic: ملف .env معزول، لا تضمينها مباشرة في الخدمة
لا تضع RESTIC_PASSWORD أو AWS_ACCESS_KEY_ID أو AWS_SECRET_ACCESS_KEY مباشرةً في تعريف وحدة systemd أو سكربت مُصدَر أو Dockerfile. ملف /root/.restic-env مع chmod 600 هو الممارسة الصحيحة: يُحمَّل عبر EnvironmentFile= دون أن يظهر في systemctl show أو السجلات. أضف /root/.restic-env إلى .gitignore أو .dockerignore إذا كان الدليل /root مُصدَرًا. لبيئات متعدّدة المستخدمين، فضّل مدير الأسرار أو بيانات اعتماد systemd (LoadCredential=) على الملف المسطّح.
استكشاف الأخطاء: أربعة أخطاء شائعة
Fatal: unable to open config file عند restic init أو أول restic backup. لا يستطيع Restic الوصول إلى الحاوية. تحقّق من تحميل المتغيّرات (echo $RESTIC_REPOSITORY) وصحة بيانات الاعتماد. تحقّق من صلاحيات IAM لمفتاحك على B2 أو R2: يحتاج على الأقل إلى صلاحيات القراءة والكتابة والقائمة على الحاوية.
حاوية S3: صلاحيات غير كافية. إذا نجح restic init لكن restic backup فشل بخطأ تفويض، فسياسة الحاوية على الأرجح تتجاوز صلاحيات المفتاح. على B2، تحقّق من غياب قاعدة denyUpload. على R2، تحقّق من أن الحاوية ليست في وضع عام مع قيود الكتابة.
مؤقّت systemd لا يُشغَّل. شخّص بثلاثة أوامر: systemctl status restic-backup.timer، وsystemctl list-timers --all | grep restic، وjournalctl -u restic-backup.service --since today. إذا كان المؤقّت نشطًا لكن الخدمة لم تعمل، تحقّق من صحة بناء OnCalendar بـ systemd-analyze calendar '*-*-* 03:00:00'.
restic check --read-data بطيء جدًا. على مستودع بعشرات الغيغابايت، قد يستغرق ساعات ويولّد تكاليف صادرات على B2. استخدم --read-data-subset=10% للتحقّق من عيّنة عشوائية في كل اختبار أسبوعي، واحتفظ بالتحقّق الكامل لصيانة شهرية مجدوَلة.
خطة الاسترداد: كم من الوقت تستغرق الاستعادة من B2 أو R2؟
تعتمد مدة الاستعادة على ثلاثة عوامل: حجم البيانات، وعرض النطاق الترددي المتاح بين خادم VPS والحاوية، وأي تكاليف صادرة.
كتقدير: يُستعاد مستودع Restic بحجم 20 غيغابايت على B2 (بيانات مُزيلة التكرار ومضغوطة مسبقًا) في نحو 15 إلى 30 دقيقة مع اتصال مركز بيانات معياري بسرعة 1 غيغابت في الثانية. على R2، الصادرات مجانية — لا ضغط مالي لتمديد الاستعادة.
ممارستان تقلّصان وقت الاسترداد: أولًا، احتفظ بقائمة مجلداتك الحسّاسة بعيدًا عن مجلدات الذاكرة المؤقتة والسجلات — مستودع أصغر يُستعاد أسرع. ثانيًا، اختبر دوريًا الاستعادة الجزئية لمجلد واحد (restic restore latest --target /tmp/test --include /etc) لمعايرة المدة الفعلية على بنيتك التحتية. أمر restic stats يعطي حجم المستودع للتخطيط.