إنتقل إلى المحتوى الرئيسي

الاستعداد للاستعادة

يوفّر Libre WebUI حصرًا للاستعادة للقراءة فقط بوصفه أول بوابة أمان للنسخ الاحتياطي والاستعادة. يبلغ عن الحالة المعروفة الموجودة والظروف المكتشفة التي تحظر أخذ لقطة. ولا يقتني قفل صيانة، ولا ينسخ البيانات أو يشفّرها أو يرفعها أو يحذفها أو يصلحها أو يستعيدها.

libre-webui recovery-check --json > recovery-inventory.json

من نسخة المصدر، شغّل npm run build:backend مرة واحدة واستبدل libre-webui recovery-check بـ npm run recovery:check --. تفحص تثبيتات npx وHomebrew المجمعة المسار ~/.libre-webui افتراضيًا؛ ويتجاوز DATA_DIR وخيارات المسار الصريحة ذلك الموقع.

ينتهي الأمر بالحالة 0 عند عدم العثور على حواجز، وبالحالة 1 عندما يكون التقرير مكتملًا لكن توجد حواجز للاستعادة، وبالحالة 2 للوسائط غير الصالحة أو فشل جمع غير متوقع. استخدم --data-dir PATH أو --database PATH لفحص موقع غير افتراضي. لا يقبل حصر وحدة افتراضية أو محددة بـ --data-dir إلا ملف DATA_DIR/data.sqlite القياسي، ويرفض إدخالات قاعدة البيانات أو WAL أو SHM ذات الروابط الصلبة أو الرمزية أو غير العادية. يمكن أن يقع مسار --database الصريح خارج DATA_DIR، لكن يجب أن تظل قاعدة البيانات المختارة وملفاتها المرافقة ملفات عادية لا روابط رمزية. عند استخدام --database بلا --data-dir، تعتبر الاستعادة المجلد الأب لقاعدة البيانات جذر البيانات حتى تُحصر معها المفاتيح والكائنات الثنائية وتعريفات المكوّنات المطابقة.

تقرأ بيئة التشغيل أيضًا تعريفات المكوّنات القديمة من دليل plugins الحتمي في حزمة الخادم الخلفي، ومن موقعها التاريخي النسبي للخادم الخلفي عندما يكون PLUGINS_DIR نسبيًا. تحصر الاستعادة تلك المسارات القديمة النشطة وتحظر لقطة الوحدة وحدها عندما تحتوي تعريفات مخصصة. ويمكن للنشرات المجمعة تمرير --legacy-plugins-dir PATH أكثر من مرة عندما تنقل بنية الصورة أدلة التوافق.

في نشر Compose الخاص، شغّله داخل الحاوية المنشورة كي يصف التقرير وحدتها المربوطة وشيفرتها وأسرارها:

docker exec libre-webui \
libre-webui recovery-check --json --data-dir /app/backend/data

ما يفحصه الحصر

يسجل تقرير JSON ذو الإصدار:

  • إصدارات التطبيق وNode.js ونظام التشغيل والبنية؛
  • أحجام ملف SQLite وWAL/SHM وquick_check والتحقق من المفاتيح الأجنبية وبصمة schema وإصدار المستخدم والجداول المطلوبة المفقودة والتحقق من ملف المصدر دون اتباع الروابط قبل إنشاء لقطة فحص خاصة؛
  • قابلية قراءة دليل البيانات وكتابته وعدد الملفات والبايتات؛
  • مصدر مفتاح التشفير المحدد وبصمة أحادية الاتجاه من 16 حرفًا؛
  • التحقق دون اتباع الروابط ومن رابط واحد لملف .encryption_key الدائم؛
  • وجود تعريفات المكوّنات المخصصة وأعدادها وأحجامها ووجودها ضمن دليل البيانات، إلى جانب جذر الكائنات الثنائية المحلية المشفّر والوسائط المضمّنة ومراجع الصوت ونص المستندات ومتجهات المستندات القديمة ومتجهات المنصة مع صفوف ACL والتصفية؛
  • مصادقة محدودة للقراءة فقط لكل كائن ثنائي محلي قياسي وغلاف متجه منصة مضمّن، بما في ذلك التحقق الكامل من أجزاء الكائن وchecksum وتوفر المفتاح المضبوط؛
  • مصادقة محدودة للقراءة فقط لكل غلاف نص AES-GCM قديم يمكن تمييزه عبر المحادثات والملاحظات والمستندات والتفضيلات وأسرار المكوّنات وحالة المعرض والوسائط وبريد الحساب، إلى جانب كل غلاف اسم صوت وتسجيل ونص صوتي مرتبط بـ AAD؛
  • أعداد مهام Work وعملياتها ومعايناتها ووحدات Docker أو PVC في Kubernetes أو هويات مسارات المضيف المجزأة المتوقعة؛ ويجب أن تحمل وحدات Docker كلًا من التصنيف المُدار ومعرّف المهمة المالكة الدقيق؛
  • حالات مهام توليد الوسائط القديمة والمهام الدائمة حسب الحالة والمحاولات حسب النتيجة وأعداد تدفقات الأحداث وأحداثها وآخر مؤشر أحداث عام؛
  • مصادقة محدودة للقراءة فقط لكل حمولة مهمة دائمة وحدث مشفّرة، والتحقق النحوي المحدود لكل حمولة مرجع opaque؛ و
  • حواجز وتحذيرات صريحة وبيانات تعيش خارج دليل بيانات التطبيق.

