كيفية إعداد تطبيق Node.js للإنتاج على Rocky Linux 9

مقدمة

Node.js هو بيئة تشغيل JavaScript مفتوحة المصدر لبناء تطبيقات الخادم والشبكات. تعمل المنصة على نظام التشغيل لينكس وماكوس وفريبسي وويندوز. على الرغم من أنه يمكنك تشغيل تطبيقات Node.js في سطر الأوامر، سيتم التركيز في هذا البرنامج التعليمي على تشغيلها كخدمة. وهذا يعني أنها ستقوم بإعادة التشغيل عند إعادة التشغيل أو الفشل وأنها آمنة للاستخدام في بيئة الإنتاج.

في هذا البرنامج التعليمي، ستقوم بإعداد بيئة Node.js جاهزة للإنتاج على خادم Rocky Linux 9 واحد. سيتم تشغيل هذا الخادم تطبيق Node.js الذي يتم إدارته بواسطة PM2، وسيوفر للمستخدمين الوصول الآمن إلى التطبيق من خلال بروكسي عكسي Nginx. سيقدم خادم Nginx HTTPS باستخدام شهادة مجانية من Let’s Encrypt.

المتطلبات المسبقة

يفترض هذا الدليل أن لديك ما يلي:

بعد الانتهاء من المتطلبات الأساسية، ستكون لديك خادم يخدم صفحة الويب الافتراضية لنطاقك على https://example.com/.

الخطوة 1 — إنشاء تطبيق Node.js

لنكتب تطبيق Hello World الذي يعيد “Hello World” لأي طلب HTTP. سيساعدك هذا التطبيق العيني في البدء والتشغيل مع Node.js. يمكنك استبداله بتطبيقك الخاص — فقط تأكد من تعديل التطبيق الخاص بك للاستماع إلى عناوين IP ومنافذ مناسبة.

محرر النص الافتراضي الذي يأتي مع Rocky Linux 9 هو vi. vi هو محرر نصوص قوي للغاية، ولكن قد يكون مبهمًا إلى حد ما للمستخدمين الذين يفتقرون إلى الخبرة في استخدامه. قد ترغب في تثبيت محرر نصوص أكثر ودية للمستخدم مثل nano لتسهيل تحرير ملفات التكوين على خادم Rocky Linux 9 الخاص بك:

  1. sudo dnf install nano

الآن، باستخدام nano أو محرر النصوص المفضل لديك، قم بإنشاء تطبيق عينة يسمى hello.js:

  1. nano hello.js

أدخل الكود التالي في الملف:

~/hello.js
const http = require('http');

const hostname = 'localhost';
const port = 3000;

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello World!\n');
});

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});

احفظ الملف واخرج من المحرر. إذا كنت تستخدم nano، اضغط Ctrl+X، ثم عندما يُطلب منك، اضغط Y ثم Enter.

يستمع هذا التطبيق Node.js على العنوان المحدد (localhost) والمنفذ (3000)، ويُعيد “مرحبًا بالعالم!” مع رمز نجاح HTTP 200. نظرًا لأننا نستمع على localhost، فلن يتمكن العملاء البعيدين من الاتصال بتطبيقنا.

لتجربة تطبيقك، اكتب:

  1. node hello.js

ستتلقى الناتج التالي:

Output
Server running at http://localhost:3000/

ملاحظة: تشغيل تطبيق Node.js بهذه الطريقة سيمنع تنفيذ أوامر إضافية حتى يتم إيقاف التطبيق بالضغط على CTRL+C.

لتجربة التطبيق، افتح جلسة طرفية أخرى على خادمك، واتصل بـ localhost باستخدام curl:

  1. curl http://localhost:3000

إذا حصلت على الناتج التالي، فإن التطبيق يعمل بشكل صحيح ويستمع على العنوان والمنفذ الصحيحين:

Output
Hello World!

إذا لم تحصل على الناتج المتوقع، تأكد من أن تطبيق Node.js الخاص بك يعمل ومضبوط للاستماع على العنوان والمنفذ الصحيحين.

بمجرد التأكد من أنه يعمل، قم بإيقاف التطبيق (إذا لم تكن قد فعلت بالفعل) بالضغط على CTRL+C.

الخطوة 2 — تثبيت PM2

الآن دعنا نقوم بتثبيت PM2، وهو مدير لعمليات Node.js. يجعل PM2 من الممكن تشغيل التطبيقات في الخلفية كخدمة.

