العربية

كيف تضبط إعدادات Node.js على الاستضافة المشتركة لتجنب توقف التطبيق؟

تعرف على الآلية التقنية لتشغيل تطبيقات Node.js عبر Plesk باستخدام Phusion Passenger، وكيفية معالجة أخطاء 503 وإدارة ملفات البيئة في بيئة الاستضافة المشتركة.

5 دقائق قراءة
كيف تضبط إعدادات Node.js على الاستضافة المشتركة لتجنب توقف التطبيق؟

تعتمد استضافة تطبيقات Node.js في بيئة الاستضافة المشتركة على آلية تقنية تختلف جذرياً عن التشغيل المباشر عبر سطر الأوامر في الخوادم الخاصة. نحن في Hostna نشغّل خوادمنا في ألمانيا باستخدام لوحة تحكم Plesk، والتي تعتمد على محرك Phusion Passenger ليكون الوسيط بين خادم الويب Nginx أو Apache وبين تطبيق JavaScript الخاص بك. هذه الطريقة تسمح بتشغيل التطبيق دون الحاجة لصلاحيات root، ولكنها تفرض قيوداً معينة على كيفية إدارة العمليات واستهلاك الذاكرة.

الإجابة المباشرة على كيفية الاستضافة تكمن في رفع ملفات المشروع، ثم تحديد ملف التشغيل الرئيسي (غالباً ما يكون app.js أو index.js)، وتثبيت الاعتمادات عبر واجهة لوحة التحكم. ومع ذلك، يواجه المطورون في الخليج العربي تحديات تتعلق باستقرار التطبيق عند زيادة الطلبات، وهو ما يتطلب ضبطاً دقيقاً لملفات الإعدادات وتجنب الأخطاء الشائعة في مسارات الملفات.

فهم آلية عمل Phusion Passenger في الاستضافة المشتركة

عند رفع تطبيقك إلى الاستضافة المشتركة، لا يقوم النظام بتشغيل node server.js بشكل دائم كما تفعل في جهازك المحلي. بدلاً من ذلك، يقوم Phusion Passenger بمراقبة الطلبات القادمة عبر المنفذ 80 أو 443. عندما يصل طلب إلى الدومين الخاص بك، يقوم Passenger بتشغيل عملية Node.js إذا لم تكن تعمل بالفعل. هذا السلوك يسمى spawning.

من الناحية التقنية، يتم توجيه الطلبات من Nginx (الذي يعمل كـ Reverse Proxy) إلى مقبس Unix Socket يتصل بعملية التطبيق. إذا توقف التطبيق عن الاستجابة أو استهلك موارد تتجاوز المسموح بها في الخطة، يقوم النظام بإغلاق العملية تلقائياً. لذلك، من الضروري جداً التأكد من أن تطبيقك لا يعتمد على ذاكرة الحالة (Stateful) لأن العملية قد تُعاد تشغيلها في أي وقت.

خادم بموارد مخصصة لك

إعداد ملف package.json والاعتمادات

أحد أكثر الأسباب شيوعاً لفشل تشغيل تطبيقات Node.js هو فقدان الاعتمادات أو عدم توافق النسخ. في لوحة التحكم، يجب عليك استخدام زر NPM Install الذي يقوم بتنفيذ الأمر في بيئة معزولة. تأكد دائماً من أن ملف package.json يحتوي على قسم scripts صحيح، وتحديداً start، رغم أن Passenger غالباً ما يتجاوزه ليبحث عن الملف المذكور في خانة Application Startup File.

{
  "name": "my-app",
  "version": "1.0.0",
  "main": "app.js",
  "dependencies": {
    "express": "^4.18.2"
  }
}

عند تنفيذ تثبيت الحزم، يتم إنشاء مجلد node_modules. في الاستضافة المشتركة، يُنصح دائماً باستخدام خيار --production لتقليل عدد الملفات المرفوعة وحجم المساحة المستهلكة، حيث أن تجاوز عدد الملفات (Inodes) المسموح به قد يؤدي إلى توقف لوحة التحكم عن إجراء التحديثات.

إدارة ملفات البيئة .env والأمان

في بيئة بيئة نود جي إس، تُخزن مفاتيح الربط وقواعد البيانات عادة في ملف .env. في الاستضافة المشتركة، يجب أن يكون هذا الملف خارج مجلد httpdocs للتأكد من عدم الوصول إليه عبر المتصفح. تتيح لوحة التحكم إضافة Environment Variables يدوياً، وهي طريقة مناسبة للأمان، حيث يتم حقن هذه المتغيرات مباشرة في process.env الخاص بالتطبيق عند التشغيل.

إذا كنت تستخدم مكتبة dotenv، تأكد من تحديد المسار المطلق للملف، لأن المسارات النسبية قد تختلف عندما يقوم Passenger بتشغيل التطبيق من مجلد جذر مختلف. استخدام المسارات المطلقة مثل /var/www/vhosts/example.com/httpdocs/.env يقلل من احتمالية فشل تحميل الإعدادات.

