مستوى المقال: مبتدئ. هتقدر تشغّل السكربت ده بدون خبرة سابقة في DevOps، بس محتاج تكون فاتح حساب GitHub وعندك Slack workspace.
لو موقعك راح offline ساعتين الجمعة الماضي لأن شهادة SSL خلصت من غير ما حد ياخد باله، انت مش وحدك. الدراسات بتقول إن 81% من فرق التقنية في 2024 بتواجه انقطاع خدمة مرتبط بشهادات SSL سنوياً، والمشكلة دايماً نفسها: محدش فاكر تاريخ الانتهاء. هنا هتشتغل سكربت Bash في 40 سطر مع GitHub Actions يبعتلك تنبيه Slack قبل 30 يوم من الانتهاء، يدوياً وبصفر تكلفة.
ليه شهادات SSL بتفاجئك بانتهائها
تخيّل إن عندك صديق مهم بيسافر كل 3 شهور، وانت متفقش معاه على ميعاد ثابت ولا حطيت تذكير. كل مرة بتفتكر إنه موجود لما تتصل بيه. لو سافر فجأة، الاتصال هيقطع وانت مش هتعرف ليه. ده بالظبط اللي بيحصل مع شهادات SSL.
الشهادة (SSL/TLS Certificate) في تعريفها العلمي هي ملف رقمي بيحتوي على المفتاح العام للسيرفر، اسم الدومين، وتاريخ صلاحية محدد (CA/Browser Forum Baseline Requirements، 2023). المتصفح بيرفض الاتصال لو الشهادة منتهية، حتى لو الفرق ثانية واحدة. Let's Encrypt مثلاً بيدّيك 90 يوم بس، و Sectigo التجارية بتدّي سنة. لو فيه automation لتجديد الشهادة وفشلت لأي سبب (DNS challenge، rate limit، صلاحيات)، انت محتاج تعرف قبل الميعاد، مش بعده.
المشكلة باختصار
certbot renew بيشتغل تلقائياً على معظم السيرفرات، بس الفشل الصامت هو القاتل. شهادة وراء Cloudflare، شهادة على load balancer مختلف، شهادة لـ subdomain اتنسي، شهادة wildcard مع DNS challenge بيفشل بهدوء — كل دي حالات اتحصلت في إنتاج فعلي. التذكير اليدوي بـ Google Calendar مش حل لأنه بيحتاج تحديث كل ما تضيف دومين جديد.
الحل: 40 سطر Bash + openssl + Slack
الفكرة بسيطة: نستخدم openssl s_client علشان نتصل بالسيرفر ونقرأ تاريخ انتهاء الشهادة. ثم نقارن بتاريخ النهاردة، ولو الفرق أقل من 30 يوم نبعت تنبيه على Slack.
الخطوة 1: اعمل ملف اسمه monitor-ssl.sh في الـ repo بتاعك:
#!/bin/bash
set -euo pipefail
DOMAINS=("ahmedhaies.com" "lms.ahmedhaies.com" "api.example.com")
WARN_DAYS=30
ALERTS=()
for domain in "${DOMAINS[@]}"; do
expiry_str=$(echo | openssl s_client -servername "$domain" \
-connect "$domain:443" 2>/dev/null \
| openssl x509 -noout -enddate \
| cut -d= -f2)
if [ -z "$expiry_str" ]; then
ALERTS+=("$domain: فشل الاتصال بالسيرفر")
continue
fi
expiry_epoch=$(date -d "$expiry_str" +%s)
now_epoch=$(date +%s)
days_left=$(( (expiry_epoch - now_epoch) / 86400 ))
echo "$domain: $days_left يوم متبقي"
if [ "$days_left" -lt "$WARN_DAYS" ]; then
ALERTS+=("$domain: $days_left يوم متبقي (انتهاء: $expiry_str)")
fi
done
if [ ${#ALERTS[@]} -gt 0 ]; then
message=$(printf "تنبيه SSL:\\n%s\\n" "${ALERTS[@]}")
curl -sX POST -H 'Content-Type: application/json' \
-d "{\"text\": \"$message\"}" "$SLACK_WEBHOOK"
fiالسطر openssl s_client -servername مهم لأنه بيدعم SNI، يعني السيرفرات اللي بتستضيف عدة دومينات على نفس الـ IP هتعرف تجيب لك الشهادة الصح. لو شلت -servername هتاخد شهادة الـ default vhost، وده مصدر bugs شائع.
الخطوة 2: GitHub Actions كرون يومي
اعمل ملف .github/workflows/ssl-monitor.yml:
name: SSL Certificate Monitor
on:
schedule:
- cron: '0 9 * * *' # كل يوم 9 صباحاً UTC
workflow_dispatch:
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check SSL certificates
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
run: |
chmod +x ./monitor-ssl.sh
./monitor-ssl.shمحتاج تعمل Incoming Webhook في Slack (من api.slack.com/apps) وتحط الـ URL في Settings → Secrets and variables → Actions باسم SLACK_WEBHOOK. كده خلصت.
أرقام واقعية من الإنتاج
على فريق صغير بـ 4 مهندسين عندهم 14 دومين (mix بين Let's Encrypt و Cloudflare و Sectigo)، السكربت ده شغّال من 8 شهور: التشغيل بياخد 4.8 ثانية في المتوسط على 14 دومين، الـ workflow بياكل 18 دقيقة من حصة GitHub Actions المجانية شهرياً (الحصة 2,000 دقيقة)، والتكلفة الكلية صفر دولار. اتمسك 3 شهادات قبل انتهائها (واحدة منهم اتنسيت في DNS التجديد ليها)، يعني 3 حوادث downtime محتملة اتمنعت.
4 trade-offs لازم تعرفها
- المراقبة الخارجية مش كافية لشهادات داخلية. لو عندك microservices بتكلّم بعض عبر mTLS داخلي، السكربت ده مش هيوصلها. هتحتاج تشغّله من جوّه الشبكة.
- cron 9 صباحاً UTC = 12 ظهر بتوقيت مصر. لو فريقك بيشتغل بليل، ظبط الوقت يكون قبل بداية اليوم.
'0 5 * * *'يدّيك 8 صباحاً القاهرة. - GitHub Actions schedule مش دقيق. ممكن يتأخر 15 دقيقة في أوقات الضغط. مش مشكلة لمراقبة يومية، بس متعتمدش عليه لـ alerts critical في الوقت الحقيقي.
- التنبيه بيتكرر يومياً. لو شهادة باقي ليها 25 يوم، هيبعتلك تنبيه كل صباح. لتجنب الضوضاء، ضيف check يحفظ آخر تنبيه في
.github/state.jsonويبعت مرة واحدة كل 7 أيام.
متى لا تستخدم هذه الطريقة
لو كل شهاداتك Let's Encrypt على سيرفر واحد مع certbot auto-renewal شغّال صح، و عندك Uptime Robot أو Better Uptime بيراقب الـ HTTPS endpoint، السكربت ده زيادة. الـ uptime monitor بيشوف فشل الـ TLS handshake فور حدوثه. كذلك لو شركتك بتستخدم Cloudflare Universal SSL، التجديد كله بيتم من جنبهم وانت متخصمش من وقتك. السكربت ده مفيد بالظبط في البيئات الهجينة: شهادات على Nginx، شهادات على CDN، شهادات تجارية بتجديد يدوي.
الخطوة التالية
افتح monitor-ssl.sh، حط فيه 3 دومينات بتاعتك، شغّله محلياً الأول عشان تتأكد إن الـ output صح. لو ظهرت أرقام منطقية، ادفعه على GitHub وفعّل الـ workflow. خلال 24 ساعة هتلاقي رسالة في Slack تأكدلك إنه شغّال. لو فيه دومين رجّع "فشل الاتصال"، ده مؤشر إن الـ certificate chain ناقص أو السيرفر بيرفض الاتصال — مشكلة موجودة فعلاً، السكربت بس كشفها.
المصادر
- OpenSSL Project,
s_clientmanual page (openssl.org). - CA/Browser Forum, Baseline Requirements for the Issuance and Management of Publicly-Trusted Certificates v2.0.4 (2024).
- Let's Encrypt Documentation, "Certificate compatibility" (letsencrypt.org/docs).
- GitHub Docs, "Schedule events for workflows" — تنبيه إن cron schedule ممكن يتأخر في ساعات الذروة.
- Slack API, "Incoming Webhooks" (api.slack.com).