لا يتضمن التقرير مفاتيح التشفير أو أسرار JWT أو الجلسات أو بيانات اعتماد الموفّرين أو محتوى المكوّنات أو محتوى المستخدم أو مسارات مساحات عمل المضيف الحرفية. ولا يخرج سوى قيم منطقية لوجود الأسرار وبصمة مفتاح التشفير غير القابلة للعكس.

يُعد ربط البيانات للقراءة فقط صالحًا لفحص الاستعادة وينتج تحذيرًا لا حاجزًا. لكن جاهزية التطبيق لا تزال تتطلب تخزينًا قابلًا للكتابة؛ فلا تشغّل Libre WebUI على لقطة القراءة فقط التي يستخدمها مساعد النسخ الاحتياطي.

الحواجز

تعامل مع أي حاجز كفشل لبوابة الاستعادة. تشمل الحواجز المعتادة قاعدة بيانات مفقودة أو تالفة، أو schema ناقصًا، أو مفتاحًا غائبًا أو متعارضًا، أو نصًا مشفّرًا قديمًا أو خاصًا بالمنصة تالفًا أو غير موثّق، أو تجاوز حدود التحقق، أو دليل بيانات غير مقروء، أو مصدر SQLite مرتبطًا أو غير عادي، أو عمليات Work أو معاينات نشطة، أو مهام وسائط أو مهام دائمة، أو مساحة Work مفقودة أو مصنفة خطأ، أو عدم تطابق رأس حدث دائم أو فجوات تسلسل، أو تعريفات مكوّنات مخصصة خارج دليل البيانات، أو طبقة تحكم في بيئة التشغيل لا تستطيع التحقق من مساحات العمل الخارجية. أوقف الأعمال النشطة وحل الاعتماديات المفقودة قبل أخذ اللقطة؛ ولا تحرر التقرير لإخفاء حاجز.

تُصادق الحمولات الدائمة المشفّرة مقابل هوية المهمة أو الحدث وتُتحقق بوصفها JSON قياسيًا محدودًا. أما حمولات المراجع opaque فمحدودة ويُتحقق من صياغتها فقط: لا تملك البنية الحالية مستودع مراجع كائنات موثوقًا تستطيع الاستعادة بواسطته إثبات وجود الهدف أو الوصول إليه. يضع التقرير referenceTargetsVerified على false ويحذر كلما وجدت مثل هذه المراجع؛ ولا يكشف قيم الحمولة أو المرجع.

تسبق حقول النص القديمة إلزام علامة الغلاف، لذلك تظل صفوف النص الصريح الحقيقية من أجيال schema القديمة قابلة للقراءة ولا تُعد نصًا مشفّرًا موثّقًا. تُصادق الأغلفة القياسية دائمًا؛ وتفشل القيم ثلاثية الأجزاء ذات IV بعرض الغلاف أو وسم المصادقة بصورة مغلقة إذا تشوهت. تملك حقول الصوت المحفوظ غلافًا ثنائيًا لا لبس فيه، ويجب دائمًا مصادقته مقابل هوية الملف والمالك والحقل. يبلغ قسم JSON encryption.legacyCiphertext عن إجماليات سجلات النص أو البيانات الثنائية الموثقة والبايتات من دون كشف النص الصريح.

