كيف جهزنا موقعًا على استضافة مشتركة لصيانة الخادم باستخدام Cloudflare Workers
الإجابة السريعة
نعم، يمكن لموقع PHP يعتمد غالبًا على المحتوى الثابت أن يبقى مفيدًا أثناء تعطل الأصل من دون نقل الحساب الحي. وضعنا Worker أمام KeyboardTester.click: تمر الاستجابات السليمة كما هي، وعند فشل الشبكة أو أخطاء خادم محددة تُعرض نسخة ثابتة معدّة مسبقًا. تعود الخدمة تلقائيًا مع أول استجابة أصل سليمة. هذا نمط استمرارية عملي وليس استضافة بلا توقف لكل شيء؛ فالنماذج والبريد وميزات الذكاء الاصطناعي والحفظ ما زالت تحتاج الخادم الأصلي.
أعطانا إشعار الاستضافة نافذة صيانة مدتها ست ساعات من دون مدة انقطاع دقيقة. انتظار رسالة «الخادم متوقف» يترك فجوة يدوية، وتحويل DNS إلى صفحة صيانة واحدة يحافظ على التنبيه فقط ولا يحافظ على الصفحات والأدوات التي جاء الزائر من أجلها.
هذه دراسة للحل الذي شغّلناه فعلًا على KeyboardTester.click: ماذا أوضحت تذكرة HostArmada، وكيف يقرر Worker، وكيف بنينا النسخة، ومشكلة التكرار داخل النطاق، وحدود الخطة المجانية، وسلوك SEO والإعلانات والتحليلات، والقيود التي لم نحاول إخفاءها.
ملاحظة زمنية: حتى 18 يوليو 2026 لم تبدأ الصيانة المجدولة بعد. النتائج هنا من محاكاة فشل الأصل والمعاينة الخاصة والتدقيق الكامل ومرور الأصل السليم، وليست من نافذة الصيانة الفعلية.
ما الذي أوضحته تذكرة HostArmada؟
كانت نافذة الصيانة في 22 يوليو 2026 من 10 صباحًا إلى 4 مساءً بتوقيت وسط الولايات المتحدة. سألنا هل تعني ست ساعات متواصلة، وهل يمكن نقل الحساب مؤقتًا، وما الخدمات المتأثرة، وهل يمكن توفير نقطة خارجية تعيد 503 Service Unavailable لكل عنوان، وما إجراءات الرجوع والتعويض.
بعد التصعيد أوضحت الإدارة أن الست ساعات نافذة محجوزة وليست مدة توقف مؤكدة. كان المتوقع أن يكون الانقطاع أقصر، لكن لا يمكن تحديده مسبقًا لأن العمل يشمل تغييرات عتاد وتحديثات وفحصًا بعد الصيانة. ورأت الشركة أن نقل الحساب ثم إعادته قد يضيف مخاطر DNS ومزامنة البريد والملفات وقاعدة البيانات.
عرضت الشركة خيارًا معقولًا لصفحة صيانة: مضيف افتراضي على خادم غير متأثر مع تغيير سجل A يدويًا عند البدء ثم إعادته. يستمر DNS الخارجي في الحل، لكن الويب وقاعدة البيانات والبريد ولوحة التحكم على الخادم تتوقف. النسخ الاحتياطية وخطوات الاسترداد قائمة، ويُراجع أي تعويض بعد معرفة الأثر الفعلي. كان العرض مناسبًا للإشعار، لكنه يدوي ولا يحافظ على موقع وظيفي، لذلك اعتبرناه خط أساس لا تقصيرًا من المزود.
That offer was fair for a maintenance notice. It was still manual and did not provide functional-site continuity, so we used it as the baseline to improve rather than portraying it as a provider failure.
تسلسل الأدلة: من بريد الصيانة إلى طبقة استمرارية مختبرة
يفصل هذا التسلسل بين ما أعلنه المزود، وما سألناه، وما بنيناه واختبرناه، وما لم تثبته نافذة الصيانة الفعلية بعد.
- يوليو 2026 — وصول بريد الصيانة
إشعار خادم Start Dock المشترك حجز 22 يوليو من 10:00 إلى 16:00 CDT، وذكر ترقية CPU وRAM وSSD، وتحديثات أمان وبرامج خادم الويب وkernel، وتنظيف tmp وcache وlogs وتحسينًا عامًا، مع وصف الإجراء بأنه غير قابل للعكس بعد البدء.
- خادم Start Dock على استضافة مشتركة
- 22 يوليو 2026، 10:00–16:00 CDT
- ترقية CPU وRAM وSSD
- تحديثات أمان وبرامج خادم الويب
- تحديث kernel
- تنظيف tmp وcache وlogs
- تحسين عام للخادم
- الإجراء غير قابل للعكس بعد البدء
- 16 يوليو — تصعيد أسئلة الاستمرارية
سألنا عن مدة الانقطاع الحقيقية، والنقل المؤقت، ونقطة 503 خارجية، وخدمات الويب وقاعدة البيانات والبريد، والنسخ والرجوع والتعويض.
- 17 يوليو — رد إدارة HostArmada
قال المزود إن الست ساعات نافذة، وتوقع توقفًا أقصر غير محدد، ورفض نقل الحساب لمخاطر المزامنة، وعرض vhost غير متأثر مع تغيير A يدوي.
- اختيار التصميم في 17 يوليو؛ إرسال المتابعة في 18 يوليو
اخترنا Worker دائمًا يبدأ بالأصل ثم نسخة ثابتة، مع معاينة خاصة وفحص تصادم المسارات و503 واضح وخطة رجوع.
- 17–18 يوليو — تنفيذ واختبارات مضبوطة
التقطنا 1,514 صفحة و1,234 أصلًا، ودققنا 2,748 مسارًا، واختبرنا الفشل والمرور، وأصلحنا حلقة النطاق وفعّلنا مساري apex وwww بنمط fail-open.
- 18 يوليو — جاهز ولم يثبت بالحدث بعد
طبقة الاستمرارية حية ومختبرة، لكن صيانة 22 يوليو لم تقع بعد؛ أرقام المرور الفعلي والإيراد ومدة الحدث تنتظر أدلة ما بعده.


