أحمد حايس
الرئيسيةمن أناالدوراتالمدونةالعروض
أحمد حايس

دورات عربية متخصصة في التقنية والبرمجة والذكاء الاصطناعي.

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

تعلم أسرعوصول مباشر للدورات والمسارات من الموبايل.
تنقل أوضحالروابط الأساسية والدعم في مكان واحد بدون تشتيت.

المنصة

  • الرئيسية
  • من أنا
  • الدورات
  • العروض
  • المدونة

الدعم

  • الأسئلة الشائعة
  • تواصل معنا
  • سياسة الخصوصية
  • شروط استخدام التطبيق
  • سياسة الاسترجاع
محتاج مسار سريع؟
ابدأ من الدوراتتواصل معناالأسئلة الشائعة

© 2026 أحمد حايس. جميع الحقوق محفوظة.

الرئيسيةالدوراتالعروضالمدونةالدخول
DevOps بالعربي

systemd: شغّل Node.js على VM بدون crash صامت

📅 ٢٥ أبريل ٢٠٢٦⏱ 4 دقائق قراءة
systemd: شغّل Node.js على VM بدون crash صامت

systemd لتشغيل Node.js على VM بدون crash صامت

هتخرج من المقال ده بإعداد عملي يخلي خدمة Node.js ترجع بعد الفشل في حوالي 8 ثواني، وتكتب logs واضحة، وتتقفل بصلاحيات أقل بدل ما تفضل شغالة بـ nohup من غير رقابة.

مستوى القارئ: متوسط

المشكلة باختصار

الطريقة الشائعة هي تشغيل التطبيق بـ node server.js داخل screen أو nohup. الطريقة دي بتفشل في 3 نقاط: لو العملية ماتت مش دايمًا هترجع، الـ logs بتتشتت في ملف عشوائي، والتطبيق غالبًا بيشتغل بصلاحيات أوسع من احتياجه.

الافتراض هنا إن عندك VM واحدة أو اتنين، تطبيق Node.js خلف Nginx، وحجم ترافيك في حدود 5K إلى 50K زائر يوميًا. لو عندك Kubernetes أو منصة PaaS، الفكرة نفسها مفيدة، لكن التنفيذ هيختلف.

مخطط يوضح تشغيل خدمة Node.js خلف Nginx مع systemd وjournalctl وطبقة sandboxing

الفكرة بمثال واضح

ركز في المثال ده: عندك API فواتير على /srv/invoice-api. الساعة 2 بالليل حصل memory leak والعملية خرجت بكود خطأ. بدون مدير خدمة، الموقع يفضل واقع لحد ما حد يفتح السيرفر. مع systemd، العملية تفشل، تتحول لحالة failed، ثم ترجع بعد RestartSec=5. المكسب إن الانقطاع يبقى ثواني بدل دقائق. الـ trade-off إنك لازم تكتب unit file مضبوط وتراقب سبب الفشل، بدل ما تخبي المشكلة وراء restart لا نهائي.

في قياس داخلي بسيط، خدمة كانت تحتاج تدخل يدوي بعد crash خلال 3 دقائق تقريبًا. بعد Restart=on-failure رجعت في 8 ثواني. وبعد hardening نزل تقدير systemd-analyze security من 8.8 إلى 4.1. الأرقام هنا تقديرية لتوضيح طريقة القياس، مش وعد ثابت لكل تطبيق.

رسم أعمدة يقارن زمن رجوع خدمة Node.js بعد crash ومستوى exposure قبل وبعد إعداد systemd hardening

ملف service جاهز

أنشئ مستخدم تشغيل محدود بدل root. بعد كده اكتب ملف الخدمة. هذا مثال عملي لتطبيق Express يستمع على port داخلي مثل 3000 وNginx يمرر له الترافيك.

Bash
sudo useradd --system --home /srv/invoice-api --shell /usr/sbin/nologin invoice-api
sudo mkdir -p /srv/invoice-api
sudo chown -R invoice-api:invoice-api /srv/invoice-api
sudo nano /etc/systemd/system/invoice-api.service
[Unit]
Description=Invoice API Node.js service
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=invoice-api
Group=invoice-api
WorkingDirectory=/srv/invoice-api
Environment=NODE_ENV=production
Environment=PORT=3000
ExecStart=/usr/bin/node /srv/invoice-api/server.js
Restart=on-failure
RestartSec=5
TimeoutStopSec=20
KillSignal=SIGTERM

NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/srv/invoice-api/logs

[Install]
WantedBy=multi-user.target

Restart=on-failure أفضل من always في أغلب خدمات الويب، لأنه لا يعيد تشغيل الخدمة لو أنت عملت systemctl stop بإرادتك. ProtectSystem=strict يجعل النظام read-only للخدمة، ثم تسمح فقط بمسار كتابة واضح عبر ReadWritePaths. بتكسب تقليل الضرر لو التطبيق اتخترق، وتخسر مرونة الكتابة العشوائية في أي مجلد.

التشغيل والتحقق

قبل التشغيل، خلّي systemd يراجع الملف. بعد ذلك فعّل الخدمة واقرأ حالتها والـ logs من مكان واحد.

Bash
sudo systemd-analyze verify /etc/systemd/system/invoice-api.service
sudo systemctl daemon-reload
sudo systemctl enable --now invoice-api
sudo systemctl status invoice-api --no-pager
journalctl -u invoice-api -f

لو عايز تختبر الرجوع بعد الفشل، اقتل العملية الرئيسية ثم راقب وقت الرجوع. لا تعمل هذا على production وقت الذروة.

Bash
MAIN_PID=$(systemctl show -p MainPID --value invoice-api)
sudo kill -9 "$MAIN_PID"
sleep 8
systemctl is-active invoice-api
journalctl -u invoice-api -n 40 --no-pager

لو النتيجة active بعد 8 إلى 12 ثانية، الـ restart policy شغالة. لو الخدمة ترجع وتقع كل مرة، لا تزود RestartSec وخلاص. افتح آخر logs وابحث عن السبب الحقيقي: متغير بيئة ناقص، اتصال قاعدة بيانات، أو migration اتنفذت غلط.

hardening وقياسه

أفضل طريقة هنا إنك تقيس قبل وبعد. الأمر systemd-analyze security لا يثبت إن تطبيقك آمن بالكامل، لكنه يعطيك مؤشر سريع عن إعدادات sandboxing التي يطبقها systemd نفسه. قيمة أعلى تعني exposure أكبر، وقيمة أقل تعني قيود أقوى.

Bash
systemd-analyze security invoice-api.service

NoNewPrivileges=true يمنع العملية وأولادها من اكتساب صلاحيات جديدة عبر exec. PrivateTmp=true يعزل /tmp عن باقي النظام. ProtectHome=true يمنع الوصول لمجلدات المستخدمين. الـ trade-off هنا واضح: كل قيد ممكن يكسر مكتبة كانت تكتب في مكان غير متوقع. لذلك طبّق القيود واحدة واحدة، ثم شغّل health check بعد كل تغيير.

متى لا تستخدم هذه الطريقة

لا تستخدم هذا الإعداد وحده لو عندك أكثر من instance تحتاج rolling deploy، أو auto-scaling، أو service discovery. في الحالة دي Kubernetes أو Nomad أو PaaS قد يكونوا أنسب. لا تعتمد عليه أيضًا كبديل للمراقبة. systemd يرجّع الخدمة، لكنه لا يخبرك وحده إن معدل أخطاء API وصل 12% أو إن latency زاد من 90ms إلى 700ms.

ولو تطبيقك يستخدم native addons أو runtime يكتب ملفات مؤقتة كثيرة، ابدأ بقيود أقل. مثلًا جرّب NoNewPrivileges وPrivateTmp أولًا، ثم أضف ProtectSystem=strict بعد ما تحدد مسارات الكتابة المطلوبة.

مصادر اعتمدت عليها

  • systemd.service: Restart وWatchdogSec وNotifyAccess
  • systemd.exec: NoNewPrivileges وProtectSystem وPrivateTmp
  • systemd-analyze security وقياس exposure level
  • journalctl لقراءة logs من systemd journal

الخطوة التالية

الخطوة التالية: خذ خدمة واحدة غير حرجة عندك، حوّلها إلى systemd service بنفس القالب، ثم سجل رقمين فقط: زمن الرجوع بعد crash، ونتيجة systemd-analyze security قبل وبعد hardening.

هل استفدت من المقال؟

اطّلع على المزيد من المقالات والدروس المجانية من نفس المسار المعرفي.

تصفّح المدونة