عند وجود عمود users.email_lookup في schema v4، تصادق الاستعادة أيضًا كل بريد غير null وتعيد حساب رمز بحثه ذي المفتاح والمفصول بالنطاق. يحظر اللقطة رمز مفقود أو غير مطابق، أو رمز مرتبط ببريد null. تظل قواعد ما قبل v4 متوافقة لأنها لا تملك عمود البحث المشتق هذا.

حدود النسخ الاحتياطي الحالية

يوقف مساعد النشر الخاص التطبيق إذا كان يعمل، ويستخدم صورة تلك الحاوية الثابتة ووحدة البيانات المربوطة والبيئة لإنشاء أرشيف solo متكامل. يُوقّع manifest بـ Ed25519 وتُشفّر الحمولة الكاملة بمفتاح نسخ احتياطي AES-256-GCM يحتفظ به المشغّل. ويحتوي SQLite والكائنات الثنائية المحلية والمتجهات المضمّنة ومحددات بيئة التشغيل والضبط المحمي اللازم لفك الحالة المستعادة. يتحقق المساعد من التوقيع وchecksum للنص المشفّر والحمولة المفكوكة قبل نشر الأرشيف وتقرير البيانات. لا يقبل libre-webui-restore إلا وحدة Docker جديدة، ويتحقق من حصر الاستعادة المفكوك قبل نسخ أي بيانات، وينشر الضبط المستعاد كملفات خاصة في دليل هدف جديد.

يشمل ضبط بيئة التشغيل المحمي مهلات pool والاتصال والخمول والتعليمة وقفل الهجرة في PostgreSQL، ومهلة اتصال Redis، وإعدادَي حصة الكائنات الدائمة، ومحددات المنصة، وبادئة S3 ووضع العنونة. تقع هذه القيم داخل الحمولة الموقعة والمشفّرة، لا manifest الصريح، وتُعاد نشرها كضبط بالوضع 0600 عند تطبيق الاستعادة.

لا يشمل أرشيف solo وحدات Docker لـ Work أو PVC في Kubernetes أو مجلدات مساحة العمل المرتبطة بالمضيف أو نماذج Ollama أو حالة الموفّرين الخارجيين. أبقِ هذه الاستثناءات في manifest الموقع ظاهرة، وخذ لقطات منفصلة لتخزين Work الخارجي. يستخدم ملف الفريق سيرًا منفصلًا بلا اتصال: تُختم لقطة PostgreSQL مصدّرة وكائنات S3 المشفّرة ذات الإصدارات الدقيقة وحصر PGVector وضبط بيئة التشغيل وهوية المفتاح في تنسيق الأرشيف الموقع والمشفّر نفسه، وتُتحقق مقابل هدف PostgreSQL/S3 نظيف عند الاستعادة. ويُعاد بناء cache Redis والحضور والتنبيهات والleases من حالة SQL القياسية.

تصادق نسخة الفريق أيضًا كل حمولة مشفّرة محدودة لمهمة دائمة وحدث داخل لقطة PostgreSQL المصدرة الدقيقة. يسجل حصرها المحمي الموقع إجماليات المهام والأحداث والتدفقات والمؤشرات والأغلفة والمراجع والنصوص الصريحة الموثقة. يجب أن يحتوي كل تدفق أحداث التسلسل المتصل 1..last_sequence بالضبط، وألا يتأخر تسلسل المؤشر العام في PostgreSQL عن أكبر مؤشر مخزن. تكرر الاستعادة هذه الفحوص على الهدف النظيف وتتطلب تطابق النتيجة الكاملة مع حصر المصدر الموقع قبل إعلان النجاح. الفجوات بين قيم المؤشر العام المختلفة صالحة لأن تخصيص identity في PostgreSQL ليس معاملاتيًا؛ أما تسلسلات كل تدفق فهي عقد الترتيب المتصل.

عندما يشير PLUGINS_DIR خارج DATA_DIR، تحصر الاستعادة ذلك الدليل بعينه وتضع علامة استبعاده من أرشيف وحدة التطبيق. تحظر أي تعريفات داخله اللقطة المقصورة على الوحدة حتى يرتب المشغّل لقطة مطابقة لدليل المكوّنات. تنطبق القاعدة نفسها على أدلة المكوّنات القديمة النشطة. تعريفات JSON الرمزية أو غير العادية أو غير المقروءة حواجز دائمًا، ولا تُتبع أو تُهمل بصمت.