البنية: الأصل أولًا والنسخة عند الحاجة فقط
يعمل Worker دائمًا على مساري النطاق الأساسي وwww. يطلب الأصل الحقيقي بمهلة محدودة؛ وإذا كانت الاستجابة سليمة يمررها كما هي، فتظل PHP والجلسات والرؤوس والإعلانات والتحليلات طبيعية.
عند فشل الاتصال أو انتهاء المهلة أو ظهور 500 أو 502 أو 503 أو 504 أو أخطاء Cloudflare من 520 إلى 527 يبحث Worker عن المسار نفسه في الأصول الثابتة. تستمر طلبات GET وHEAD، وكل طلب تالٍ يجرب الأصل مجددًا فتكون العودة تلقائية.
النسخة ليست خادم PHP ثانيًا. هذا يتجنب قاعدتي بيانات قابلتين للكتابة وتعارض الجلسات والبريد ومصالحة البيانات بعد الصيانة.
تدفق الطلب باختصار

صفحة صيانة من المزود أم استمرارية عبر Worker؟
كلاهما مفيد. صفحة الصيانة تكفي إذا كان المطلوب دلالة HTTP صحيحة، أما النسخة الثابتة فتناسب موقعًا يحتاج إبقاء أغلب رحلة القراءة والأدوات التي تعمل في المتصفح.
| السؤال | مضيف المزود المؤقت | Worker دائم |
|---|---|---|
| التحويل | تغيير DNS يدوي في البداية والنهاية | تلقائي لكل طلب |
| ما يراه الزائر | صفحة صيانة واحدة | الصفحة أو الأداة أو الأصل المطابق |
| الكتابة | غير متاحة | غير متاحة؛ 503 واضح |
| العودة | إعادة DNS يدويًا | تلقائية عند سلامة الأصل |
| مخاطر اتساق البيانات | منخفضة بلا قاعدة ثانية | منخفضة بلا قاعدة ثانية |
| التشغيل | صفحة بسيطة لكن تحتاج شخصًا في الموعد | إعداد واختبار أكثر، تدخل قليل أثناء الحدث |
ماذا يرى المستخدم ومحرك البحث عند الفشل؟
تستمر الصفحات والأدوات العميلية والأنماط والبرامج والصور والخطوط من النسخة، مع تنبيه صغير وصادق. تبقى العناوين الأساسية والبيانات المنظمة على عناوين النطاق الأصلية.
لم نتظاهر بأن عمليات الكتابة تعمل. تعيد طلبات POST والإجراءات غير المتاحة 503 مع Retry-After: 300 وCache-Control: no-store. يعرّف RFC 9110 الرمز 503 للصيانة المؤقتة ويسمح بتحديد وقت إعادة المحاولة.
This distinction matters: returning a pretty 200 OK “maintenance” page for a failed form can mislead users and crawlers. Returning a controlled 503 for the unavailable action is both more honest and easier for clients to retry.
مصفوفة قرار fallback الفعلية
| نتيجة الأصل | GET / HEAD | POST أو كتابة |
|---|---|---|
| استجابة سليمة أو تحويل أو 4xx أو حالة خارج مجموعة الفشل | تمرير استجابة الأصل بلا تعديل | تمرير استجابة الأصل بلا تعديل |
| فشل شبكة أو مهلة 4.5 ثانية | المسار المطابق من النسخة؛ 503 إن لم يوجد | 503 + Retry-After: 300 + no-store |
| 500 أو 502 أو 503 أو 504 أو 520–527 | المسار المطابق مع ترويسة تشخيص لحالة الأصل | 503 + Retry-After: 300 + no-store |
| مسار آمن مجهول أثناء غياب الأصل | 503 مضبوط؛ لا صفحة مخترعة ولا الرئيسية 200 | لا ينطبق |
كيف بنينا النسخة واختبرناها؟
زحفنا الموقع الحي المعروض بدل شجرة PHP المحلية لأنها تحتوي تغييرات غير منشورة. التقطنا 1,514 صفحة معروضة و1,234 أصلًا داخليًا. بلغ الإصدار 2,749 ملفًا بحجم يقارب 547.6 ميغابايت، وكل ملف دون حد Cloudflare.
حافظنا على canonical وschema، وأصلحنا مراجع نسبية قديمة داخل النسخة فقط، وأزلنا أدوات التتبع أثناء الالتقاط. يضيف Worker في الإنتاج GA4 وAdSense وClarity للصفحة الرئيسية فقط، بينما تبقى المعاينة الخاصة بلا تتبع ومع noindex.
شملت الجودة فحوص TypeScript والوحدات، وتعطلًا محليًا مصطنعًا، ومعاينة موثقة، وفحص متصفح، ومعاينة الأصل، وتدقيقًا بعيدًا نجح في جميع مسارات الصفحات والأصول العامة وعددها 2,748.
- أكد الخدمات المتوقفة وفرق نافذة الصيانة عن مدة الانقطاع.
- ابنِ من الإنتاج المعروض إذا لم تكن الشجرة المحلية نسخة نشر دقيقة.
- احصر الصفحات والأصول وافحص حدود العدد والحجم.
- اجعل المعاينة خاصة وnoindex واختبر الفشل والمرور السليم.
- حدد المهلة والأكواد والطرق الآمنة و503 وخطة الرجوع.
- امنع حلقة الطلب داخل النطاق مع الحفاظ على Host الأساسي.
- اختر fail-open فقط عندما يكون تجاوز العامل أكثر أمانًا.
- وثّق الوظائف غير المتاحة وحدّث النسخة بعد التغييرات.