استخدم npm لتثبيت أحدث إصدار من PM2 على الخادم الخاص بك:

  1. sudo npm install pm2@latest -g

الخيار -g يخبر npm بتثبيت الوحدة على نطاق عالمي، بحيث يكون متاحًا على مستوى النظام.

لنستخدم أولاً أمر pm2 start لتشغيل تطبيقك، hello.js، في الخلفية:

  1. pm2 start hello.js

يقوم هذا أيضًا بإضافة تطبيقك إلى قائمة عمليات PM2، والتي يتم إخراجها في كل مرة تقوم فيها بتشغيل تطبيق:

Output
... [PM2] Spawning PM2 daemon with pm2_home=/home/sammy/.pm2 [PM2] PM2 Successfully daemonized [PM2] Starting /home/sammy/hello.js in fork_mode (1 instance) [PM2] Done. ┌────┬────────────────────┬──────────┬──────┬───────────┬──────────┬──────────┐ │ id │ name │ mode │ ↺ │ status │ cpu │ memory │ ├────┼────────────────────┼──────────┼──────┼───────────┼──────────┼──────────┤ │ 0 │ hello │ fork │ 0 │ online │ 0% │ 25.2mb │ └────┴────────────────────┴──────────┴──────┴───────────┴──────────┴──────────┘

كما هو موضح أعلاه، يعين PM2 تلقائيًا اسم التطبيق (بناءً على اسم الملف، بدون امتداد .js) و معرف PM2. كما يحتفظ PM2 أيضًا بمعلومات أخرى، مثل PID للعملية، وحالتها الحالية، واستخدام الذاكرة.

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

  1. pm2 startup systemd
Output
… [PM2] To setup the Startup Script, copy/paste the following command: sudo env PATH=$PATH:/usr/bin /usr/local/lib/node_modules/pm2/bin/pm2 startup systemd -u sammy --hp /home/sammy

انسخ وقم بتشغيل الأمر المقدم (هذا لتجنب مشكلات الأذونات في تشغيل أدوات Node.js ك sudo):

  1. sudo env PATH=$PATH:/usr/bin /usr/local/lib/node_modules/pm2/bin/pm2 startup systemd -u sammy --hp /home/sammy
Output
… [ 'systemctl enable pm2-sammy' ] [PM2] Writing init configuration in /etc/systemd/system/pm2-sammy.service [PM2] Making script booting at startup... [PM2] [-] Executing: systemctl enable pm2-sammy... Created symlink /etc/systemd/system/multi-user.target.wants/pm2-sammy.service → /etc/systemd/system/pm2-sammy.service. [PM2] [v] Command successfully executed. +---------------------------------------+ [PM2] Freeze a process list on reboot via: $ pm2 save [PM2] Remove init script via: $ pm2 unstartup systemd

الآن، ستحتاج إلى إجراء تحرير في خدمة النظام التي تم إنشاؤها لتجعلها متوافقة مع نظام Rocky Linux’s SELinux الأمان. باستخدام nano أو محرر النصوص المفضل لديك، افتح /etc/systemd/system/pm2-sammy.service:

  1. sudo nano /etc/systemd/system/pm2-sammy.service

في قسم [Service] في ملف التكوين، استبدل محتويات إعداد PIDFile بـ /run/pm2.pid كما هو موضح أدناه، وأضف السطر الآخر المظلل Environment:

/etc/systemd/system/pm2-sammy.service
[Unit]
Description=PM2 process manager
Documentation=https://pm2.keymetrics.io/
After=network.target

[Service]
Type=forking
User=sammy
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
Environment=PATH=/home/sammy/.local/bin:/home/sammy/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/usr/bin:/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
Environment=PM2_HOME=/home/sammy/.pm2
PIDFile=/run/pm2.pid
Restart=on-failure
Environment=PM2_PID_FILE_PATH=/run/pm2.pid

ExecStart=/usr/local/lib/node_modules/pm2/bin/pm2 resurrect
ExecReload=/usr/local/lib/node_modules/pm2/bin/pm2 reload all
ExecStop=/usr/local/lib/node_modules/pm2/bin/pm2 kill

[Install]

احفظ وأغلق الملف. لقد قمت الآن بإنشاء وحدة systemd تعمل بتشغيل pm2 للمستخدم الخاص بك عند التمهيد. تقوم هذه النسخة من pm2 بتشغيل hello.js.

ابدأ الخدمة باستخدام systemctl:

  1. sudo systemctl start pm2-sammy

تحقق من حالة وحدة systemd:

  1. systemctl status pm2-sammy

