القرص الممتلئ لا يُنبّه أحدًا
يتكرر السيناريو نفسه. يعمل VPS لعميل منذ أشهر، وتكتب قاعدة البيانات سجلاتها، وتتراكم النسخ الاحتياطية، وفي صباح ما تتوقف الخدمة. لم يصدر أي تنبيه، ويعلم العميل قبلكم. في PostgreSQL، تُظهر حالة أُبلغ عنها في القائمة البريدية الرسمية للمشروع السطر الدقيق: PANIC: could not write to file "pg_wal/xlogtemp.11399": No space left on device. والـ PANIC ليس مجرد تحذير: فالخادم لم يعد قادرًا على تسجيل عمليات الكتابة، فيتوقف، ولا يعاود التشغيل سليمًا إلا بعد تحرير مساحة.
الصعوبة ليست في اكتشاف القرص الممتلئ بل في اكتشافه قبل ذلك. بين امتلاء بنسبة 80 % والانقطاع تبقى غالبًا ساعات أو أيام، وهذه بالضبط النافذة التي ينبغي لتنبيه مضبوط جيدًا أن يلتقطها. لا يعيد هذا الدليل تثبيت منظومة مراقبة: بل يضع الحد الأدنى المفيد على كل VPS، بلغة shell، دون خادم ثانٍ يلزمكم صيانته.
التنبيهات الستة الدنيا والنبضة، على كل VPS
- القرص — عتبتان: 80 % تحذيرًا و90 % حرجًا، على كل نقطة ربط مهمة.
- الـ inodes — قد يرفض القرص الكتابة رغم بقاء بايتات حرة إذا استُنفدت الـ inodes.
- الذاكرة وOOM — اكتشاف أن النواة قتلت عملية، لا مجرد ارتفاع استهلاك الذاكرة.
- خدمات systemd — التنبيه حين تدخل قاعدة البيانات أو خادم الويب أو الوكيل حالة failed.
- الشهادات — التنبيه قبل 21 يومًا من الانتهاء، حين يفشل التجديد التلقائي بصمت.
- النسخ الاحتياطية — التنبيه على غياب نجاح حديث، لا على خطأ صريح فقط.
- الفحص نفسه — نبضة خارجية تنبّهكم حين تتوقف التنبيهات عن الإرسال.
المتطلبات بالأرقام: لا شيء تقريبًا
كل ما يلي يتسع في بضع عشرات من أسطر shell وفق POSIX. تحتاجون إلى VPS بنظام Linux مزوّد بـ curl وcron أو مؤقّتات systemd، وصلاحية root للكتابة في /usr/local/bin و/etc، ونحو 1 ميغابايت من القرص. وتكلفة الذاكرة هي تكلفة سكربت يدوم ثانية كل خمس دقائق: لا تُذكر، حتى على أصغر VPS.
ويكمل المنظومةَ عنصران خارجيان: قناة استقبال (بوت Telegram أو أي webhook يمكن بلوغه عبر HTTP) وخدمة نبضة تستقبل ping منتظمًا وتنبّهكم حين يتوقف. وبخصوص هذه الأخيرة، تقدّم Healthchecks.io خطة مجانية محدودة بـ 20 مهمة و100 سجل لكل مهمة، وهو يكفي أسطولًا صغيرًا؛ تحققوا من هذه الحدود في المصدر قبل الاعتماد عليها. وإن لم ترغبوا في أي خدمة طرف ثالث، فإن وضع push في Uptime Kuma يؤدي الدور نفسه على جهاز تملكونه.
القرص والـ inodes: العتبات وما يزيحها
الأمر المفيد هو df -h --output=pcent,target: لا يعرض سوى النسبة ونقطة الربط، وهذا سهل القراءة والمعالجة. وبالنسبة للـ inodes تصبح الفكرة نفسها df --output=ipcent,target. قد يستهلك مجلد جلسات أو ملفات تخزين مؤقت صغيرة كل الـ inodes في نظام ملفات ext4 بينما يعرض df -h امتلاءً بنسبة 40 % فقط: وتفشل الكتابة مع ذلك بالرسالة نفسها No space left on device.
وثمة دقة ثانية. في ext4 يُحجز 5 % من الكتل افتراضيًا للعمليات المميّزة، بحسب صفحة دليل tune2fs؛ وبذلك تواصل خدمات النظام الكتابة حين يملأ مستخدم عادي القرص. والنتيجة: الخدمة التي تعمل بحساب غير مميّز، مثل قاعدة البيانات، يرى df يعرض 100 % بينما القرص مستخدم بنحو 95 %. ومن هنا العتبتان المختارتان: 80 % لإتاحة وقت للتصرف، و90 % للتصرف فورًا. انتظار 100 % يعني التنبيه بعد الانقطاع.
إعداد المنظومة في ساعة واحدة
إنشاء قناة التنبيه
أنشئوا بوت Telegram عبر BotFather، ودوّنوا الرمز المميز ومعرّف المحادثة التي ستستقبل الرسائل. تتبع كل طلبات واجهة Bot الصيغة
https://api.telegram.org/bot<token>/METHOD_NAME، وطريقة الإرسال هيsendMessage. وإن فضّلتم webhook (Slack أو Mattermost أو ntfy) فلا يتغير سوى السطر الأخير من سكربت الإرسال.كتابة ملف البيئة
sudo mkdir -p /var/lib/alerte-vpssudo install -m 600 /dev/null /etc/alerte-vps.env
ثم أضيفوا إليه أربعة أسطر:TG_TOKEN=...وTG_CHAT=...وHC_URL=https://hc-ping.com/<uuid>(فحص كل خمس دقائق) وHC_URL_JOUR=https://hc-ping.com/<other-uuid>(فحص يومي). الوضع 600 يُبقي الرمز مقروءًا لـ root وحده.كتابة سكربت الإرسال مع منع التكرار
احفظوا هذه الأسطر في
/usr/local/bin/alerte-envoiثم اجعلوا الملف قابلًا للتنفيذ بالأمرsudo chmod 755. يمنع ملف القفل لكل رسالة أن تُزعجوا كل خمس دقائق بالتنبيه نفسه: فالرسالة المطابقة لا تُعاد إلا بعد ساعة.#!/bin/sh. /etc/alerte-vps.envf=/var/lib/alerte-vps/$(echo "$1" | md5sum | cut -c1-12)[ -n "$(find "$f" -mmin -60 2>/dev/null)" ] && exit 0touch "$f"curl -fsS -m 10 --retry 3 "https://api.telegram.org/bot${TG_TOKEN}/sendMessage" -d chat_id="${TG_CHAT}" --data-urlencode text="$(hostname) $1"فحص القرص والـ inodes
في
/usr/local/bin/alerte-rapide(مع shebang#!/bin/sh) أضيفوا الحلقتين التاليتين. يستبعد المرشّحgrep -vأنظمة الملفات التي لا تعرض inodes وتطبع شرطة.df --output=pcent,target -x tmpfs -x devtmpfs | tail -n +2 | while read p m; do n=${p%\%}; if [ "$n" -ge 90 ]; then alerte-envoi "CRIT disk $m"; elif [ "$n" -ge 80 ]; then alerte-envoi "WARN disk $m"; fi; donedf --output=ipcent,target -x tmpfs -x devtmpfs | tail -n +2 | grep -v '^ *-' | while read p m; do [ "${p%\%}" -ge 90 ] && alerte-envoi "INODES $m"; doneاكتشاف العمليات التي قتلها OOM killer
لا يفعل العدّاد
oom_killفي/proc/vmstatسوى الازدياد منذ الإقلاع. تُقارن قيمته بالقيمة السابقة المحفوظة في ملف؛ وبعد إعادة التشغيل يبدأ العدّاد من الصفر فتخطئ المقارنة مرة واحدة ثم تستقيم.n=$(awk '/^oom_kill/ {print $2}' /proc/vmstat)old=$(cat /var/lib/alerte-vps/oom 2>/dev/null || echo 0)[ "$n" -gt "$old" ] && alerte-envoi "OOM kill"echo "$n" > /var/lib/alerte-vps/oomإضافة النبضة والجدولة
أنهوا
alerte-rapideبالـ ping. لا يُبلغ هذا السطر إلا إذا بلغ السكربت نهايته؛ فإن توقف cron أو صار القرص للقراءة فقط أو تعطل السكربت، توقف الـ ping وتنبّهكم الخدمة الخارجية. ثم أضيفوا سطري cron في/etc/cron.d/alerte-vps.. /etc/alerte-vps.env; curl -fsS -m 10 --retry 5 -o /dev/null "$HC_URL"PATH=/usr/local/bin:/usr/bin:/bin*/5 * * * * root /usr/local/bin/alerte-rapide30 7 * * * root /usr/local/bin/alerte-quotidienفحص الشهادات والنسخ الاحتياطية مرة يوميًا
في
/usr/local/bin/alerte-quotidienأضيفوا هذه الأسطر. يفشل الخيار-checkendفيopenssl x509إذا انتهت صلاحية الشهادة خلال عدد الثواني المحدد؛ و1814400 ثانية تساوي 21 يومًا. ويُنبّه اختبار النسخ حين لا يوجد ملف.gzغير فارغ أحدث من 1560 دقيقة، أي 26 ساعة. وينتهي السكربت بـ ping خاص به نحو الفحص الثاني: فبدونه قد يتوقف الفحص اليومي بصمت دون أن يلحظه أحد.echo | openssl s_client -servername your-domain.com -connect your-domain.com:443 2>/dev/null | openssl x509 -noout -checkend 1814400 || alerte-envoi "CERT your-domain.com"find /var/backups/app -name '*.gz' -mmin -1560 -size +1k | grep -q . || alerte-envoi "BACKUP absent". /etc/alerte-vps.env; curl -fsS -m 10 --retry 5 -o /dev/null "$HC_URL_JOUR"ربط الخدمات الحرجة بـ OnFailure
أنشئوا
/etc/systemd/system/[email protected]بالمحتوى التالي ثم نفّذواsudo systemctl daemon-reload.[Unit]Description=Alerte echec de %i[Service]Type=oneshotExecStart=/usr/local/bin/alerte-envoi "FAILED %i"
ولكل خدمة تريدون مراقبتها، افتحوا drop-in بالأمرsudo systemctl edit mariadb.serviceوأضيفوا هذين السطرين.[Unit]OnFailure=notify-failure@%n.serviceافتعال تنبيه للاختبار ثم التنظيف
تنبيه لم يُطلَق قط ليس تنبيهًا. تحققوا أولًا من المساحة الحرة، وأنشئوا ملفًا كبيرًا بما يكفي لتجاوز العتبة، وشغّلوا السكربت يدويًا، ثم احذفوا الملف. وإن لم تصل الرسالة فالخلل في القناة، ومن الأفضل اكتشافه الآن.
df -h --output=pcent,target /var/tmpsudo fallocate -l 2G /var/tmp/test-alerte.imgsudo /usr/local/bin/alerte-rapidesudo rm /var/tmp/test-alerte.img
الذاكرة: OOM النواة أم حد cgroup
هناك آليتان تقتلان عملية لنقص الذاكرة، ولا تُقرآن في المكان نفسه. الأولى هي OOM killer في النواة حين تنقص الذاكرة الجهاز كله: فيحتوي سجل النواة على رسالة من نوع Out of memory: Killed process يتيح journalctl -k العثور عليها. والثانية هي حد cgroup. وبحسب توثيق systemd، حين يتعذر احتواء استهلاك وحدة تحت MemoryMax= يُستدعى OOM killer داخل الوحدة: وقد يبقى لبقية الجهاز ذاكرة حرة.
ويغطي العدّاد oom_kill في /proc/vmstat الحالة الأولى على مستوى الجهاز. أما لوحدة بعينها فيعرض الملف memory.events في cgroup الخاص بها عدّادًا oom_kill خاصًا، تعرّفه وثائق النواة بأنه عدد عمليات الـ cgroup التي قتلها أي نوع من OOM killer. وعلى VPS يستضيف تطبيقًا شرهًا، مثل التطبيق الموصوف في دليل n8n وOOM في الإنتاج، يفسّر هذا العدّاد الثاني التوقفات التي لا يُظهرها free -h أبدًا.
OnFailure: ما يغطيه وما لا يغطيه
بحسب توثيق systemd، يسرد OnFailure= الوحدات التي تُفعَّل حين تدخل الوحدة حالة failed. يتلقى القالب [email protected] اسم الوحدة المعطوبة عبر المحدّد %n، ويمكن لرسالة التنبيه أن ترفق مخرجات systemctl status أو journalctl -u للسياق.
والحد بنيوي: الخدمة التي تعمل لكنها لم تعد تستجيب لم تمرّ قط بحالة failed، فلا يقول OnFailure= شيئًا. والخدمة التي يعيد Restart= تشغيلها لا تبلغ تلك الحالة إلا عند بلوغ حد المحاولات. ولهذه الحالات أضيفوا مسبارًا بسيطًا للتطبيق، مثل curl على عنوان صحة التطبيق، في السكربت السريع. وقد عولجت صيغة المؤقّتات وcron في دليل cron ومؤقّتات systemd، فلا داعي لتكرارها هنا.
الشهادات والنسخ: التنبيه على غياب النجاح
قد يفشل التجديد التلقائي للشهادة بصمت أسابيع: سجل DNS عُدّل، أو منفذ محجوب، أو إضافة معطوبة. ولا تنتهي الشهادة في ذلك اليوم بل بعد تسعين يومًا، ولا يتذكر أحد. ويستجوب اختبار openssl ما يتلقاه الزائر فعلًا، وهذا أفضل من قراءة ملف على القرص. وعلى خادم تديره Certbot، يسرد certbot certificates الشهادات وتواريخ انتهائها، ويتحقق certbot renew --dry-run من أن التجديد القادم سينجح.
المنطق نفسه للنسخ الاحتياطية. التنبيه المرتبط بفشل سكربت النسخ لا يرى الحالة التي لم يُشغَّل فيها السكربت قط. والتنبيه الصحيح يُوضع على الغياب: لا ملف حديث، أو ملف حجمه صفر. وهذا ما يفعله السطر find -mmin في السكربت اليومي، ولذلك يصمت حين يسير كل شيء على ما يرام ويتكلم فور توقف سلسلة النسخ، أيًّا كان السبب.
سكربتات خاصة أم منظومة مراقبة
مرّر الجدول أفقيًا
| المعيار | سكربتات shell وOnFailure | Beszel أو Uptime Kuma |
|---|---|---|
| الإعداد | ساعة واحدة، بضعة ملفات في `/usr/local/bin` | hub يلزم استضافته ووكلاء يُثبَّتون على كل VPS |
| الأسطول المستهدف | من 1 إلى 5 خوادم VPS، وحتى 10 إذا تطابقت العتبات | ما بعد 5 إلى 10 خوادم VPS، أو حين تلزم المقارنة |
| السجل والرسوم | لا شيء، فقط لحظة التنبيه | رسوم واتجاهات ومقارنة بين الأجهزة |
| الصيانة | لا شيء يُحدَّث خارج shell | خادم ثانٍ وتحديثاته يلزم متابعتها |
| خدمات التطبيق | مسبار `curl` تكتبونه بأنفسكم | مسابير HTTP وTCP وصفحة حالة جاهزة |
| عطل المراقِب | تكشفه النبضة الخارجية | يلزم مراقبته على حدة، فالـ hub جهاز بدوره |
| متى تختارونه | تنبيهات دنيا، أسطول صغير، دون خادم إضافي | سجل مطلوب، أسطول متنامٍ، فريق مشترك |
راقبوا المراقِب
فخ هذه السكربتات أن تتحول إلى طمأنة زائفة: تصمت لأن كل شيء سليم أو لأنها معطوبة، ويبدو الصمت واحدًا في الحالتين. وتحل نبضة الـ ping المشكلة. اضبطوا المدة المتوقعة للفحص فوق فاصل cron بقليل وأضيفوا هامش سماح: تنبيه صمت يصل متأخرًا عشرين دقيقة خير من إنذار كاذب عند كل إعادة تشغيل. واحتفظوا أيضًا بالملف /etc/alerte-vps.env في الوضع 600 ولا تضعوا الرمز في نظام التحكم بالإصدارات أبدًا.
استكشاف الأخطاء: الأعطال التي تتكرر
تتعطل التنبيهات نفسها بطرق يمكن توقعها. هذه أكثر الحالات مصادفة، مع الرسالة أو العَرَض الذي ينبغي التعرف عليه والعلاج. ويُتحقق من كل منها يدويًا قبل البحث أبعد.
الرسائل والأعراض مع علاجها
PANIC: could not write to file "pg_wal/...": No space left on device— المجلد الذي يحمل سجلات PostgreSQL ممتلئ. حرّروا مساحة خارج PostgreSQL أولًا (سجلات مدوَّرة، نسخ قديمة)، ولا تحذفوا ملفاتpg_walيدويًا أبدًا، ثم أعيدوا تشغيل الخدمة.No space left on deviceبينما يعرضdf -hمساحة حرة — الـ inodes مستنفدة. نفّذواdf --output=ipcent,target، وحدّدوا المجلد الذي يضم ملايين الملفات الصغيرة (جلسات، تخزين مؤقت) ونظّفوه.- القرص ممتلئ لكن
duلا يجد المساحة — ملفات محذوفة ما زالت مفتوحة لدى عملية. يسردهاsudo lsof +L1؛ وإعادة تشغيل العملية تحرر المساحة. oom_killيرتفع ولا شيء فيjournalctl -k— دار سجل النواة أو أن القتل ناتج عن حدMemoryMax=. اقرؤواmemory.eventsفي مجلد cgroup الوحدة وjournalctl -uللوحدة.- وحدة تعمل لكنها لا تستجيب ولا تنبيه — هذا حد
OnFailure=. أضيفوا مسبارcurlعلى عنوان الصحة ونبّهوا بحسب رمز الإرجاع. - لا رسالة Telegram ولا خطأ ظاهر — يرسل cron مخرجات السكربت بريدًا محليًا لا يقرؤه أحد. شغّلوا
alerte-envoi testيدويًا بـsudoواقرؤوا ردّcurl. - الشهادة تقترب من الانتهاء رغم تثبيت Certbot — نفّذوا
certbot renew --dry-runواقرؤوا خطأ التحقق، ثم صحّحوا DNS أو المنفذ المعني.
التوثيق الرسمي
كل سلوك موصوف هنا مصدره مرجع أولي. بالنسبة إلى OnFailure= راجعوا صفحة دليل systemd.unit؛ وبالنسبة إلى MemoryMax= راجعوا systemd.resource-control؛ وللعدّادين oom وoom_kill راجعوا توثيق cgroups v2 في النواة؛ وللـ 5 % المحجوزة راجعوا صفحة دليل tune2fs. وفي جانب الإرسال تصف واجهة Telegram Bot شكل الطلبات، وتصف وثائق واجهة Healthchecks عناوين الـ ping، مع صفحة الأسعار لحدود الخطة المجانية. وبخصوص التجديد راجعوا توثيق Certbot. ورسالة PostgreSQL المقتبسة مصدرها نقاش في القائمة البريدية الرسمية للمشروع.
تنبيهات بسيطة ومتطابقة على كل VPS
ستة تنبيهات ونبضة لا تحل محل منظومة مراقبة، لكنها تغطي ما يُسقط خادمًا فعلًا: القرص والـ inodes والذاكرة والخدمات والشهادات والنسخ. والمكسب الرئيسي هو التجانس: العتبات نفسها والرسائل نفسها وطريقة الاختبار نفسها على كل جهاز في الأسطول. وحين يكبر الأسطول أو يلزم سجل تاريخي، يُمهَّد الانتقال إلى منظومة في دليل Beszel وفي دليل التنبيهات الاستباقية مع Beszel وUptime Kuma، وهما يعالجان التثبيت من أوله إلى آخره.