المهام الدائمة والأحداث المرتبة نشطة في الملفين. تحظر الاستعادة ما دامت محاولة مهمة أو عملية Work نشطة، وتتحقق من حمولات المهام والأحداث ورؤوس التدفقات المتصلة، وتحفظ حالة SQL القياسية. يشغّل solo العامل المضمّن المحدود؛ ويشغّل team المعالجات المسجلة نفسها في عامل خارجي ويستخدم Redis للتنبيه والتوزيع فقط.

في الإنتاج، خزّن أسرار التشفير وJWT في مدير أسرار محمي، واحتفظ بأرشيفات النسخ الاحتياطي مشفّرة وخارج المضيف، واختبر الاستعادة في بيئة نظيفة متوافقة. الحصر لقطة أولية للحالة المعروفة، لا قفل صيانة ولا دليلًا مستقلًا على إمكانية استعادة كل مورد خارجي.

أوامر النسخ الاحتياطي الموقع والمشفّر

تستخدم الأمثلة أدناه أمر libre-webui المثبّت من npm العام أو Homebrew. من دون تثبيت عام، استبدل libre-webui بـ npx --yes libre-webui@latest. ومن نسخة المصدر، ابنِ الخادم الخلفي مرة واحدة واستبدل libre-webui backup بـ npm run recovery:backup --. تعرض صورة Docker الإنتاجية الأمر نفسه في /usr/local/bin/libre-webui. تتطلب استعادة الفريق ونسخه الاحتياطي أيضًا pg_dump وpg_restore من PostgreSQL 16؛ وهما مضمّنان في صورة الإنتاج ومسار أوامر صيغة Homebrew. ثبّت عميل PostgreSQL متوافقًا صراحةً قبل استخدام هذه الأوامر من npm أو npx العاديين.

ولّد مفتاح أرشيف AES-256-GCM الذي يحتفظ به المشغّل وزوج مفاتيح توقيع Ed25519 في دليل خاص، ثم انقل المفاتيح الخاصة إلى تخزين محمي خارج المضيف:

install -d -m 0700 /absolute/private/libre-backup-keys
libre-webui backup keygen \
--directory /absolute/private/libre-backup-keys

لدليل بيانات solo ساكن، أنشئ أرشيفًا وتحقق منه بصورة مستقلة:

libre-webui backup create \
--offline \
--data-dir /absolute/path/to/libre-data \
--output /absolute/backups/libre-solo.lwbackup \
--encryption-key /absolute/private/libre-backup-keys/backup-encryption.key \
--signing-private-key /absolute/private/libre-backup-keys/backup-signing-private.pem

libre-webui backup verify \
--archive /absolute/backups/libre-solo.lwbackup \
--encryption-key /absolute/private/libre-backup-keys/backup-encryption.key \
--signing-public-key /absolute/private/libre-backup-keys/backup-signing-public.pem

نفّذ فحص الاستعادة المسبق أولًا، ثم طبّقها على دليل هدف جديد وفارغ فقط:

libre-webui backup restore-preflight \
--archive /absolute/backups/libre-solo.lwbackup \
--target /absolute/restore/libre-data \
--encryption-key /absolute/private/libre-backup-keys/backup-encryption.key \
--signing-public-key /absolute/private/libre-backup-keys/backup-signing-public.pem

libre-webui backup restore-apply \
--archive /absolute/backups/libre-solo.lwbackup \
--target /absolute/restore/libre-data \
--encryption-key /absolute/private/libre-backup-keys/backup-encryption.key \
--signing-public-key /absolute/private/libre-backup-keys/backup-signing-public.pem

libre-webui backup restore-verify \
--target /absolute/restore/libre-data

لوضع team، أوقف كل نسخ التطبيق والعاملين، وأبقِ بيئة PostgreSQL/S3/keyring للمصدر محملة، وأنشئ الأرشيف المنسق:

libre-webui backup create-team \
--offline \
--output /absolute/backups/libre-team.lwbackup \
--encryption-key /absolute/private/libre-backup-keys/backup-encryption.key \
--signing-private-key /absolute/private/libre-backup-keys/backup-signing-private.pem