للحصول على نظرة عامة مفصلة حول systemd، يرجى مراجعة Systemd Essentials: العمل مع الخدمات والوحدات والسجل.

بالإضافة إلى ما تمت Covered، يوفر PM2 العديد من الأوامر الفرعية التي تتيح لك إدارة أو البحث عن معلومات حول تطبيقاتك.

قم بإيقاف تشغيل تطبيق بهذا الأمر (حدد اسم التطبيق PM2 App name أو id):

  1. pm2 stop app_name_or_id

أعد تشغيل التطبيق:

  1. pm2 restart app_name_or_id

قائمة التطبيقات التي يديرها PM2 حاليًا:

  1. pm2 list

احصل على معلومات حول تطبيق معين باستخدام App name الخاص به:

  1. pm2 info app_name

يمكن استدعاء مراقب العمليات PM2 باستخدام الأمر الفرعي monit. يعرض هذا الأمر حالة التطبيق، واستخدام وحدة المعالجة المركزية، واستخدام الذاكرة:

  1. pm2 monit

يرجى ملاحظة أن تشغيل pm2 بدون أي وسيطات سيعرض أيضًا صفحة مساعدة تحتوي على استخدامات مثالية.

الآن بعد أن تم تشغيل تطبيق Node.js الخاص بك وإدارته بواسطة PM2، دعنا نقوم بإعداد الوكيل العكسي.

الخطوة 3 — إعداد Nginx كخادم وكيل عكسي

يتم تشغيل تطبيقك والاستماع على localhost، ولكنك بحاجة إلى إعداد طريقة للمستخدمين الخاص بك للوصول إليه. سنقوم بإعداد خادم الويب Nginx كوكيل عكسي لهذا الغرض.

في البرنامج التعليمي الأساسي، قمت بإعداد تكوين Nginx الخاص بك في ملف /etc/nginx/conf.d/your_domain.conf. افتح هذا الملف للتحرير:

  1. sudo nano /etc/nginx/conf.d/your_domain.conf

Dentro del bloque server, deberías tener un bloque location / existente. Reemplaza el contenido de ese bloque con la siguiente configuración. Si tu aplicación está configurada para escuchar en un puerto diferente, actualiza la parte resaltada con el número de puerto correcto:

/etc/nginx/conf.d/your_domain.conf
server {
...
    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
...
}

يقوم هذا بتكوين الخادم للاستجابة للطلبات في الجذر الخاص به. بافتراض أن خادمنا متاح على your_domain، فإن الوصول إلى https://your_domain/ عبر متصفح الويب سيُرسل الطلب إلى hello.js، الذي يستمع على المنفذ 3000 في localhost.

يمكنك إضافة كتل location إضافية إلى نفس كتلة الخادم لتوفير الوصول إلى تطبيقات أخرى على نفس الخادم. على سبيل المثال، إذا كنت تقوم أيضًا بتشغيل تطبيق آخر بـ Node.js على المنفذ 3001، فيمكنك إضافة كتلة الموقع هذه للسماح بالوصول إليها عبر https://your_domain/app2:

/etc/nginx/conf.d/your_domain.conf — Optional
server {
...
    location /app2 {
        proxy_pass http://localhost:3001;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
...
}

بمجرد الانتهاء من إضافة كتل الموقع لتطبيقاتك، قم بحفظ الملف والخروج من محررك.

تأكد من عدم إدخال أخطاء بناء الجملة من خلال كتابة:

  1. sudo nginx -t

أعد تشغيل Nginx:

  1. sudo systemctl restart nginx

بافتراض أن تطبيقك Node.js قيد التشغيل، وأن تكوينات تطبيقك وNginx صحيحة، يجب الآن أن تكون قادرًا على الوصول إلى تطبيقك عبر خادم Nginx العكسي. جرب ذلك عن طريق الوصول إلى عنوان URL الخاص بخادمك (عنوان IP العام أو اسم النطاق).

الاستنتاج

تهانينا! لديك الآن تطبيق Node.js الخاص بك يعمل خلف خادم عكسي Nginx على خادم Rocky Linux 9. هذا الإعداد للخادم العكسي مرن بما يكفي لتوفير وصول المستخدمين إلى تطبيقات أخرى أو محتوى ويب ثابت ترغب في مشاركته.

التالي، قد ترغب في البحث عن كيفية بناء تطبيق Node.js باستخدام Docker.

Source:
https://www.digitalocean.com/community/tutorials/how-to-set-up-a-node-js-application-for-production-on-rocky-linux-9