كلاود
أدلة

فشل تجديد شهادة Let's Encrypt: الأسباب السبعة وحلولها

كلاود|٢ نوفمبر ٢٠٢٦|6 دقائق قراءة|٢ مشاهدة
فشل تجديد شهادة Let's Encrypt: الأسباب السبعة وحلولها

أغلب حالات فشل تجديد Let's Encrypt ترجع لسبعة أسباب، من منفذ 80 المغلق وبروكسي CDN إلى خدمة لم تُعِد تحميل الشهادة. ابدأ بـcertbot renew --dry-run ثم راقب الانتهاء من الخارج قبل 14 يوماً.

شهادة Let's Encrypt صالحة 90 يوماً فقط، وCertbot يحاول تجديدها تلقائياً حين يتبقى 30 يوماً على انتهائها، أي أن عندك نافذة أمان من 60 محاولة يومية تقريباً قبل أن يرى زوارك تحذير "الاتصال غير آمن". المشكلة أن التجديد حين يفشل يفشل بصمت، فلا أحد يقرأ سجل /var/log/letsencrypt/letsencrypt.log إلا بعد أن يتصل عميل غاضب. الجواب المباشر: أغلب حالات الفشل ترجع لسبع حالات محددة، وهي منفذ 80 مغلق في الجدار الناري، بروكسي CDN يعترض طلب التحقق، سجل AAAA قديم يوجّه Let's Encrypt لعنوان IPv6 لا يرد، تجاوز حدود المعدل، مسار webroot تغيّر بعد نقل الموقع، مؤقت systemd أو cron الخاص بالتجديد معطّل، وخدمة الويب التي جددت الشهادة على القرص لكنها ما زالت تقدّم القديمة من الذاكرة. ابدأ دائماً بأمر واحد يكشف لك الحقيقة دون أن يستهلك حدودك: certbot renew --dry-run، فهو يجرب التجديد كاملاً على خادم الاختبار (staging) ويطبع سبب الفشل بالضبط. بعدها طابق رسالة الخطأ مع الأسباب السبعة أدناه، ثم أضف مراقبة تنبهك قبل الانتهاء بـ14 يوماً على الأقل حتى لا يتكرر الأمر.

كيف يعمل التجديد أصلاً

حين يطلب Certbot شهادة جديدة، يعطيه خادم Let's Encrypt رمزاً عشوائياً، ويطلب منه وضعه في مكان يثبت أنك تتحكم بالنطاق. في تحدي HTTP-01 يوضع الرمز في ملف تحت المسار /.well-known/acme-challenge/ ثم يزوره Let's Encrypt من عدة مواقع حول العالم عبر المنفذ 80. في تحدي DNS-01 يوضع الرمز في سجل TXT باسم _acme-challenge، وهذا هو الخيار الوحيد للشهادات العامة (wildcard). فهم هذه الخطوة يختصر عليك نصف التشخيص، لأن كل الأسباب الشائعة تقريباً تعني شيئاً واحداً: الزائر القادم من Let's Encrypt لم يصل للملف الذي كتبه Certbot.

على أغلب التوزيعات الحديثة يأتي Certbot مع مؤقت systemd اسمه certbot.timer يعمل مرتين يومياً بتأخير عشوائي، وعلى تثبيتات snap يكون اسمه snap.certbot.renew.timer. أما التثبيتات القديمة فتعتمد على سطر في /etc/cron.d/certbot. تأكد أي واحد عندك قبل أن تفترض أن التجديد يعمل.

الأسباب السبعة وحل كل واحد

1. المنفذ 80 مغلق

كثير من فرق الأمان تغلق المنفذ 80 بعد تفعيل HTTPS بحجة أن كل شيء صار مشفراً، وهذا يكسر تحدي HTTP-01 مباشرة لأن Let's Encrypt لا يبدأ التحقق إلا عبر 80. ستظهر لك رسالة فيها Timeout during connect أو Connection refused. الحل أن تفتح 80 وتحوّل كل الطلبات إلى HTTPS ما عدا مسار التحدي، وتتحقق من الجدار الناري بـufw status أو nft list ruleset، ولا تنسَ جدار المزود الخارجي إن وُجد.