حل مشكلة الخطأ 503 Service Unavailable

يظهر خطأ 503 عندما يفشل Passenger في بدء تشغيل عملية Node.js أو عندما يستغرق التطبيق وقتاً طويلاً في الاستجابة (Timeout). لتشخيص هذا الخطأ، يجب عليك تفعيل خيار عرض الأخطاء في المتصفح مؤقتاً أو فحص سجلات الأخطاء (Logs). يمكنك إضافة الكود التالي في بداية ملف app.js لتوجيه الأخطاء إلى ملف نصي يمكنك قراءته:

const fs = require('fs');
const process = require('process');
process.on('uncaughtException', (err) => {
  fs.writeSync(1, `Caught exception: ${err}
`);
});

غالباً ما يكون السبب هو نقص في الذاكرة المتاحة. في الاستضافة المشتركة، إذا حاول التطبيق استهلاك أكثر من المحدود له، سيقوم نظام OOM killer بإنهاء العملية مباشرة. إذا كان تطبيقك يحتاج إلى معالجة ثقيلة للصور أو تشغيل عمليات معقدة في الخلفية، فإن الانتقال إلى استضافة بوتات برمجية أو خادم افتراضي هو الخيار التقني السليم.

تحديث التطبيق وآلية restart.txt

عندما تقوم بتعديل الكود الخاص بك ورفعه عبر FTP، لن تلاحظ التغييرات مباشرة لأن العملية القديمة لا تزال تعمل في الذاكرة. لإجبار Passenger على إعادة تحميل التطبيق، يجب عليك إما الضغط على زر Restart App في لوحة التحكم، أو إنشاء ملف فارغ يسمى restart.txt داخل مجلد tmp في جذر التطبيق.

mkdir tmp
touch tmp/restart.txt

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

القيود التقنية ومتى يجب الترقية إلى VPS؟

هناك حدود واضحة لما يمكن تحقيقه على الاستضافة المشتركة. على سبيل المثال، تقنيات WebSockets عبر Socket.io قد لا تعمل بكفاءة عالية بسبب قيود مهلة الاتصال (Proxy Timeout) في Nginx. أيضاً، لا يمكنك تشغيل مدير عمليات مثل PM2 بشكل دائم لأن الاستضافة المشتركة تمنع العمليات التي تعمل في الخلفية لفترات طويلة دون وجود طلبات HTTP نشطة.

إذا كان مشروعك يتطلب:

  • اتصالات WebSocket دائمة ومستقرة.
  • تشغيل مهام مجدولة (Cron Jobs) معقدة كل دقيقة.
  • الوصول إلى صلاحيات root لتثبيت حزم نظام معينة (مثل ffmpeg).
  • استخدام منافذ (Ports) مخصصة غير 80 و443.

في هذه الحالات، ننصح بالاطلاع على الخوادم الافتراضية الموجهة للمنطقة التي تمنحك تحكماً كاملاً بالموارد. في Hostna، نوفر خوادم في ألمانيا تتيح لك تثبيت أي نسخة من Node.js وإدارة العمليات باستخدام systemd للمساعدة في إعادة التشغيل التلقائي بعد أي توقف.

يمكنك الاطلاع على توثيق شبكة مطوري موزيلا لفهم أفضل الممارسات في بناء تطبيقات مستقرة برمجياً قبل رفعها إلى الخادم. تذكر دائماً أن جودة الكود تلعب دوراً أساسياً في تقليل استهلاك الموارد؛ فمثلاً، ضبط TTFB (وقت الوصول لأول بايت) يعتمد بشكل كبير على سرعة استعلامات قاعدة البيانات وكفاءة Middleware في تطبيقك.

ماذا تفعل إذا لم يعمل التطبيق؟

إذا اتبعت الخطوات السابقة ولا يزال التطبيق يظهر خطأ Internal Server Error، يرجى التحقق من نسخة Node.js المختارة في لوحة التحكم، حيث أن بعض الحزم الحديثة تتطلب نسخة 18.x أو أحدث. إذا تواصلت مع فريق الدعم التقني، يرجى إرسال سجل الأخطاء الموجود في مجلد logs باللغة الإنجليزية، وتوضيح نسخة Node التي تستخدمها، ونتائج أمر npm install إذا ظهرت فيه أي تحذيرات تتعلق بـ node-gyp أو الاعتمادات الأصلية (Native Dependencies).

كُتبت هذه المقالة بمساعدة الذكاء الاصطناعي ضمن خط البحث الخاص بـ Hostna وراجعها شخص قبل النشر.

أسئلة شائعة3
u0644u0645u0627u0630u0627 u064au0638u0647u0631 u062eu0637u0623 503 u0639u0646u062f u062au0634u063au064au0644 Node.jsu061f