حمّل قبل الاستعادة متغيرات بيئة لقاعدة PostgreSQL منفصلة وفارغة وbucket S3 فارغًا ذا إصدارات. يتحقق الفحص المسبق من التوقيع والأرشيف المشفّر، ويثبت صحة الحصر المحمي، ويثبت أن قاعدة الهدف وبادئة bucket المختارتين فارغتان من دون نشر بيانات. يعيد التطبيق البيانات إلى الهدفين النظيفين، ويتحقق من schema PostgreSQL الناتج وكائنات S3 الدقيقة وسجلات PGVector، ويكتب ضبط بيئة التشغيل المحمي في دليل خاص جديد:

libre-webui backup restore-team-preflight \
--archive /absolute/backups/libre-team.lwbackup \
--encryption-key /absolute/private/libre-backup-keys/backup-encryption.key \
--signing-public-key /absolute/private/libre-backup-keys/backup-signing-public.pem

libre-webui backup restore-team-apply \
--archive /absolute/backups/libre-team.lwbackup \
--configuration-output /absolute/restore/libre-team-config \
--encryption-key /absolute/private/libre-backup-keys/backup-encryption.key \
--signing-public-key /absolute/private/libre-backup-keys/backup-signing-public.pem

لا توجّه استعادة مطلقًا إلى قاعدة المصدر أو bucket المصدر أو دليل بيانات موجود أو دليل ضبط يحتوي ملفات. احتفظ بمفتاح التوقيع العام مع دليل إجراءات الاستعادة؛ فامتلاك الأرشيف والمفتاح العام وحدهما لا يفك الحمولة.

إذا أبلغت استعادة الفريق أن rollback لم يكتمل، فاعتبر الهدفين المختارين ملوثين ولا تعد المحاولة فورًا. افحص قاعدة PostgreSQL الهدف ونظفها، ثم اسرد واحذف كل إصدار كائن وعلامة حذف تحت بادئة S3 الهدف الدقيقة. شغّل restore-team-preflight مجددًا؛ ولا تكون إعادة التطبيق آمنة إلا بعد نجاح فحص الهدف النظيف.

تمارين استعادة مجدولة ومتحقق منها

النسخ الاحتياطية التي لم تُستعد قط أمل لا استعادة. يثبت التمرين قابلية استعادة المثيل فعليًا بتشغيل خط الأنابيب الدقيق أعلاه من البداية إلى النهاية، من دون توقف أو مشغّل:

  1. تُجهز لقطة ساكنة من دليل البيانات: قاعدة SQLite عبر API النسخ الاحتياطي المتصل، والكائنات والملفات بنسخ مادي. ينتظر التمرين لحظة هادئة ويرفض العمل بينما تكون مهمة دائمة في منتصف التنفيذ، وهي قاعدة recovery-check نفسها.
  2. تصبح النسخة المجهزة أرشيفًا موقعًا ومشفّرًا بـ AES-256-GCM باستخدام مفاتيح تمرين مؤقتة، مع تشغيل حصر الاستعادة الكامل.
  3. يُتحقق من الأرشيف ويُستعاد إلى هدف مؤقت معزول، ثم يُتحقق من البيئة المستعادة مجددًا.
  4. يسجل التمرين ما قاسه: مدة الاستعادة هي RTO المثبت، والمسافة بين التمارين الناجحة تحد RPO الممكن للجدول الحالي، ثم يحذف كل عنصر. التمارين للتحقق لا للنسخ الاحتياطي؛ فلا يُحتفظ بأرشيف أو مفتاح.

فعّل الجدول باستخدام RECOVERY_DRILL_INTERVAL_HOURS (مثل 24)؛ ثم تعمل التمارين على المجدول المشترك تحت lease تنسيق، فلا تستطيع النسخ أو الدورات المتداخلة تشغيلها مرتين. تعرض صفحة النظام سجل التمارين مع زر «شغّل التمرين الآن» للمسؤولين، مدعومًا بـ GET /api/recovery/drills وPOST /api/recovery/drills/run. ينبه فشل تمرين غير مراقب كل مسؤول عبر صندوق الإشعارات (وأي أهداف webhook مشتركة)، بينما تعرض العمليات اليدوية سبب رفضها مباشرةً. يحد RECOVERY_DRILL_HISTORY السجل المحتفظ به (60 إدخالًا افتراضيًا).

تغطي التمارين ملف solo ‏(SQLite)، حيث أرشيف نظام الملفات هو مسار النسخ الاحتياطي الموثوق. يحتفظ ملف team بسير backup create-team المنسق، وتظل محاكاة استعادته خطوة يديرها المشغّل حاليًا.