تثبيت Certbot لـ nginx على Ubuntu 24.04
نفّذ sudo apt install certbot python3-certbot-nginx ثم شغّل certbot --nginx مرة واحدة. تعرّف أيضاً على فرق apt وsnap ومهلة تجديد المنفذ 80.
تثبيت Certbot: apt أو snap
في Ubuntu 24.04، يوفّر لك sudo apt install certbot python3-certbot-nginx إصدار Certbot جاهزاً لإصدار شهادات Let's Encrypt حقيقية وموثوقة علناً. تشير وثائق Certbot الأصلية إلى استخدام snap بدلاً منه. الفرق محدود: يتابع snap إصدارات المنبع، بينما يتابع حزمة الأرشيف الإصدار الذي جاء مع LTS ويحصل على إصلاحات الأمان.
اختر أحد الخيارين. وجود نسختين من Certbot يعني وجود مؤقتي تجديد يستهدفان شجرة /etc/letsencrypt نفسها. وستكون النسخة التي نسيت وجودها هي التي تفاجئك.
مسار apt:
sudo apt update
sudo apt install certbot python3-certbot-nginxيثبّت ذلك /usr/bin/certbot، وملحق nginx، وزوج certbot.service + certbot.timer، وإدخال /etc/cron.d/certbot لا ينفّذ أي إجراء عند استخدام systemd.
مسار snap:
sudo apt remove certbot python3-certbot-nginx
sudo snap install core && sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbotيأتي snap بمؤقته الخاص، snap.certbot.renew.timer. أزل حزمة apt قبل تثبيت snap.
يعمل التثبيتان بالطريقة نفسها بعد ذلك. يستخدم Certbot 2.x مفاتيح ECDSA (P-256) افتراضياً. مرّر --key-type rsa فقط إذا كان العميل لا يدعم ECDSA. توجد كل الحالة ضمن /etc/letsencrypt: يحتوي archive/ على ملفات المفاتيح والشهادات الفعلية، ويرتبط live/ رمزياً بالملفات الحالية، ويحتوي renewal/ على ملف إعداد لكل شهادة، ويحتوي accounts/ على مفتاح حساب ACME.
ما الذي يفعله HTTP-01 فعلياً، ولماذا لا يمكن الاستغناء عن المنفذ 80
تعمل عملية التحقق HTTP-01 بصفتها استدعاءً عكسياً. تطلب من Let's Encrypt شهادة تغطي example.com؛ فيحلّ اسم النطاق عبر DNS العام، ويفتح اتصالاً بالعنوان الذي يعثر عليه على المنفذ 80، ثم يطلب http://example.com/.well-known/acme-challenge/<token>. يجيب خادمك بمحتوى الرمز المميز نفسه الذي كتبه Certbot للتو على القرص. هذه هي الآلية كاملة. وتنتج عنها 3 تبعات تفسّر معظم حالات فشل إصدار الشهادات.
- يجب أن يكون المنفذ 80 قابلاً للوصول من الإنترنت العام، وليس من حاسوبك المحمول فقط. تؤدي قاعدة
ufw، أو مجموعة أمان لدى مزود سحابي، أو جدار ناري في وحدة تحكم VPS يفتح المنفذ 443 فقط، إلى فشل الإصدار وكل عملية تجديد لاحقة. - يجب أن يشير DNS إلى هذا الخادم مسبقاً. يجري خادم التحقق عملية البحث بنفسه من خارج الشبكة؛ ولا قيمة لسجلات
/etc/hostsلديك أو لذاكرة التخزين المؤقت في المتصفح بالنسبة إليه. - إذا نشرت سجل AAAA، فستتم محاولة الاتصال عبر IPv6 أولاً. تعيد Let's Encrypt المحاولة عبر IPv4 إذا فشل اتصال IPv6 فشلاً تاماً، لكن وجود سجل AAAA قديماً يشير إلى مضيف يقبل الاتصال ويقدم محتوى آخر يؤدي إلى فشل نهائي.
يُسمح بإعادة التوجيه: تتبع عملية التحقق إعادة توجيه HTTP إلى HTTPS، ولا يهمها أن تكون الشهادة في الطرف الآخر مفقودة أو منتهية الصلاحية أو موقعة ذاتياً. لكنها لن تبدأ من أي منفذ غير المنفذ 80. لا يوفّر Certbot تطبيقاً لآلية TLS-ALPN-01، لذلك فإن عبارة «استخدم 443 فقط» ليست حلاً بديلاً.
اختيار أداة المصادقة: --nginx و--webroot و--standalone
--nginx هو الخيار الافتراضي المناسب عندما يكون nginx قيد التشغيل ويخدم النطاق بالفعل. يحلل Certbot إعداداتك، ويضيف مؤقتاً موقع التحقق، ثم يعيد تحميل nginx ويتحقق من النطاق، وبعد ذلك يكتب توجيهات TLS داخل كتلة الخادم لديك. لا يحدث توقف للخدمة.
sudo certbot --nginx -d example.com -d www.example.comمناسب للبرمجة النصية على خادم جديد:
sudo certbot --nginx \
-d example.com -d www.example.com \
--agree-tos -m ops@example.com --no-eff-email \
--redirect --non-interactive--webroot مناسب عندما تريد إبقاء Certbot بعيداً تماماً عن إعدادات nginx، سواء كنت تنشئها من قالب، أو تحتفظ بها في git، أو تنشرها باستخدام Ansible. يكتب Certbot ملف التحقق فقط داخل مجلد تقدمه للخدمة مسبقاً.
sudo certbot certonly --webroot -w /var/www/example.com \
-d example.com -d www.example.com \
--deploy-hook "systemctl reload nginx"--standalone مناسب عندما لا توجد خدمة تستمع على المنفذ 80، مثل خادم بريد، أو واجهة API لا تستخدم إلا 443، أو نص يعمل عند الإقلاع الأول قبل وجود nginx. يربط Certbot المنفذ 80 بنفسه لبضع ثوانٍ. إذا كان nginx قيد التشغيل، تفشل العملية. أوقفه أثناء التنفيذ:
sudo certbot certonly --standalone -d mail.example.com \
--pre-hook "systemctl stop nginx" \
--post-hook "systemctl start nginx"تُسجَّل هذه الخطافات في إعدادات تجديد الشهادة، لذلك يحدث الإيقاف والتشغيل نفسهما تلقائياً عند التجديد.
كتلة خادم تعمل قبل وجود الشهادة وبعده
مشكلة الدجاجة والبيضة هنا هي أن nginx يرفض البدء عندما يشير ssl_certificate إلى ملف غير موجود، ولا يستطيع Certbot إجراء التحقق أثناء توقف nginx. شغّل الموقع أولاً على المنفذ 80.
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
root /var/www/example.com;
index index.html;
location ^~ /.well-known/acme-challenge/ {
root /var/www/example.com;
default_type "text/plain";
try_files $uri =404;
}
location / {
try_files $uri $uri/ =404;
}
}شغّل sudo nginx -t && sudo systemctl reload nginx، وتأكد من أن curl -I http://example.com/ يستجيب من خارج الخادم، ثم أصدر الشهادة. بعد ذلك:
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
location ^~ /.well-known/acme-challenge/ {
root /var/www/example.com;
default_type "text/plain";
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
root /var/www/example.com;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}تثبت بادئة ^~ في موقع ACME فائدتها لأنها تمنع كتلة return 301 من ابتلاع طلب التحقق. ويضمن إبقاء هذا الموقع على المنفذ 80 استمرار عمل عمليات التجديد بعد جعل بقية الموقع متاحاً عبر HTTPS فقط.
تخدم الكتلتان أعلاه الملفات من القرص. إذا كان nginx يضع نفسه أمام تطبيق بدلاً من ذلك، تصبح location / كتلة proxy_pass، ويشرح قسم كتلة خادم reverse proxy سطراً بسطر الرؤوس التي يحتاج إليها التطبيق، بينما يبقى موقع ACME وتوجيهات TLS كما هما تماماً.
تعتمد صيغة HTTP/2 على إصدار nginx الذي تستخدمه، ويؤدي الخلط بين الصيغتين إلى خطأ عند بدء التشغيل. يأتي Ubuntu 24.04 مع nginx 1.24، الذي يتطلب الصيغة المضمّنة، listen 443 ssl http2;. ويأتي Debian 13 مع إصدار أحدث من nginx، الذي يتطلب توجيه http2 on; مستقلاً. تحقّق من nginx -v أولاً.
وجّه nginx إلى live/، وليس إلى archive/. يُعاد توجيه الروابط الرمزية live/ في كل عملية تجديد؛ أما استخدام مسار ثابت داخل archive/ فيربطك بشهادة تنتهي صلاحيتها دون أن تستبدلها.
تعني Wildcards استخدام DNS-01، ويعني DNS-01 استخدام plugin
لا يمكن التحقق من شهادة wildcard (*.example.com) عبر HTTP-01، لأنه لا يوجد اسم مضيف واحد لجلب ملف منه. المسار الوحيد هو DNS-01: تثبت أنك تتحكم في النطاق من خلال نشر سجل _acme-challenge.example.com TXT. يحتاج Certbot إلى بيانات اعتماد API لدى موفر DNS لتنفيذ ذلك تلقائياً، وهذا هو سبب وجود provider plugins. يشرح الدليل الكامل لشهادة wildcard آلية سجل TXT ومشكلة التجديد في الوضع اليدوي؛ وتأتي بعده نسخة Cloudflare المختصرة.
sudo snap set certbot trust-plugin-with-root=ok
sudo snap install certbot-dns-cloudflareفي مسار apt، يكون الأمر sudo apt install python3-certbot-dns-cloudflare بدلاً من ذلك. ضع بيانات الاعتماد في ملف لا يقرأه إلا root:
# /root/.secrets/cloudflare.ini
# then: sudo chmod 600 /root/.secrets/cloudflare.ini
dns_cloudflare_api_token = your_scoped_token_hereقيّد الرمز المميز بحقوق تعديل DNS في تلك المنطقة وحدها. هذا مفتاح لخدمة DNS لديك؛ فتعامل معه على هذا الأساس.
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /root/.secrets/cloudflare.ini \
-d example.com -d '*.example.com'ضع wildcard بين علامتي اقتباس حتى لا يوسّعه shell وفق نمط glob. يحل DNS-01 أيضاً مشكلة لا يستطيع HTTP-01 حلها: إصدار شهادات لمضيفين بلا منفذ عام 80، أو لخدمة داخلية، أو لجهاز لا يمكن الوصول إليه إلا عبر WireGuard VPN مستضاف ذاتياً على VPS، أو للوحة إدارة على واجهة خاصة.
التجديد: مدة 90 يوماً، والمؤقت، وخطاف النشر
تكون شهادات Let's Encrypt صالحة لمدة 90 يوماً. يجدّد Certbot الشهادة عندما يتبقى أقل من 30 يوماً على انتهائها. يمنحك ذلك نافذة مدتها 30 يوماً يمكن خلالها معالجة فشل التجديد قبل أن يتحول إلى انقطاع. لم تعد Let's Encrypt ترسل رسائل بريد إلكتروني تحذّر من انتهاء الصلاحية. لن ينبهك أحد إلى ذلك، لذلك أصبحت مسؤولية المراقبة عليك.
تحقق من المؤقت الذي ثبّته البرنامج:
systemctl list-timers 'certbot*' 'snap.certbot*'
sudo certbot certificatesيفحص certbot renew كل إعدادات التهيئة في /etc/letsencrypt/renewal/، ويتجاوز أي إعداد يقع خارج نافذة 30 يوماً، ويجدّد الباقي باستخدام العلامات نفسها التي استُخدمت في التشغيل الأصلي. لذلك يهم التشغيل الأول: فهو الذي تُسجَّل إعداداته.
يؤدي تجديد الملف الموجود على القرص وحده إلى تغيير الشهادة على القرص فقط. يواصل nginx تقديم الشهادة القديمة الموجودة في الذاكرة إلى أن يُطلب منه إعادة التحميل. أضف خطاف نشر مرة واحدة:
sudo tee /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh >/dev/null <<'EOF'
#!/bin/sh
set -e
nginx -t && systemctl reload nginx
EOF
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.shيُشغَّل أي ملف قابل للتنفيذ في renewal-hooks/deploy/ بعد أي تجديد ناجح. تؤدي العلامة --deploy-hook المهمة نفسها لشهادة واحدة، وتخزّن renew_hook = ... في إعدادات تجديدها. ينفّذ certbot --nginx إعادة التحميل نيابةً عنك، أما إعدادا --webroot و--standalone فلا يفعلان ذلك. غياب الخطاف هو السبب الدقيق في أن موقعاً ما يقدّم شهادة منتهية الصلاحية بينما يعرض certbot certificates، بكل بساطة، شهادة جديدة. وأي برنامج آخر يقرأ الشهادة عند بدء التشغيل يحتاج إلى الخطاف نفسه. ويحتاج تطبيق يعمل داخل حاوية، مثل تثبيت Nextcloud VPS باستخدام Docker وTLS والنسخ الاحتياطية، إلى إضافة خطوة إعادة تشغيل أو إعادة تحميل خاصة به هنا أيضاً.
اختبار التجديد فعلياً
sudo certbot renew --dry-runينفّذ ذلك التحدي الكامل باستخدام بيئة Let's Encrypt التجريبية: مسار الشيفرة نفسه، والجدار الناري نفسه، وDNS نفسه، من دون استهلاك حد المعدل، ومن دون كتابة أي شيء على القرص. إذا نجح الاختبار اليوم، فسينجح التجديد التلقائي بعد 60 يوماً أيضاً، ما دام لا يتغير أي شيء في الخادم يعتمد عليه هذا الإجراء.
لا يثبت الاختبار الجاف أن hook إعادة التحميل سيُنفَّذ، لأن السلوك يختلف باختلاف إصدار Certbot. اختبر هذا الجزء يدوياً: نفّذ script الخاص بالـhook مباشرة، وتأكد من نجاح systemctl reload nginx، ثم افحص sudo grep renew_hook /etc/letsencrypt/renewal/example.com.conf.
الأخطاء التي ستواجهها فعلياً
Could not bind to IPv4 or IPv6.، و--standalone بينما يحتفظ nginx بالمنفذ 80. استخدم --nginx أو --webroot، أو أوقف nginx أثناء التشغيل. تأكد من العملية التي تملك المنفذ باستخدام sudo ss -lntp | grep ':80'.
Timeout during connect (likely firewall problem)، تعذّر على Let's Encrypt الوصول إلى المنفذ 80. تحقّق بالتدرّج من الخارج إلى الداخل: sudo ufw status، وافتحه باستخدام sudo ufw allow 'Nginx Full'، ثم جدار الحماية الخاص بمزوّد VPS، ثم DNS. اختبر من مكان ليس خادمك: curl -sSv http://example.com/.well-known/acme-challenge/test. قد ينتج سجل AAAA قديم الرسالة نفسها.
unauthorized :: Invalid response from http://example.com/.well-known/acme-challenge/xyz: 404، يمكن الوصول إلى المنفذ 80، لكن لا تتم خدمة الرمز. وصل الطلب إلى server block مختلف؛ تحقّق من الذي يملك default_server، أو أن الدليل المُمرَّر إلى -w ليس الدليل الذي يخدمه nginx. أنشئ ملفاً في /var/www/example.com/.well-known/acme-challenge/test واجلبه من الخارج. إذا أعاد 404، فالشهادة لم تكن المشكلة قط.
DNS problem: NXDOMAIN looking up A for example.com، لا يُحلّ الاسم بشكل علني. قد تكون السجلات الجديدة لم تنتشر بعد، أو قد يكون السجل موجوداً في منطقة لا يخدمها المسجّل.
too many certificates already issued for: example.com، هذا حدّ للمعدل، وهو الحد الذي يصطدم به المستخدمون أثناء التصحيح في حلقة متكررة. تفرض Let's Encrypt حداً أقصى قدره خمس شهادات مكررة أسبوعياً للمجموعة نفسها تماماً من الأسماء، كما تسمح بشكل منفصل بإصدار 50 شهادة جديدة لكل نطاق مسجّل أسبوعياً. لا يُرفع أي من الحدين إلا بمرور الوقت. نفّذ التصحيح مقابل staging باستخدام --dry-run.
nginx: [emerg] cannot load certificate "/etc/letsencrypt/live/example.com/fullchain.pem": No such file or directory، إعداد nginx يشير إلى شهادة لم تُصدر قط، أو إلى شهادة أزيلت باستخدام certbot delete. علّق server block الخاص بـTLS، ثم شغّل nginx وأصدر الشهادة، وبعد ذلك أعد server block.
open() "/etc/letsencrypt/options-ssl-nginx.conf" failed، يصل هذا الملف مع حزمة إضافة nginx. على خادم certonly لا يحتوي على python3-certbot-nginx، أضف الإضافة أو استبدل السطر include بإعدادات ssl_protocols وssl_ciphers الخاصة بك.
إدارة ذلك على نطاق واسع
يمكن لشهادة واحدة أن تتضمن ما يصل إلى 100 اسم، ويبدو استخدام certbot --nginx -d a.example.com -d b.example.com ... واحداً مغرياً، إلى أن يتسبب سجل DNS قديم واحد في فشل التحقق، فيؤدي ذلك إلى تعطيل جميع الأسماء الأخرى الموجودة على الشهادة نفسها. أما الشهادات المنفصلة لكل موقع فتفشل بشكل مستقل، وهذا هو المطلوب على خادم يستضيف أكثر من خدمتين. بعد تجاوز عدد قليل من المواقع، يصبح استخدام واجهة أمامية تدعم ACME مفيداً: إذ يطلب Reverse Proxy من Traefik يشغّل عدة تطبيقات باستخدام Docker Compose الشهادات ويجددها بنفسه، ويخرج Certbot من العملية تماماً. اختيار الـproxy المناسب لهذه الواجهة قرار مستقل، وتحديد الاختيار بين Nginx وCaddy وTraefik يعتمد أساساً على مقدار أعمال الشهادات وإعدادات كل تطبيق التي تريد أن يتولاها الـproxy بدلاً منك.
أنشئ نسخة احتياطية من /etc/letsencrypt بالكامل، مع الحفاظ على sudo tar -czf letsencrypt-$(date +%F).tar.gz -C /etc letsencrypt والروابط الرمزية. يحتوي هذا الشجر على accounts/، وهو مفتاح حساب ACME الذي لا يمكنك إعادة إنشائه مطابقاً للأصل. عند الانتقال إلى VPS جديد، تصبح العملية كالتالي: استخدم rsync لنسخ الشجر مع -a، وثبّت Certbot، وغيّر توجيه DNS، ثم شغّل certbot renew --dry-run قبل نقل الخدمة.
إذا أعدت بناء الخادم أو انتقلت إلى إصدار LTS جديد، فلن ينتقل مؤقت التجديد معك. بعد أي ترحيل أو استعادة من snapshot أو ترقية للتوزيعة، شغّل systemctl list-timers 'certbot*' ونفّذ --dry-run مرة واحدة. يؤدي تجاوز ذلك إلى توقف موقع عن العمل بعد 89 يوماً، عند الساعة 3am، بسبب شهادة افترض الجميع أنها ستتجدد تلقائياً.
يفترض كل ما سبق أنك تتحكم في الجهاز، وأن لديه عنوان IP عاماً والمنفذ 80 مفتوحاً للعالم، أي أنه VPS. وتبقى الآلية السابقة نفسها على أي جهاز من هذه الأجهزة.
تنطبق خطوات الشهادة نفسها على Apache بدلاً من nginx، وعندما لا تكون الشهادة العامة خياراً متاحاً، فإن الشهادة الموقعة ذاتياً على Ubuntu تغطي الخدمات الداخلية.
FAQ
هل أحتاج إلى فتح المنفذ 80 إذا كان موقعي يقدّم HTTPS فقط؟
نعم، بسبب تحدي HTTP-01. يبدأ Let's Encrypt دائماً طلب التحقق على المنفذ 80، ولا يطبّق Certbot آلية TLS-ALPN-01. لذلك، يحظر جدار ناري يفتح المنفذ 443 فقط الإصدار الأول وكل عملية تجديد تلقائية لاحقة. لا توجد مشكلة في إعادة توجيه الاتصالات من المنفذ 80 إلى HTTPS؛ إذ يتبع التحقق عملية إعادة التوجيه. الطريقة الوحيدة لتجاوز المنفذ 80 بالكامل هي استخدام DNS-01 مع إضافة موفّر الخدمة.
apt أم snap، أي إصدار من Certbot يجب أن أثبّت لـ nginx على Ubuntu 24.04؟
استخدم apt. sudo apt install certbot python3-certbot-nginx يوفّر Certbot 2.9.0 على Ubuntu 24.04، وهو حديث بما يكفي لكل ما يرد في هذا الدليل، ويتلقى تصحيحات الأمان عبر unattended-upgrades، ولا يتطلب snapd. اختر snap فقط إذا كنت تحتاج إلى أحدث إصدار فوراً أو إلى إضافة DNS موزّعة حصرياً بصيغة snap. في كلتا الحالتين، اختر طريقة واحدة فقط: يؤدي التثبيتان إلى مؤقتي تجديد يشيران إلى شجرة /etc/letsencrypt نفسها، وتكون عملية التثبيت المنسية هي التي تسبب المشكلة.
هل يستطيع Certbot إصدار شهادة wildcard لـ nginx؟
فقط عبر DNS-01. لا يملك wildcard مثل *.example.com اسم مضيف واحداً لجلب ملف التحدي منه، لذلك لا يمكن استخدام --nginx أو --webroot أو --standalone. ثبّت الإضافة الخاصة بموفّر DNS لديك، وضع رمز API مقيّداً في ملف بيانات اعتماد لا يستطيع قراءته إلا root، ثم شغّل certbot certonly --dns-cloudflare -d example.com -d '*.example.com'، مع وضع wildcard بين علامتي اقتباس لمنع shell من تفسيره كنمط glob.
لماذا ما زال nginx يقدّم الشهادة القديمة بعد نجاح التجديد؟
يحتفظ nginx بالشهادة في الذاكرة، ولا يكتشف الملف الجديد على القرص حتى يعيد تحميل إعداداته. ينفّذ certbot --nginx عملية إعادة التحميل تلقائياً، لكن عمليات --webroot و--standalone لا تفعل ذلك، لذلك قد تنجح عملية التجديد بينما يظل المتصفح يعرض شهادة توشك على الانتهاء. ضع سكربتاً قابلاً للتنفيذ في /etc/letsencrypt/renewal-hooks/deploy/ يشغّل nginx -t && systemctl reload nginx، وسيُنفَّذ بعد كل عملية تجديد ناجحة.
هل يثبت certbot renew --dry-run أن التجديد سيعمل؟
إلى حد كبير. ينفّذ التحدي الفعلي مقابل بيئة الاختبار، باستخدام جدار الحماية نفسه وDNS نفسه ومسار التعليمات البرمجية نفسه، من دون استهلاك حد المعدل ومن دون كتابة أي شيء على القرص. لذلك، يعني نجاحه أن جانب الشبكة سليم. لكنه لا يثبت بشكل موثوق تنفيذ deploy hook. اختبر ذلك بشكل منفصل: شغّل سكربت الخطاف يدوياً وتحقق من sudo grep renew_hook /etc/letsencrypt/renewal/example.com.conf.