u064au062du062fu062b u062eu0637u0623 503 u0639u0627u062fu0629 u0628u0633u0628u0628 u0641u0634u0644 u0645u062du0631u0643 Passenger u0641u064a u0628u062fu0621 u0627u0644u062au0637u0628u064au0642. u0627u0644u0623u0633u0628u0627u0628 u0627u0644u0634u0639u0627u0626u0639u0629 u062au0634u0645u0644 u062eu0637u0623 u0641u064a u0643u0648u062f u0627u0644u062au0634u063au064au0644 u0627u0644u0631u0626u064au0633u064au060c u0646u0642u0635 u0627u0644u0630u0627u0643u0631u0629 u0627u0644u0639u0634u0648u0627u0626u064au0629 u0627u0644u0645u062eu0635u0635u0629 u0644u0644u062du0633u0627u0628u060c u0623u0648 u0641u0642u062fu0627u0646 u0645u0644u0641u0627u062a u0623u0633u0627u0633u064au0629 u0641u064a u0645u062cu0644u062f node_modules. u064au0646u0635u062d u0628u0627u0644u062au062du0642u0642 u0645u0646 u0633u062cu0644u0627u062a u0627u0644u0623u062eu0637u0627u0621 u0641u064a u0644u0648u062du0629 u0627u0644u062au062du0643u0645 u0644u0645u0639u0631u0641u0629 u0627u0644u0633u0628u0628 u0627u0644u062fu0642u064au0642.

u0647u0644 u064au0645u0643u0646u0646u064a u0627u0633u062au062eu062fu0627u0645 Socket.io u0639u0644u0649 u0627u0644u0627u0633u062au0636u0627u0641u0629 u0627u0644u0645u0634u062au0631u0643u0629u061f

u064au0645u0643u0646 u0627u0633u062au062eu062fu0627u0645u0647 u0628u0634u0643u0644 u0645u062du062fu0648u062fu060c u0648u0644u0643u0646 u0646u0638u0631u0627u064b u0644u0623u0646 u0627u0644u0627u0633u062au0636u0627u0641u0629 u0627u0644u0645u0634u062au0631u0643u0629 u062au0639u0645u0644 u0639u0628u0631 u0648u0643u064au0644 Nginxu060c u0641u0625u0646 u0627u062au0635u0627u0644u0627u062a WebSocket u0642u062f u062au0648u0627u062cu0647 u0627u0646u0642u0637u0627u0639u0627u062a u0645u062au0643u0631u0631u0629 u0628u0633u0628u0628 u0645u0647u0644u0629 u0627u0644u0627u062au0635u0627u0644 u0627u0644u0627u0641u062au0631u0627u0636u064au0629. u0644u0644u062au0637u0628u064au0642u0627u062a u0627u0644u062au064a u062au0639u062au0645u062f u0643u0644u064au0627u064b u0639u0644u0649 u0627u0644u0628u062b u0627u0644u0645u0628u0627u0634u0631u060c u064au0641u0636u0644 u0627u0633u062au062eu062fu0627u0645 u062eu0627u062fu0645 VPS u0644u062au062du0633u064au0646 u0627u0633u062au0642u0631u0627u0631 u0627u0644u0645u0646u0627u0641u0630 u0648u0627u0644u0627u062au0635u0627u0644u0627u062a u0627u0644u062fu0627u0626u0645u0629.

u0643u064au0641 u0623u0642u0648u0645 u0628u062au062du062fu064au062b u0646u0633u062eu0629 Node.js u0641u064a u062du0633u0627u0628u064au061f

u062au0648u0641u0631 u0644u0648u062du0629 u0627u0644u062au062du0643u0645 Plesk u0642u0627u0626u0645u0629 u0645u0646u0633u062fu0644u0629 u062au062du062au0648u064a u0639u0644u0649 u0646u0633u062e Node.js u0627u0644u0645u062fu0639u0648u0645u0629 u0648u0627u0644u0645u062bu0628u062au0629 u0639u0644u0649 u0627u0644u062eu0627u062fu0645. u064au0645u0643u0646u0643 u0627u062eu062au064au0627u0631 u0627u0644u0646u0633u062eu0629 u0627u0644u0645u0646u0627u0633u0628u0629 u0644u0645u0634u0631u0648u0639u0643 u0645u0646 u0625u0639u062fu0627u062fu0627u062a u062au0637u0628u064au0642 Node.jsu060c u0648u0633u064au0642u0648u0645 u0627u0644u0646u0638u0627u0645 u062au0644u0642u0627u0626u064au0627u064b u0628u062au062du062fu064au062b u0627u0644u0645u0633u0627u0631u0627u062a u0644u0644u0639u0645u0644 u0628u0627u0644u0646u0633u062eu0629 u0627u0644u062cu062fu064au062fu0629 u062fu0648u0646 u0627u0644u062au0623u062bu064au0631 u0639u0644u0649 u0627u0644u0645u0648u0627u0642u0639 u0627u0644u0623u062eu0631u0649 u0641u064a u0627u0644u062du0633u0627u0628.