إعادة بناء الإعداد بأمان: خطوات عملية وكود منقح
1. حدّد العقد أولًا. عيّن النطاقات والطرق الآمنة وأكواد الفشل والمهلة وسلوك المسار المفقود وخطة إزالة المسارات. لا تعتبر كل استجابة غير 200 عطلًا؛ فقد يكون التحويل أو 404 أو رفض الدخول صحيحًا.
2. ازحف الإنتاج المعروض. ابدأ من sitemap الأساسية واجمع موارد النطاق نفسه من HTML وCSS، وطبع الروابط، وامنع traversal، وافشل البناء إذا تجاوز عدد الملفات أو حجمها حدود المنصة.
3. حافظ على المعنى وأزل الاعتماد. احتفظ بـcanonical وhreflang وschema والروابط وملفات أدوات المتصفح. أزل service worker والتتبع من النسخة، وأضف تنبيهًا خفيفًا فقط، ثم احقن الإعلان والتحليلات في وضع الإنتاج.
4. اربط الأصول بالـWorker. استخدم ASSETS وrun_worker_first حتى يفحص الأصل قبل النسخة. الأمثلة أدناه placeholders ولا تحتوي أي معرف حساب أو عنوان أصل.
5. امنع تكرار النطاق. استخدم اسم DNS-only مضبوطًا داخل النطاق نفسه لـresolveOverride مع بقاء URL وHost أساسيين، واختبر TLS والـvirtual host مباشرة.
6. ابدأ بمعاينة خاصة. سر دخول، وnoindex، وrobots حاجب، ولا إعلانات أو تحليلات، ووضع origin preview للمقارنة.
7. اربط المسارين واحدًا واحدًا. ارفض التصادم، اختبر apex ثم www وتحويله، واجعل التفعيل fail-open إذا كان Worker للاستمرارية لا للأمن.
8. اجعل الرجوع مستقلًا. إزالة المسارين المملوكين تعيد المرور إلى الأصل فورًا بلا حذف Worker أو تغيير DNS، ثم اسحب صلاحيات التحرير المؤقتة.
إعداد منقح للـWorker والأصول الثابتة
{
"name": "example-host-outage-fallback",
"main": "src/index.ts",
"compatibility_date": "2026-07-17",
"assets": {
"directory": "./snapshot/dist",
"binding": "ASSETS",
"run_worker_first": true,
"html_handling": "none",
"not_found_handling": "none"
},
"vars": {
"MODE": "production",
"ORIGIN_BASE": "https://example.com",
"ORIGIN_RESOLVE_OVERRIDE": "origin-bypass.example.com",
"ORIGIN_TIMEOUT_MS": "4500"
}
}قرار الأصل ومصفوفة أكواد fallback
const FALLBACK_STATUSES = new Set([
500, 502, 503, 504, 520, 521, 522, 523, 524, 525, 526, 527
]);
try {
const origin = await fetch(originRequest, {
signal: AbortSignal.timeout(4500),
redirect: "manual",
cf: { resolveOverride: "origin-bypass.example.com" }
});
if (!FALLBACK_STATUSES.has(origin.status)) return origin;
return serveSnapshot(request, origin.status);
} catch {
return serveSnapshot(request);
}503 صادق لعمليات الكتابة
if (!new Set(["GET", "HEAD"]).has(request.method)) {
return new Response("Temporarily unavailable", {
status: 503,
headers: {
"Retry-After": "300",
"Cache-Control": "no-store",
"Content-Type": "text/plain; charset=utf-8"
}
});
}البناء والمعاينة والتفعيل والرجوع
# Build from rendered production and validate the package
python scripts/build_snapshot.py
npm run types
npm run check
npx wrangler deploy --env staging --dry-run
# Deploy and test the private preview (use your own secret securely)
npx wrangler deploy --env staging
python scripts/smoke_staging.py --base "https://<private-preview>" --password "<secret>"
# Inspect, activate, or remove only the owned routes
python scripts/manage_routes.py status
python scripts/manage_routes.py activate --confirm ACTIVATE-KBT-FALLBACK
python scripts/manage_routes.py deactivate --confirm REMOVE-KBT-FALLBACKخطة الاختبار: أثبت الفشل والمرور والعودة
اختبر الرئيسية والأداة الأساسية وCSS/JS ومقالًا والعربية RTL وصفحة مترجمة طويلة وrobots ومسارًا مفقودًا وHEAD وPOST وتحويل www والثيمين على الهاتف.
في وضع snapshot تحقق من الترويسة وcanonical وH1 وJSON-LD والأصول والتنبيه. وفي origin preview تحقق من الوصول بلا حلقة. وفي المرور الحي السليم تأكد من غياب ترويسة fallback ومن بقاء الاستجابة والتحويل والتتبع كما هي.
لا تكسر الأصل الحي للاختبار. استخدم معاينة خاصة أو أصل فشل منفصل، وسجل وقت بناء النسخة وhash للـmanifest.
الرجوع والمراقبة والعودة بعد الحدث
الرجوع الفوري هو إزالة مسارات Worker المملوكة فقط، لا تغيير DNS ولا حذف Worker. افحص apex وwww مباشرة، وامسح cache فقط إذا بقي HTML قديم، واترك Worker منشورًا حتى يستقر الأصل.
أثناء الحدث راقب ترويسات fallback وحالة الأصل والسجلات والصفحات الحرجة واستجابات 503. العودة تلقائية مع أول استجابة سليمة. وبعد الحدث ثبّت الاستقرار، واسحب الصلاحيات المؤقتة، واحفظ القياسات وحدّث النسخة للمرة المقبلة.
فخان: التكرار داخل النطاق وحد الطلبات المجاني
إذا كان Worker يغطي keyboardtester.click/* ثم طلب الاسم العام نفسه بلا حذر فقد يعود الطلب إلى Worker. استخدمنا resolveOverride الموثق مع اسم DNS داخلي في النطاق نفسه، مع بقاء URL وترويسة Host على الاسم الأساسي. لا تنشر عنوان الأصل أو تنشئ مسار تجاوز بلا ضوابط.
تسمح الخطة المجانية حاليًا بـ100,000 طلب Worker يوميًا و20,000 ملف ثابت لكل إصدار و25 MiB لكل ملف. حزمة 2,749 ملفًا ملائمة. وضبطنا المسارين على fail-open: عند نفاد الحصة يتجاوز Cloudflare العامل إلى HostArmada بدل عرض Error 1027؛ وهذا مناسب لأن العامل للاستمرارية لا لفرض الأمن.
SEO والإعلانات والتحليلات أثناء النسخة
تخدم النسخة العناوين الأصلية مع canonical وschema والروابط الداخلية. الصفحة الموجودة فعلًا تعيد 200، والإجراء غير المتاح يعيد 503. لا حاجة لنطاق نسخة عامة أو عناوين مكررة.
المعاينة الخاصة محمية بكلمة مرور ومحظورة في robots وتحمل noindex ولا إعلانات أو تحليلات. HTML الاحتياطي في الإنتاج فقط يتلقى GA4 وAdSense وClarity في الرئيسية بتأخير أو بعد تفاعل. لا نعدل استجابات الأصل السليمة. يمكن قياس الزيارة وقد يظهر الإعلان، لكن لا يوجد ضمان للملء أو الإيراد.
We did not submit fallback URLs to search engines because there are no new public URLs. The continuity layer sits behind the same addresses Google already knows.
يطابق الحقن الإنتاجي أداء الموقع: GA4 بعد تفاعل أو ثانيتين من load، وAdSense بعد تفاعل أو 15 ثانية، وClarity في الرئيسية بعد تفاعل أو 12 ثانية. يضيف HTMLRewriter المتدفق الكود إلى HTML الاحتياطي GET فقط، ولا يعدل HEAD أو CSS أو JS أو الصور.
ما الذي لا يستطيع هذا النمط فعله؟
أثناء تعطل الأصل لا تعمل النماذج ولا الذكاء الاصطناعي على الخادم ولا البريد ولا كتابات قاعدة البيانات ولا الجلسات ولا الحفظ. قد تعمل أداة متصفح فقط إذا كانت كل ملفاتها ضمن النسخة.
وقد تصبح النسخة قديمة؛ حدّثها بعد تغييرات المحتوى والقالب والأصول، واختبر العودة لا الفشل فقط. المنتج الذي يعتمد على المعاملات والكتابة يحتاج تطبيقًا وقاعدة بيانات مكررين، لا نسخة ثابتة.
أما موقع محتوى على استضافة مشتركة مع أدوات عميلة كثيرة فهذا حل ملائم: لا انقسام بيانات، ولا تحويل يدوي، ولا نطاق مكرر، مع وضع تدهور واضح. إنه يقلص الانقطاع المرئي ولا يلغي كل اعتماد.
المصادر والأدلة المباشرة
قياسات التنفيذ مأخوذة من ملفات الجرد وفحوص النشر والتوجيه الحية في 17–18 يوليو 2026. سلوك المنتج وحدوده موثقان في المصادر الأولية التالية.
- Cloudflare Workers: Static Assets
- Cloudflare Workers: Platform Limits
- Cloudflare Workers Request API
- Cloudflare Workers Routes API
- RFC 9110: HTTP Semantics
- HostArmada support correspondence, July 16–17, 2026
الأسئلة الشائعة
- هل تصبح الاستضافة المشتركة بلا توقف حقًا؟
لا. تبقى نسخة قراءة معدّة مسبقًا متاحة، لكن النماذج والكتابة والبريد والذكاء الاصطناعي والجلسات ما زالت تحتاج الأصل.
- هل أغير DNS عندما يتوقف الخادم؟
لا في هذا النمط الدائم. يفحص Worker الأصل لكل طلب ويعود إليه تلقائيًا عند التعافي.
- هل يرى Google صفحة صيانة لكل عنوان؟
لا. الصفحات الموجودة في النسخة تبقى 200 بعناوينها وcanonical وschema، أما الإجراء غير المتاح فيعيد 503 مؤقتًا.
- لماذا لا ننقل الحساب كاملًا مؤقتًا؟
النقل والإرجاع السريعان قد يضيفان مشاكل DNS ومزامنة قاعدة البيانات والبريد والملفات. تجنبنا تطبيقًا ثانيًا قابلًا للكتابة.
- لماذا نستخدم resolveOverride؟
لمنع Worker على الاسم العام من طلب نفسه. يغيّر حل DNS إلى اسم آخر في النطاق نفسه مع إبقاء URL وHost الأساسيين.
- ماذا يحدث عند بلوغ الحد المجاني؟
المساران fail-open، فيتجاوز Cloudflare العامل إلى الأصل. يفقد الموقع ميزة النسخة أثناء تعطل الأصل لكنه لا يعرض خطأ حصة Worker.
- متى نحدّث النسخة؟
بعد تغييرات كبيرة في المحتوى أو القالب أو البرامج أو الأصول، وقبل صيانة مخطط لها، مع اختبار الفشل والعودة.
الدرس ليس «ضع كل شيء خلف Worker»، بل اختر أصغر طبقة استمرارية تناسب العطل، اختبرها سرًا، اذكر حدودها بصدق، واجعل العودة تلقائية.