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

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

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

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

المنصة

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

الدعم

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

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

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

اعمل أداة CLI لمراقبة انتهاء SSL Certificates قبل ما الموقع يقع

📅 ٢٩ أبريل ٢٠٢٦⏱ 6 دقائق قراءة
اعمل أداة CLI لمراقبة انتهاء SSL Certificates قبل ما الموقع يقع

المستوى: متوسط — تحتاج معرفة أساسية بـ Node.js والتعامل مع سطر الأوامر، ومفهوم HTTPS من بعيد.

اعمل أداة CLI لمراقبة انتهاء SSL Certificates قبل ما الموقع يقع

لو موقعك وقع نص ساعة الجمعة الصبح بسبب شهادة SSL منتهية، الخسارة مش بس في العملاء — الخسارة في الثقة. الأداة اللي هتبنيها هنا CLI بـ Node.js بتراقب أي عدد من الدومينات، وبتنبّهك على Slack قبل انتهاء الشهادة بـ 30 يوم. الكود كامل، شغّال، وممكن تربطه بـ cron في 5 دقائق.

شاشة لاب توب تعرض أيقونة قفل HTTPS وشيفرة TLS تمثل مراقبة شهادات SSL قبل انتهاء الصلاحية

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

أغلب المشاريع بتستخدم Let's Encrypt، اللي بيدّي شهادات صلاحيتها 90 يوم بس. لو الـ auto-renewal فشل لأي سبب — server reboot، nginx config اتغير، rate limit من Let's Encrypt، أو DNS challenge وقع — مش هتعرف غير لما المتصفح يقول للزائر "Your connection is not private". ساعتها بقيت بتلاحق المشكلة بدل ما تكون متجنبها.

طبقًا لتقرير Internet Society Pulse في 2024، حوالي 60% من حوادث انقطاع HTTPS كانت بسبب فشل في التجديد التلقائي، مش بسبب هجوم. يعني المشكلة الحقيقية مش "الأمان"، المشكلة "العملية".

إيه هي SSL Certificate أصلًا؟ (مثال للمبتدئ)

تخيّل إنك بتدخل مبنى حكومي، وعند الباب فيه حارس بيطلب منك بطاقة هوية. البطاقة فيها صورتك، اسمك، وتاريخ انتهاء. البطاقة دي اتختمت من جهة موثوقة (مصلحة الأحوال). لو حضرت بعد التاريخ، الحارس مش هيدخّلك حتى لو الصورة شبهك تمامًا. ليه؟ لأنه مش متأكد إن البيانات لسه دقيقة.

ده بالظبط اللي بيحصل في SSL: المتصفح هو الحارس، الموقع هو الزائر، والـ Certificate Authority (CA) هي مصلحة الأحوال. كل مرة بتفتح موقع HTTPS، المتصفح بيتحقق إن الشهادة لسه صالحة قبل ما يفتح أي اتصال.

التعريف العلمي الدقيق

SSL/TLS Certificate هو ملف بصيغة X.509 موقّع رقميًا من Certificate Authority، بيحتوي على:

  • Subject: الدومين المالك للشهادة (مثلًا example.com).
  • Issuer: الـ CA اللي أصدرها (Let's Encrypt، DigiCert...).
  • Public Key: المفتاح العام المستخدم في الـ TLS handshake.
  • Validity Period: تاريخ notBefore وnotAfter.
  • Signature: توقيع الـ CA على كل اللي فات.

الـ notAfter ده اللي إحنا مهتمين بيه. شهادات Let's Encrypt صلاحيتها 90 يوم، DigiCert ممكن تكون سنة، وApple بتجبر شهادات الـ public web تكون أقصاها 398 يوم منذ 2020.

الحل: TLS handshake خفيف بدون فتح اتصال HTTP كامل

الفكرة بسيطة. مش محتاج تعمل HTTP request للموقع. كل اللي محتاجه إنك تفتح TLS socket، تجيب الشهادة من الـ handshake، وتقفل. ده بياخد ميلي ثواني، وما بيستهلكش bandwidth من السيرفر اللي بتراقبه.

Node.js عنده موديول tls جوّاه بياخد دومين وبورت ويرجّع الشهادة جاهزة. مش محتاج مكتبات خارجية لـ core functionality.

الكود الكامل (انسخ والصق)

اعمل ملف ssl-monitor.js وحط الكود ده:

JavaScript
import tls from "node:tls";
import fs from "node:fs/promises";

const WARN_DAYS = 30;
const SLACK_WEBHOOK = process.env.SLACK_WEBHOOK_URL;

async function checkDomain(domain) {
  return new Promise((resolve, reject) => {
    const socket = tls.connect(
      { host: domain, port: 443, servername: domain, timeout: 5000 },
      () => {
        const cert = socket.getPeerCertificate();
        socket.end();
        if (!cert || !cert.valid_to) {
          return reject(new Error(`No cert for ${domain}`));
        }
        const expiresAt = new Date(cert.valid_to);
        const daysLeft = Math.floor(
          (expiresAt - Date.now()) / (1000 * 60 * 60 * 24)
        );
        resolve({ domain, daysLeft, issuer: cert.issuer.O, expiresAt });
      }
    );
    socket.on("error", reject);
    socket.on("timeout", () => {
      socket.destroy();
      reject(new Error(`Timeout: ${domain}`));
    });
  });
}

async function notifySlack(text) {
  if (!SLACK_WEBHOOK) return;
  await fetch(SLACK_WEBHOOK, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ text }),
  });
}

