لماذا تؤتمت نسخك الاحتياطية باستخدام Restic
غالبًا ما يستضيف خادم VPS بيانات لا يمكن تعويضها: قواعد بيانات، وأقراص تخزين Docker (volumes)، وملفات تهيئة. يلبّي Restic ثلاثة متطلبات أساسية لاستراتيجية جيدة: التشفير (AES-256، فالمستودع غير قابل للاستخدام دون كلمة المرور)، وإزالة التكرار (لا تُخزَّن الكتل المتطابقة إلا مرة واحدة، ما يقلّص الحجم والتكلفة تقليصًا كبيرًا)، ودعم واجهات تخزين متنوّعة (S3 وBackblaze B2 وSFTP والتخزين المحلي). واستضافة Restic ذاتيًا على الخادم بدلًا من الاعتماد على خدمة نسخ احتياطي مُدارة تمنحك تحكّمًا كاملًا في التشفير: يبقى المفتاح لديك، ولا يرى مزوّد التخزين سوى كتل بيانات مبهمة. وهذا هو أساس استراتيجية 3-2-1 جادّة.
ما الذي يقدّمه لك Restic
- تشفير AES-256 من جهة العميل: لا ترى واجهة التخزين سوى بيانات غير قابلة للقراءة.
- إزالة التكرار على مستوى الكتل تقلّص كثيرًا حجم النسخ الاحتياطية المتتالية وتكلفتها.
- لقطات تزايدية سريعة: لا تُنقَل سوى الكتل الجديدة في كل تشغيلة.
- واجهات تخزين متعددة (S3 وBackblaze B2 وSFTP وrest-server والتخزين المحلي) دون تغيير سير العمل.
- استعادة دقيقة: ملف واحد أو مجلد أو لقطة كاملة عبر
restic restore. - سياسة احتفاظ مؤتمتة عبر
forget --prune(الاحتفاظ بـ N نسخة يومية، وM نسخة أسبوعية...).
قاعدة 3-2-1: لماذا لا تكفي لقطات مزوّد الاستضافة
تفعيل اللقطات (snapshots) لدى مزوّد خادمك VPS أمر مفيد، لكنه ليس استراتيجية نسخ احتياطي: إنه نسخة إضافية واحدة، لدى المزوّد نفسه، تشارك خادمك مصيره. وثلاثة سيناريوهات توضّح ذلك. إذا حُذف الخادم (خطأ في التعامل، أو فاتورة غير مدفوعة، أو إنهاء للعقد)، فكثيرًا ما تختفي لقطاته معه. وإذا استولى مهاجم على حسابك لدى المزوّد، فإنه يمحو الخادم واللقطات ببضع نقرات أو عبر واجهة API. كما أن اللقطة لا تُستعاد أبدًا على سبيل الاختبار: فقاعدة بيانات جُمّدت في أثناء الكتابة قد تتبيّن عدم صلاحيتها يوم تحتاج إليها.
تعالج قاعدة 3-2-1 هذه المخاطر الثلاثة: ثلاث نسخ من البيانات، على وسيطين مختلفين، واحدة منها خارج المزوّد، مشفّرة قبل مغادرة الخادم. ويبني Restic هذه الحلقة الأخيرة تحديدًا، وهي الوحيدة التي تصمد أمام فقدان حساب الاستضافة بالكامل.
النسخ الثلاث لاستراتيجية 3-2-1 على خادم VPS
- النسخة 1، البيانات الحية على قرص الخادم: إنها الأصل، ومصدر أسرع عمليات الاستعادة.
- النسخة 2، لقطات المزوّد: تغطي تحديثًا فاشلًا أو خطأً في الإعدادات بإعادة الجهاز كله إلى حالة سابقة.
- النسخة 3، مستودع Restic لدى مزوّد آخر للتخزين الكائني: مشفّر من جهة العميل، ويبقى بعيدًا عن متناول لوحة تحكم مزوّد الاستضافة.
- وسيطان منفصلان فعلًا: قرص الخادم من جهة، والتخزين الكائني لطرف ثالث من جهة أخرى، مع بيانات اعتماد مختلفة.
المتطلبات المسبقة لهذا النشر
Restic أداة مقتصدة: تعمل على أي خادم VPS، حتى بوحدة vCPU واحدة وذاكرة 1 غيغابايت، إذ تستهلك إزالة التكرار قليلًا من الذاكرة بما يتناسب مع حجم المستودع. تحتاج إلى الملف التنفيذي restic، وإلى واجهة تخزين وجهة بعيدة (سلّة متوافقة مع S3 لدى مزوّد، أو خادم آخر عبر SFTP) وبيانات اعتمادها. ولا حاجة إلى Docker هنا: فـ Restic أداة سطر أوامر.
تحقّق من الإصدار الذي توفّره توزيعتك: يوفّر Debian 13 وUbuntu 26.04 الإصدار 0.18، لكن Ubuntu 24.04 ما زال على 0.16.4 وDebian 12 على 0.14.0، وهو أقدم من أن يدعم الخيار --stdin-from-command المستخدم أدناه (الذي ظهر في 0.17.0). في هذه الحالة، ثبّت الملف التنفيذي الرسمي من صفحة الإصدارات (0.19.1، الصادر في 5 يوليو 2026): فهذه الملفات الرسمية وحدها تتضمن الأمر restic self-update، أما حزمة التوزيعة فتُحدَّث عبر apt. وأخيرًا، جهّز مؤقّت systemd (أو cron) للأتمتة، ومكانًا آمنًا خارج الخادم لحفظ كلمة مرور المستودع.
Backblaze B2 أم Cloudflare R2: اختيار واجهة S3
مرّر الجدول أفقيًا
| المعيار | Backblaze B2 | Cloudflare R2 |
|---|---|---|
| التخزين المجاني | أول 10 غيغابايت | 10 غيغابايت-شهر كل شهر (الفئة Standard) |
| خروج البيانات (egress) | مجاني حتى 3 أضعاف متوسط الحجم المخزَّن في الشهر، ودون حد نحو شبكات CDN الشريكة (Cloudflare وFastly) | مجاني دون سقف |
| نقطة نهاية S3 | خاصة بمنطقة الحساب، مثل `s3.us-west-004.backblazeb2.com` | `<account-id>.r2.cloudflarestorage.com`، والمنطقة `auto` |
| مفاتيح الوصول | مفتاح Application Key مخصّص: فواجهة S3 ترفض المفتاح الرئيسي | رمز API لـ R2 بصلاحيات قراءة الكائنات وكتابتها |
| نقطة انتباه | قد تتجاوز الاستعادات الكاملة المتكرّرة حصة الخروج المجانية | لا تضيف اختبارات الاستعادة المنتظمة أي تكلفة خروج |
إعداد نسخ احتياطية مؤتمتة باستخدام Restic
تثبيت Restic وتجهيز ملف البيئة
ثبّت
restic(حزمة حديثة أو الملف التنفيذي الرسمي، انظر المتطلبات)، ثم أنشئ الملف/root/.restic-env. اكتبه أسطرًا بسيطة على صيغةKEY=value، دونexport: فهذه هي الصيغة التي يقرؤها توجيهEnvironmentFile=في systemd، كما يمكن تحميلها في الصدفة (shell). ومع Restic، يُفضَّل استخدام B2 عبر واجهته المتوافقة مع S3:# /root/.restic-env (Backblaze B2, S3 API) RESTIC_REPOSITORY=s3:https://s3.us-west-004.backblazeb2.com/my-bucket RESTIC_PASSWORD=change-me AWS_ACCESS_KEY_ID=b2-key-id AWS_SECRET_ACCESS_KEY=b2-application-key # Cloudflare R2 # RESTIC_REPOSITORY=s3:https://<account-id>.r2.cloudflarestorage.com/my-bucketقيّد صلاحيات الملف، ثم حمّله في جلستك:
chmod 600 /root/.restic-env set -a; . /root/.restic-env; set +aتهيئة المستودع المشفّر
restic initينشئ هذا الأمر بنية المستودع ويختم التشفير بكلمة مرورك؛ كما تضغط المستودعات الحديثة (الصيغة 2، منذ Restic 0.14.0) البيانات أيضًا. احفظ كلمة المرور هذه خارج الخادم، في مدير كلمات مرور أو خزنة على جهاز آخر: فدونها تستحيل أي استعادة، حتى لو امتلكت السلّة كاملة.
تشغيل أول نسخة احتياطية
انسخ مجلداتك الحرجة احتياطيًا، ثم قواعد بياناتك. ولتفريغ قاعدة بيانات، فضّل
--stdin-from-commandعلى أنبوبpg_dump | restic backup --stdin: إذ لا يستطيع Restic أن يعرف إن كان التدفق المقروء من الدخل القياسي مكتملًا، وتفريغ يفشل في منتصفه سينتج لقطة مبتورة دون أي خطأ. أما مع--stdin-from-command، فإن رمز خروج غير صفري من الأمر يلغي النسخ ولا تُنشأ أي لقطة.restic backup /etc /var/www /opt/docker-data restic backup --stdin-filename mydb.sql --stdin-from-command -- pg_dump -U postgres mydb restic snapshotsتحديد سياسة الاحتفاظ
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --pruneسبع نسخ يومية تغطي أسبوعًا كاملًا، وهذا يكفي لاكتشاف تلف لا يظهر إلا بعد بضعة أيام. وأربع أسبوعية تفتح نافذة شهر لمشكلة تطبيقية بطيئة، كبيانات تختفي شيئًا فشيئًا. وست شهرية تتيح العودة إلى حالة سابقة لعملية ترحيل فاشلة. أما تمريرة
--pruneفلا غنى عنها: فالأمرforgetوحده يزيل اللقطات من القائمة دون تحرير المساحة، وتستمر فاتورة التخزين في الارتفاع.التحقق من السلامة: check ثم read-data
هذه الأوامر لا تتحقق من الشيء نفسه:
restic check restic check --read-data-subset=10% restic check --read-dataيتحقق
restic checkمن بنية المستودع (اللقطات والأشجار والفهارس والحزم) دون قراءة محتوى ملفات البيانات: فهو سريع ويُشغَّل بعد كلforget --prune. أما--read-dataفينزّل كل الحزم ويتحقق منها، وهذا يستغرق وقتًا ويستهلك عرض نطاق الخروج. وبينهما، يتحقق--read-data-subsetمن جزء عشوائي (10%، أو حجم مثل5G) أو من شريحة ثابتة (من1/5إلى5/5، لتغطية الكل في خمس مرات). والتحقق الجزئي كل أسبوع والكامل مرة في الشهر حلّ وسط جيد.كتابة سكربت النسخ وخدمة systemd الخاصة به
اجمع الخطوات في سكربت واحد. يكتب أولًا ملفًا حارسًا (sentinel) مختومًا بالوقت، سيُستخدم في اختبار الاستعادة، ويتوقف عند أول خطأ بفضل
set -eu:#!/bin/sh # /usr/local/bin/restic-backup.sh set -eu date +%s > /opt/restic-sentinel.txt restic backup /etc /var/www /opt/docker-data /opt/restic-sentinel.txt restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune restic checkوتشغّله الخدمة بمتغيرات ملف البيئة، دون أن يظهر أي سرّ في تعريف الوحدة:
# /etc/systemd/system/restic-backup.service [Unit] Description=Restic backup After=network-online.target Wants=network-online.target [Service] Type=oneshot EnvironmentFile=/root/.restic-env ExecStart=/usr/local/bin/restic-backup.shالجدولة بمؤقّت systemd
يُطلق المؤقّت الخدمة كل ليلة. يعوّض
Persistent=trueتشغيلًا فائتًا إن كان الخادم مطفأً في الموعد المحدد، ويوزّعRandomizedDelaySec=900الانطلاق على خمس عشرة دقيقة، وهذا مفيد حين تستهدف عدة خوادم السلّة نفسها:# /etc/systemd/system/restic-backup.timer [Unit] Description=Daily restic backup [Timer] OnCalendar=*-*-* 03:00:00 Persistent=true RandomizedDelaySec=900 [Install] WantedBy=timers.targetفعّله، ثم تحقّق من الموعد التالي ومن سجلات آخر تشغيل:
chmod 700 /usr/local/bin/restic-backup.sh systemctl daemon-reload systemctl enable --now restic-backup.timer systemctl list-timers restic-backup.timer journalctl -u restic-backup.service --since todayوإن كنت تفضّل
cron، فإن سطرًا0 3 * * *يحمّل ملف البيئة ثم يستدعي السكربت نفسه يؤدي الغرض، دون التعويض الذي يوفّرهPersistent=.أتمتة اختبار الاستعادة
النسخة الاحتياطية التي لم تُستعَد قط تبقى مجرد فرضية. يستعيد هذا السكربت الثاني الملف الحارس وحده من آخر لقطة ويقارنه بالأصل: فإن فشل نسخ الليلة أو لم يعد المستودع يُرجع شيئًا، يفشل
cmpوتنتقل الخدمة إلى الحالةfailed. ويستهدف الاختبار أحدث لقطة: فإن أضفت إلى سكربت النسخ عمليات تفريغ عبر--stdin-from-command، فضعها قبل نسخ الملفات، الذي يجب أن يبقى الأخير.#!/bin/sh # /usr/local/bin/restic-restore-test.sh set -eu rm -rf /tmp/restic-test-restore restic restore latest --target /tmp/restic-test-restore --include /opt/restic-sentinel.txt cmp /tmp/restic-test-restore/opt/restic-sentinel.txt /opt/restic-sentinel.txtجدوِله أسبوعيًا، بعد نسخ الليلة:
# /etc/systemd/system/restic-restore-test.service [Service] Type=oneshot EnvironmentFile=/root/.restic-env ExecStart=/usr/local/bin/restic-restore-test.sh # /etc/systemd/system/restic-restore-test.timer [Timer] OnCalendar=Sun 05:00:00 Persistent=true [Install] WantedBy=timers.targetفعّل المؤقّت بالأمر
systemctl enable --now restic-restore-test.timer، واربط الحالةfailedللخدمتين بنظام المراقبة لديك. ومرة كل ثلاثة أشهر، استعد أيضًا مجلدًا حقيقيًا، بما فيه قاعدة بيانات، على جهاز اختبار.
أسرار Restic: ملف معزول، لا تُكتب أبدًا داخل الوحدة
لا تضع أبدًا RESTIC_PASSWORD ولا مفاتيح S3 في سطر Environment= ضمن وحدة systemd، ولا في سكربت خاضع لنظام إدارة الإصدارات، ولا في ملف Dockerfile: فالمتغيرات المعرَّفة في الوحدة يمكن قراءتها بالأمر systemctl show. أما الملف /root/.restic-env بصلاحيات chmod 600، المحمَّل عبر EnvironmentFile=، فيُبقي الأسرار خارج تعريف الوحدة. وللذهاب أبعد، يعرض التوجيه LoadCredential= في systemd السرّ داخل مجلد مخصّص للخدمة ($CREDENTIALS_DIRECTORY): فيقرأ Restic عندها كلمة مروره عبر RESTIC_PASSWORD_FILE.
استكشاف الأخطاء: الأعطال الشائعة
فشل restic init أو أول backup على السلّة. تحقّق أولًا من تحميل المتغيرات (echo $RESTIC_REPOSITORY)، ثم من نقطة النهاية: يجب أن تطابق على B2 منطقة حسابك، واستخدام نقطة نهاية AWS (s3.amazonaws.com) خطأ شائع. كما يحتاج مفتاح Application Key على B2 المقصور على سلّة واحدة إلى الصلاحية listAllBucketNames ليعمل مع أدوات S3، والمفتاح الرئيسي للحساب لا يعمل مع واجهة S3. وعلى R2، يجب أن يملك الرمز صلاحيات قراءة كائنات السلّة وكتابتها.
المؤقّت لا ينطلق. تكفي ثلاثة أوامر: 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 list locks، ويزيل restic unlock الأقفال المتقادمة. تأكّد قبل ذلك من عدم وجود أي عملية Restic أخرى قيد التشغيل.
الأمر restic check --read-data طويل جدًا. على مستودع بعشرات الغيغابايتات، تستغرق القراءة الكاملة ساعات وتثقل حصة الخروج. انتقل إلى --read-data-subset=10% أو إلى شريحة 1/4 كل أسبوع، واحتفظ بالقراءة الكاملة لصيانة شهرية.
خطة الاستئناف: كم يستغرق استرجاع كل شيء؟
تعتمد مدة الاستعادة الكاملة على حجم المستودع، وعرض النطاق بين الخادم والسلّة، وسياسة الخروج لدى المزوّد. على R2، الخروج مجاني: فلا شيء يضطرك إلى توزيع الاستعادة على فترات. وعلى B2، هو مجاني حتى ثلاثة أضعاف متوسط الحجم المخزَّن في الشهر؛ وما زاد على ذلك، تُفوتَر الاستعادة الكاملة لمستودع كبير.
لا تخمّن هذه المدة، بل قِسها. يعطي restic stats حجم المستودع؛ ثم استعد مجلدًا ذا دلالة (restic restore latest --target /tmp/test --include /etc) وقِس زمن العملية لتستنتج الباقي. وممارستان تختصران الاستئناف: ألّا تنسخ إلا ما يهم (لا ذاكرات مؤقتة ولا سجلات ولا /tmp ولا مجلدات Docker مهجورة)، وأن تدوّن في إجراءاتك ترتيب إعادة التشغيل، قواعد البيانات أولًا، ثم التطبيقات التي تعتمد عليها.
احمِ نسخك الاحتياطية من برامج الفدية (ransomware) بتفعيل وضع "append-only" في واجهة التخزين: انشر rest-server بعيدًا مع الخيار --append-only، أو استخدم سلّة S3 مع سياسة IAM تمنع عمليات الحذف. وبذلك، حتى لو اخترق مهاجمٌ خادمك وحصل على بيانات الاعتماد، فلن يتمكّن من محو لقطاتك الحالية ولا تشفيرها. وامزج ذلك بتشغيل restic forget --prune من جهاز منفصل يملك وحده صلاحيات الحذف.