مستوى المقال: مبتدئ. هتقدر تشغّل السكربت ده بدون خبرة سابقة في 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