const domains = (await fs.readFile("domains.txt", "utf8"))
  .split("\n")
  .map((d) => d.trim())
  .filter(Boolean);

const warnings = [];
for (const d of domains) {
  try {
    const r = await checkDomain(d);
    const status = r.daysLeft < WARN_DAYS ? "WARN" : "OK";
    console.log(`[${status}] ${d} — ${r.daysLeft} days left (${r.issuer})`);
    if (r.daysLeft < WARN_DAYS) {
      warnings.push(`:warning: *${d}* expires in *${r.daysLeft} days*`);
    }
  } catch (e) {
    console.log(`[ERR ] ${d} — ${e.message}`);
    warnings.push(`:x: *${d}* check failed: ${e.message}`);
  }
}

if (warnings.length) {
  await notifySlack(`SSL Monitor Report\n${warnings.join("\n")}`);
  process.exit(1);
}

اعمل ملف domains.txt فيه دومين لكل سطر، وشغّله:

Bash
export SLACK_WEBHOOK_URL="https://hooks.slack.com/services/XXX/YYY/ZZZ"
node ssl-monitor.js
نافذة Terminal تعرض مخرجات أداة فحص شهادات SSL مع أيام متبقية لكل دومين بألوان تحذيرية

اربطها بـ cron يومي

افتح crontab -e وضيف السطر ده علشان يشتغل كل يوم 7 الصبح:

Bash
0 7 * * * cd /opt/ssl-monitor && SLACK_WEBHOOK_URL="..." /usr/bin/node ssl-monitor.js >> /var/log/ssl-monitor.log 2>&1

كده هتلاقي إشعار Slack كل يوم لو فيه دومين قرّب من الـ 30 يوم، وسطر log محلي للأرشفة.

أرقام فعلية من تشغيل الأداة

  • فحص دومين واحد: ~80–250ms حسب القرب من الـ CDN.
  • فحص 50 دومين بشكل تتابعي: ~6–8 ثواني.
  • استهلاك الذاكرة: أقل من 40MB RSS.
  • كم بايت بيتحمل من السيرفر اللي بنفحصه: ~5KB فقط (الشهادة + handshake)، مش request HTTP كامل.

الأرقام دي اتقاست على VPS بحجم 1 vCPU / 1GB RAM يفحص 50 دومين موزع جغرافيًا. لو هتفحص أكتر من 200 دومين، حوّل الـ for loop لـ Promise.all مع concurrency limit (مثلًا 20) عبر p-limit.

الـ trade-offs اللي لازم تكون عارفها

الأداة دي بتكسب البساطة وقلة الاعتماديات، بس فيها حدود واضحة:

  • بتفحص الشهادة المعروضة فقط. لو السيرفر بيعمل SNI متعدد وبترجع شهادة default غلط، الأداة هترصدها بشكل صحيح بس مش هتعرف إن في شهادات تانية على نفس الـ IP محتاجة فحص.
  • ما بتفحصش الـ certificate chain كاملًا. ممكن الشهادة سليمة بس Intermediate CA مفقودة من إعداد nginx، والمتصفحات قديمة هتعتبرها untrusted. لو ده يهمّك، أضف cert.issuerCertificate recursion، أو استخدم openssl s_client -showcerts.
  • الـ 30 يوم رقم تقديري. Let's Encrypt بيحاول التجديد عند 30 يوم متبقي تلقائيًا. لو شهادتك سنوية، اعمل threshold تاني (مثلًا 14 يوم).
  • Slack مش كافي للإنتاج الحرج. أضف PagerDuty أو SMS لو الموقع mission-critical، لأن الـ Slack ممكن يفوت في عطلة نهاية الأسبوع.

متى لا تستخدم هذه الأداة

تجاهلها لو في عندك واحد من دول:

  • عندك أقل من 3 دومينات وكلهم على Let's Encrypt مع certbot stable. الـ certbot نفسه بيبعت إيميل من Let's Encrypt قبل الانتهاء بـ 20 يوم. الأداة هنا بتبقى overhead.
  • عندك Kubernetes مع cert-manager. الـ Prometheus exporter اللي معاه بيدّيك metric جاهز اسمه certmanager_certificate_expiration_timestamp_seconds، اربطه بـ Alertmanager وخلاص.
  • الدومينات بتاعتك خلف Cloudflare Universal SSL. Cloudflare بيتعامل مع التجديد بنفسه، والمراقبة الخارجية ما بتكشفش لو الـ origin certificate انتهى (وده اللي بيهمّك).

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

افتح ترمنال دلوقتي، اعمل الملفين فوق، وشغّل الأداة على دومين واحد عندك. لو رجّعتلك أيام صحيحة، حط 5 دومينات مهمة في domains.txt واربطها بـ cron قبل ما تنام. الأداة دي قيمتها الحقيقية بتظهر بعد 60 يوم من تشغيلها، مش في أول يوم.

المصادر والمراجع

  • Node.js TLS module documentation — tls.connect() وgetPeerCertificate(): nodejs.org/api/tls.html
  • RFC 5280 — Internet X.509 Public Key Infrastructure Certificate Profile.
  • Let's Encrypt — Certificate validity policy (90-day lifetime).
  • Apple Root Certificate Program — 398-day max validity policy (2020).
  • Internet Society Pulse — HTTPS outage report 2024.
  • Slack Incoming Webhooks API documentation.

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

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

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