لماذا تدير Let's Encrypt بنفسك على خادم VPS
Let's Encrypt هي سلطة إصدار شهادات مجانية تُصدر شهادات TLS مُتحقَّقًا منها عبر تحدٍّ مؤتمت (HTTP-01 أو DNS-01). فعلى استضافة مشتركة، أنت خاضع لتهيئة TLS الخاصة بالمزوّد: إصدارات بروتوكول مفروضة، ولا OCSP stapling، وتجديد مبهم. أما على خادم VPS، فأنت تملك certbot (أو acme.sh) والوكيل العكسي وإنهاء TLS. أنت من يقرّر البروتوكولات (TLS 1.2/1.3 فقط)، ومجموعات التشفير، وHSTS، وربط شهادة OCSP (stapling). ويمكنك أيضًا إصدار شهادة wildcard (*.your-domain.com) عبر تحدّي DNS-01، وتغطية عدة نطاقات في شهادة واحدة (SAN)، وربط التجديد بتنبيهاتك الخاصة. باختصار: تحكّم كامل في أمن النقل، وهو شرط لتقييم A+ على SSL Labs ولأقصى درجة ثقة من جانب المتصفح.
ما الذي تكسبه باستضافة سلسلة TLS ذاتيًا
- شهادات مجانية 100%، صالحة 90 يومًا وتُجدَّد تلقائيًا دون تدخّل.
- شهادة wildcard
*.your-domain.comممكنة عبر تحدّي DNS-01: شهادة واحدة لجميع نطاقاتك الفرعية. - تحكّم كامل في التهيئة: TLS 1.3، ومجموعات تشفير حديثة، وHSTS، وOCSP stapling.
- شهادات SAN متعددة النطاقات (
your-domain.comوwww.your-domain.comوapi.your-domain.com) على عنوان IP واحد. - تجديد قابل للبرمجة والمراقبة: خطّافات إعادة التحميل، وتنبيهات Slack/بريد إلكتروني قبل انتهاء الصلاحية.
- لا اعتماد على لوحة طرف ثالث: الوصفة نفسها تعمل على جميع خوادمك VPS وبيئاتك.
متطلبات مسبقة واقعية
يستهلك إنهاء TLS موارد قليلة جدًا: فخادم VPS بـ 1 vCPU / 512 ميغابايت إلى 1 غيغابايت من RAM يكفي وأكثر لتقديم HTTPS لموقع واحد أو عدة مواقع.
من ناحية الشبكة: يجب أن يُشير اسم نطاقك إلى عنوان IP العام للخادم (سجلّ A/AAAA منتشر). تحقّق من الانتشار قبل تشغيل certbot: يجب أن يُرجع dig +short your-domain.com عنوان IP الخاص بخادمك. تحدٍّ يفشل بسبب انتشار DNS غير مكتمل يُحسب كمحاولة ويقرّبك من حدود معدل ACME.
المنفذان 80 و443 مفتوحان في جدار الحماية — المنفذ 80 ضروري لتحدّي HTTP-01:
ufw allow 80/tcp
ufw allow 443/tcp
ufw reloadلشهادة wildcard (*.your-domain.com)، لا يكفي تحدّي HTTP-01: جهّز وصولًا عبر واجهة برمجة (API) إلى مزوّد DNS الخاص بك (رمز token) لأتمتة تحدّي DNS-01.
تثبيت certbot والحصول على شهادة Nginx
تثبيت certbot وإضافة Nginx
على Debian/Ubuntu:
apt update apt install -y certbot python3-certbot-nginxتقرأ إضافة
python3-certbot-nginxإعداد Nginx الخاص بك، وتحقن تهيئة TLS وتستبدل التوجيهlisten 80بكتلة443 ssl. إذا كنت تُفضّل التحكّم اليدوي في Nginx، استخدم--standaloneأو--webrootبدلًا من--nginx.توجيه النطاق وفتح المنافذ
أنشئ سجلّ A باسم
your-domain.com(وسجلّ AAAA إن كان IPv6) يُشير إلى عنوان IP الخاص بالخادم، ثم اسمح بحركة الويب:ufw allow 80,443/tcpأكِّد التحويل (resolution) عبر
dig +short your-domain.comقبل المضي أبعد — فالتحدّي يفشل دائمًا إذا لم يكن DNS يُشير بعد.إصدار الشهادة مع إضافة Nginx
الطريقة الأكثر مباشرة — يعدّل certbot vhost Nginx الخاص بك ويدير التجديد:
certbot --nginx -d your-domain.com -d www.your-domain.comيطلب certbot عنوان بريد إلكتروني (تنبيهات الانتهاء) ويدعوك لقبول شروط الخدمة. يُصدر الشهادة ويعدّل
/etc/nginx/sites-available/<vhost>ويضيف إعادة توجيه HTTP→HTTPS ويُعيد تحميل Nginx دون انقطاع.تُودَع الملفات في
/etc/letsencrypt/live/your-domain.com/:fullchain.pem(الشهادة + السلسلة) وprivkey.pem(المفتاح الخاص).التحقق من التجديد التلقائي
يُثبّت certbot مؤقّت systemd يحاول التجديد مرتين يوميًا:
systemctl status certbot.timerلمحاكاة تجديد دون إصدار شهادة جديدة:
certbot renew --dry-runإن نجحت المحاكاة، فسلسلة التجديد لديك تعمل. تأكّد من أن Nginx يُعاد تحميله بعد تجديد فعلي — يُضيف certbot تلقائيًا خطّاف
--deploy-hook "systemctl reload nginx"في/etc/letsencrypt/renewal/<domain>.confعند استخدام إضافة Nginx.
شهادة wildcard مع Cloudflare DNS challenge
تغطّي شهادة *.your-domain.com جميع نطاقاتك الفرعية بملف واحد. وهي إلزامية إذا كنت تنشئ نطاقات فرعية ديناميكيًا أو إذا كنت لا تريد إصدار شهادة لكل نطاق فرعي.
لا يستطيع تحدّي HTTP-01 التحقق من wildcard — فأنت بحاجة إلى تحدّي DNS-01 الذي يطلب من certbot إنشاء سجلّ TXT مؤقت _acme-challenge.your-domain.com.
مع Cloudflare (رمز API token):
apt install -y python3-certbot-dns-cloudflareأنشئ ملف بيانات اعتماد Cloudflare (صلاحيات: 600):
mkdir -p /etc/letsencrypt/cloudflare
chmod 700 /etc/letsencrypt/cloudflare
cat > /etc/letsencrypt/cloudflare/credentials.ini << 'EOF'
dns_cloudflare_api_token = YOUR_CLOUDFLARE_API_TOKEN
EOF
chmod 600 /etc/letsencrypt/cloudflare/credentials.iniأصدر شهادة wildcard:
certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare/credentials.ini \
-d your-domain.com \
-d '*.your-domain.com'يُنشئ certbot سجلّ TXT، وينتظر الانتشار (10 ثوانٍ بشكل افتراضي — قابل للزيادة بـ --dns-cloudflare-propagation-seconds 30)، يحصل على الشهادة، ثم يحذف سجلّ TXT.
البديل مع acme.sh:
acme.sh --issue --dns dns_cf -d your-domain.com -d '*.your-domain.com'يستخدم acme.sh متغير البيئة CF_Token أو CF_Key + CF_Email بحسب طريقة مصادقة Cloudflare لديك.
تحصين TLS في Nginx: TLS 1.2/1.3 وHSTS ومجموعات التشفير
تُهيّئ إضافة certbot HTTPS وظيفيًا، لكن الإعداد الافتراضي ليس مثاليًا للحصول على تقييم A+ على SSL Labs. إليك التوجيهات التي يجب إضافتها في كتلة server (أو في ملف مُدرَج مثل /etc/nginx/snippets/ssl-params.conf):
# البروتوكولات: TLS 1.2 كحد أدنى، TLS 1.3 موصى به
ssl_protocols TLSv1.2 TLSv1.3;
# مجموعات تشفير حديثة (Mozilla Intermediate)
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off;
# جلسة TLS
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 8.8.8.8 valid=300s;
resolver_timeout 5s;
# HSTS (6 أشهر، مع النطاقات الفرعية، preload)
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload" always;
# رؤوس أمان إضافية
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;وجّه كل المنفذ 80 إلى 443 في كتلة server منفصلة:
server {
listen 80;
server_name your-domain.com www.your-domain.com;
return 301 https://$host$request_uri;
}أعِد التحميل دون انقطاع: nginx -s reload. ثم اختبر على SSL Labs — يجب أن تحصل على A+.
مراقبة انتهاء صلاحية الشهادات
قد يفشل التجديد التلقائي بصمت: مؤقّت systemd معطَّل، المنفذ 80 محجوب بعد تعديل جدار الحماية، رمز API Cloudflare مُلغى... شهادة منتهية الصلاحية في الإنتاج تُوقف الخدمة لجميع زوّارك.
التحقق اليدوي:
echo | openssl s_client -connect your-domain.com:443 -servername your-domain.com 2>/dev/null \
| openssl x509 -noout -datesسكربت تنبيه بالبريد الإلكتروني (للوضع في cron أو systemd):
#!/bin/bash
# تنبيه إذا كانت الشهادة تنتهي خلال أقل من 14 يومًا
cert_file="/etc/letsencrypt/live/your-domain.com/fullchain.pem"
if ! openssl x509 -checkend 1209600 -noout -in "$cert_file" 2>/dev/null; then
echo "تنبيه: شهادة your-domain.com تنتهي خلال أقل من 14 يومًا" \
| mail -s "[SSL] انتهاء وشيك" [email protected]
fi-checkend 1209600 يُقابل 14 يومًا بالثواني (14 × 86400).
مع Uptime Kuma: أضف مراقبًا من نوع «Certificate Expiry» يُنبّه قبل 14 يومًا — دون الحاجة لصيانة أي سكربت.
استكشاف الأخطاء: حدود المعدل، المنفذ 80 محجوب، انتشار DNS
حدود معدل ACME «too many certificates already issued»
يُحدّد Let's Encrypt بـ 5 شهادات لكل نطاق قابل للتسجيل أسبوعيًا. إذا وصلت إلى هذا الحد أثناء الاختبار، انتقل إلى بيئة staging:
certbot --nginx --staging -d your-domain.comتُصدر بيئة staging شهادات غير موثوقة من المتصفحات، لكن دون حدود معدل. بمجرد التحقق من إعدادك، احذف شهادة staging وأعِد الإصدار في الإنتاج.
المنفذ 80 محجوب
يتطلب تحدّي HTTP-01 أن يصل Let's Encrypt إلى http://your-domain.com/.well-known/acme-challenge/. تحقق:
curl -I http://your-domain.com/.well-known/acme-challenge/test
# المتوقع: 404 (المسار موجود، الملف لا يوجد بعد)
ufw status | grep 80إذا كان المنفذ 80 محجوبًا بجدار حماية علوي (مزوّد سحابي، Cloudflare في وضع proxy)، افتحه مؤقتًا أو انتقل إلى تحدّي DNS-01.
Cloudflare proxy نشط
إذا كان نطاقك خلف Cloudflare (أيقونة السحابة البرتقالية)، تأكّد أن وضع SSL في Cloudflare هو Full (Strict) — في وضع Flexible، يتواصل Cloudflare مع خادمك عبر HTTP وnginx الذي يُعيد توجيه HTTP→HTTPS يُنتج حلقة لا نهاية لها (HTTP 525/526).
انتشار DNS غير كافٍ
لتحدّي DNS-01، انتظر 60 ثانية على الأقل بعد إنشاء سجلّ TXT قبل إعادة تشغيل certbot. تحقق:
dig TXT _acme-challenge.your-domain.com +shortإذا لم تظهر القيمة بعد، انتظر قبل المحاولة مجددًا.
مقارنة: certbot مقابل acme.sh مقابل Caddy HTTPS التلقائي
مرّر الجدول أفقيًا
| المعيار | certbot | acme.sh | Caddy (HTTPS تلقائي) |
|---|---|---|---|
| التثبيت | `apt install certbot` | سكربت bash، لا تبعيات نظام | ملف ثنائي واحد، مُدمج |
| تكامل Nginx/Apache | إضافة أصلية (`--nginx`، `--apache`) | خطّافات `--install-cert` يدوية | يدير وكيله العكسي الخاص |
| Wildcard DNS-01 | عبر إضافة DNS (`python3-certbot-dns-*`) | أصلي، مزودي DNS متعددون مُدمجون | عبر وحدة `tls.dns.*` (Caddy v2) |
| التجديد | مؤقّت systemd (تلقائي) | مهمة cron تُنشأ عند التثبيت | أصلي، دون إعداد |
| منحنى التعلم | منخفض — أوامر بديهية | متوسط — خيارات كثيرة | منخفض جدًا — Caddyfile مبسَّط |
| حالة الاستخدام المثالية | خادم Nginx/Apache مخصص قائم | بيئات معقدة، مزودو DNS متعددون | مشاريع جديدة، وكيل عكسي مُدمج |
الاختبار قبل الإنتاج
قبل الانتقال إلى الإنتاج، اختبر مقابل بيئة staging الخاصة بـ Let's Encrypt (--staging مع Certbot، و--server letsencrypt_test مع acme.sh): فحدّ الإنتاج هو 5 إصدارات لكل نطاق أسبوعيًا، وقد يجعلك سكربت سيّئ الضبط تبلغه بسرعة.
أضِف أيضًا مراقبة انتهاء الصلاحية: مسبار (probe) ينفّذ openssl x509 -checkend 604800 (7 أيام) ويُطلق تنبيهًا إذا فشل التجديد التلقائي بصمت — فمهمة cron معطَّلة هي السبب الأول لانتهاء صلاحية HTTPS في جوف الليل.
راجع صفحة الإصدارات certbot على GitHub للتحقق من الإصدار المتاح قبل كتابة برنامج تعليمي أو سكربت تثبيت.