2. بروكسي CDN يعترض التحدي

إذا كان النطاق خلف Cloudflare أو أي CDN بخاصية "Always Use HTTPS" أو قواعد WAF صارمة، فقد يرد البروكسي بنفسه على طلب التحدي أو يحجبه كأنه زيارة آلية. العلامة أن الخطأ يذكر عنوان IP تابع لشبكة CDN لا لخادمك. الحلول بالترتيب: استثنِ المسار /.well-known/acme-challenge/* من قواعد التحويل والحماية، أو انتقل إلى تحدي DNS-01 عبر الإضافة الخاصة بمزود DNS، أو استخدم شهادة Origin من المزود نفسه بين البروكسي والخادم.

3. سجل AAAA قديم

Let's Encrypt يفضّل IPv6 إذا وجد سجل AAAA للنطاق. إذا نقلت الموقع لخادم جديد وغيّرت سجل A ونسيت سجل AAAA القديم، سيحاول التحقق عبر عنوان لا يخص خادمك فيفشل، حتى لو كان IPv4 سليماً تماماً. شغّل dig AAAA example.com +short وقارن الناتج بعناوين الخادم الفعلية من ip -6 addr، ثم احذف السجل أو صححه.

4. حدود المعدل

Let's Encrypt يسمح بخمس شهادات مكررة لنفس مجموعة الأسماء كل 168 ساعة، وبخمسة إخفاقات تحقق لكل حساب واسم نطاق في الساعة، و50 شهادة لكل نطاق مسجّل في الأسبوع. السبب المعتاد للوصول لهذه الحدود سكربت نشر يطلب شهادة جديدة مع كل تشغيل بدل التجديد، أو تجارب متكررة على الإنتاج. الرسالة واضحة هنا: too many certificates already issued. الحل أن تجرب دائماً بـ--dry-run أو --staging، وأن تنتظر نهاية النافذة الزمنية بدل المحاولة المتكررة التي تمدد الحجب.

5. مسار webroot تغيّر

عند الإصدار الأول يحفظ Certbot الإعدادات في /etc/letsencrypt/renewal/example.com.conf، ومنها المسار الذي يكتب فيه ملف التحدي. إذا نقلت الموقع من /var/www/html إلى /var/www/app/public كما يحدث مع Laravel، سيكتب Certbot الملف في المجلد القديم بينما يقدّم Nginx المجلد الجديد، فيرجع الخطأ 404. افتح ملف التجديد وعدّل قيمة webroot_path، أو أضف في Nginx موقعاً ثابتاً لمسار التحدي يشير لمجلد مستقل لا يتغير مع النشر، وهذا أنظف حل على المدى الطويل.

6. المؤقت معطل

بعد ترقية التوزيعة أو الانتقال من حزمة apt إلى snap قد يختفي المؤقت أو يبقى معطلاً. شغّل systemctl list-timers | grep certbot، فإذا لم يظهر شيء أو ظهر بلا موعد قادم فالتجديد لا يعمل أصلاً منذ تلك الترقية. فعّله بـsystemctl enable --now certbot.timer وراجع آخر تشغيل بـjournalctl -u certbot.service -n 50.

7. الشهادة تجددت والخدمة لم تُعِد التحميل

هذه أكثر حالة تربك الناس، فالأمر certbot certificates يقول إن الشهادة صالحة 89 يوماً والمتصفح يقول إنها منتهية. السبب أن Nginx أو Apache أو Postfix أو Dovecot تحمّل الشهادة عند التشغيل فقط، وما زالت تقدّم النسخة القديمة من الذاكرة. الحل خطاف نشر دائم: ضع سكربتاً في /etc/letsencrypt/renewal-hooks/deploy/ ينفذ systemctl reload nginx وأي خدمة أخرى تستخدم الشهادة، وتذكّر أن خوادم البريد تحديداً تُنسى كثيراً هنا.

جدول تشخيص سريع

الرسالة في السجلالسبب الأرجحأمر التحقق
Timeout during connectمنفذ 80 مغلق أو IPv6 خاطئcurl -I http://example.com/.well-known/acme-challenge/test
Invalid response 404webroot تغيّرgrep webroot /etc/letsencrypt/renewal/*.conf
Invalid response 403 من IP غريببروكسي CDN أو WAFdig A example.com +short
too many certificatesحدود المعدلcertbot certificates
لا يوجد سجل حديث أصلاًالمؤقت معطلsystemctl list-timers
السجل ناجح والمتصفح يرفضالخدمة لم تُعِد التحميلopenssl s_client -connect example.com:443

راقب تاريخ الانتهاء من الخارج

الدرس الأهم أن نجاح التجديد على القرص لا يعني شيئاً، والذي يهمك هو الشهادة التي يراها الزائر فعلاً. اكتب فحصاً بسيطاً يتصل بالمنفذ 443 ويقرأ تاريخ الانتهاء، مثل openssl s_client -connect example.com:443 -servername example.com مع openssl x509 -noout -enddate، ثم يحسب الأيام المتبقية ويرسل تنبيهاً إذا قلت عن 14 يوماً. لماذا 14؟ لأن Certbot يبدأ التجديد عند 30 يوماً، فإذا وصلت إلى 14 يوماً معناه أن 16 يوماً من المحاولات فشلت، وهذا وقت كافٍ لتصلح دون ضغط. افحص كل منفذ يقدّم شهادة: 443 للويب، و465 و587 و993 للبريد، لأن شهادة البريد المنتهية تجعل رسائلك تتعثر قبل أن تصل صندوق الوارد عند الجهات الصارمة.

إذا كان عندك عشرة نطاقات أو أكثر، اجمع الفحص في سكربت واحد يقرأ قائمة النطاقات ويشتغل يومياً من مؤقت، ويرسل النتيجة لقناة التنبيهات التي يتابعها فريقك فعلاً لا لبريد مهمل. هذا الفحص يأخذ أقل من ثانية لكل نطاق، ويغنيك عن الاعتماد على رسائل Let's Encrypt التحذيرية التي توقفت الخدمة عن إرسالها في 2025 أصلاً.

أين يناسب هذا في بنيتك

على الاستضافة السحابية المُدارة لا تحتاج شيئاً من هذا، فـcPanel يصدر شهادات AutoSSL ويجددها ويعيد تحميل الخدمات بنفسه، والباقات من 2,900 ريال سنوياً شاملة الضريبة. على الخادم السحابي أنت المسؤول عن السلسلة كاملة، وهنا تفيدك هذه القائمة. باقة أساس (1vCPU و2GB و20GB) بـ3,450 ريالاً سنوياً تكفي لموقع أو واجهة API مع Certbot وNginx، وزمن الاستجابة نحو 8ms من الرياض يجعل فحوصات المراقبة نفسها سريعة ودقيقة. راجع التفاصيل في صفحة الأسعار والباقات.

قائمة الخطوات اليوم

  • شغّل certbot renew --dry-run على كل خادم واقرأ النتيجة سطراً سطراً.
  • تحقق من وجود المؤقت وموعده القادم بـsystemctl list-timers.
  • افتح ملفات /etc/letsencrypt/renewal/ وتأكد من صحة webroot وطريقة التحقق.
  • أضف خطاف deploy يعيد تحميل كل خدمة تستخدم الشهادة، بما فيها البريد.
  • راجع سجلات A وAAAA لكل نطاق بعد أي نقل.
  • فعّل فحصاً خارجياً يومياً ينبهك عند 14 يوماً متبقية.

هذه الخطوات الست تأخذ نحو 30 دقيقة لخادم واحد، وتحوّل الشهادة من قنبلة موقوتة كل 90 يوماً إلى شيء لا تفكر فيه، لأنك ستعرف بالمشكلة قبل زوارك بأسبوعين على الأقل.

مشاركة