SSD Nodes Learn
الأدلة Matt Connorبقلم Matt Connor · آخر تحديث في 2026-07-22

شهادات موقّعة ذاتيًا على Ubuntu، بالشكل الصحيح

أنشئ شهادة TLS موقّعة ذاتيًا يقبلها Chrome فعلًا على Ubuntu 24.04: أمر openssl واحد بامتداد SAN صحيح، وربطها بـ nginx أو Apache، والوثوق بها دون curl -k.

ما الذي تبنيه

شهادة TLS موقّعة ذاتيًا (self-signed certificate) يقبلها فعلًا المتصفحات والعملاء الحديثون — بامتداد subjectAltName صحيح، وأذونات مفتاح معقولة، ومربوطة بـ nginx أو Apache — إضافة إلى الجزء الذي يتجاهله كل دليل تقريبًا: تعليم عملائك الوثوق بها بالشكل الصحيح، بدلًا من تجاوز التحذيرات بنقرة والاكتفاء بترسيخ curl -k في السكربتات إلى الأبد. وفي الختام، CA خاصة (جهة إصدار شهادات، Certificate Authority) بخمسة أوامر فقط، ليوم تتحول فيه خدمة داخلية واحدة إلى ست.

أولًا القرار، لأن الشهادة الموقّعة ذاتيًا هي الأداة الصحيحة في حالات أقل بكثير مما تُستخدم فيه فعليًا. إذا كانت الخدمة متاحة من الإنترنت العام تحت اسم DNS حقيقي، فتوقف عن القراءة واحصل بدلًا من ذلك على شهادة Let's Encrypt مجانية عبر certbot على nginx أو ما يعادلها على Apache. فهذا لا يكلّف شيئًا، ويتجدد من تلقاء نفسه، وكل متصفح على وجه الأرض يثق به مسبقًا. أما الشهادة الموقّعة ذاتيًا على موقع عام فتعوّد مستخدميك على تجاوز تحذيرات الأمان بنقرة، وهذه عادة أسوأ من HTTP العادي.

الشهادة الموقّعة ذاتيًا هي الأداة الصحيحة حين لا يكون للإنترنت العام أي دخل في الأمر: لوحة تحكم إدارية مربوطة بـ عنوان نفق WireGuard على خادم VPS الخاص بك، أو جهاز تجريبي (staging) على شبكة خاصة، أو حركة بيانات بين خدمات خلفية لا تمر عبر الإنترنت العام، أو جهاز home-lab، أو استبدال الشهادة الافتراضية التي يولّدها Webmin لنفسه على المنفذ 10000. أصلًا لا يستطيع Let's Encrypt إصدار شهادة لعنوان مثل 10.8.0.1 أو git.internal.lan — فلا توجد أي CA عامة تضع عنوان IP خاصًا أو TLD مُلفَّقًا داخل شهادة. لهذه الأسماء، فأنت الجهة المُصدِرة (CA) نفسها.

كل ما يلي يعمل على جهاز Ubuntu 24.04 جديد، الذي يأتي مزوّدًا بـ OpenSSL 3.0.x (تأكد بالأمر openssl version). لا شيء هنا يحتاج إلى اتصال بالإنترنت؛ كل ذلك يعمل في بيئة معزولة عن الشبكة تمامًا (air-gapped).

لماذا يُنتج أمر السطر الواحد القديم شهادات يرفضها Chrome

الأمر الذي يقدّمه لك كل درس سابق لعام 2017 يبدو هكذا:

# Do not run this — shown so you recognise it in old guides
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout selfsigned.key -out selfsigned.crt

يطرح سلسلة من الأسئلة التفاعلية، ويضع اسم مضيفك في حقل Common Name، وينتج شهادة بلا امتداد subjectAltName. هذه الشهادة ميتة منذ ولادتها. توقف Chrome عن قراءة Common Name في الإصدار 58، في أبريل 2017 — وكانت RFC 2818 قد ألغت اعتماد مطابقة CN منذ عام 2000 أصلًا — ويسلك Firefox وSafari وcurl وPython المسلك نفسه. الشهادة تُعرِّف خادمها عبر امتداد SAN أو لا تُعرِّفه إطلاقًا، والمتصفح يخبرك بذلك بهذه الكلمات بالضبط:

NET::ERR_CERT_COMMON_NAME_INVALID

This server could not prove that it is git.internal.lan; its security
certificate does not specify Subject Alternative Names.

لا يصلح أي قدر من العبث بمخزن الثقة (trust store) هذا الخطأ، لأن الشهادة لا تُسمّي شيئًا فعلًا. إذا كنت تحدّق الآن في NET::ERR_CERT_COMMON_NAME_INVALID، فشهادتك لا تحمل SAN (أو تحمل واحدًا خاطئًا) وعليك توليد شهادة جديدة. لحسن الحظ، الحل أمر واحد فقط.

أصدر شهادة يقبلها المتصفح: أمر واحد

اكتسب OpenSSL الخيار -addext في الإصدار 1.1.1، ما يعني أنك لم تعد بحاجة إلى الألاعيب مع ملفات الإعداد التي كانت الأدلة القديمة تستخدمها لحقن SAN. على Ubuntu 24.04:

sudo openssl req -x509 -newkey rsa:4096 -sha256 -days 730 -noenc \
  -keyout /etc/ssl/private/git.internal.key \
  -out /etc/ssl/certs/git.internal.crt \
  -subj "/CN=git.internal.lan" \
  -addext "subjectAltName=DNS:git.internal.lan,IP:10.8.0.1"

ما الذي يفعله كل خيار:

  • -x509 يصدر شهادة موقّعة ذاتيًا مباشرة بدلًا من طلب توقيع.
  • -newkey rsa:4096 يولّد مفتاحًا جديدًا في الخطوة نفسها. RSA بحجم 4096 لا يضايق أي عميل قديم؛ وإذا كان كل ما سيتصل حديثًا، فإن -newkey ec -pkeyopt ec_paramgen_curve:P-256 أصغر حجمًا وأسرع.
  • -noenc هو الاسم الجديد في OpenSSL 3.x لخيار -nodes القديم: بلا عبارة مرور (passphrase) على المفتاح. كلا الاسمين يعملان. مفتاح محميّ بعبارة مرور يعني أن nginx يتجمّد منتظرًا إدخالًا يدويًا مع كل إقلاع، لذا فانعدام عبارة المرور (أي -noenc) هو ما تريده لمفتاح خادم.
  • -days 730 — سنتان؛ مزيد من التفصيل حول هذا الرقم في قسم انتهاء الصلاحية.
  • -subj يجيب عن الأسئلة التفاعلية مباشرة في السطر. حقل CN شكلي الآن، لكن اضبطه على الاسم الأساسي على أي حال؛ فبعض الأدوات تعرضه.
  • -addext "subjectAltName=..." هو الخيار الحاسم هنا. اذكر كل اسم وكل عنوان IP سيكتبه العملاء: إدخالات DNS: لأسماء المضيفين (الأحرف البديلة (wildcards) مثل DNS:*.internal.lan مقبولة)، وإدخالات IP: للعناوين. إذا كان أحدهم سيتصفح https://10.8.0.1، فيجب أن يكون إدخال IP:10.8.0.1 موجودًا — فـ SAN يقتصر على DNS فقط يعيد له NET::ERR_CERT_COMMON_NAME_INVALID من جديد.

تأكد من أن SAN استقر فعلًا قبل ربط أي شيء:

openssl x509 -in /etc/ssl/certs/git.internal.crt -noout -ext subjectAltName

المخرجات الصحيحة:

X509v3 Subject Alternative Name:
    DNS:git.internal.lan, IP Address:10.8.0.1

إذا طبع بدلًا من ذلك No extensions in certificate، فالشهادة لا تحمل SAN وسترفضها المتصفحات — أعد التوليد بدلًا من المضي قدمًا.

أحكم إغلاق المفتاح

مفتاح خاص يستطيع كل مستخدم على الجهاز قراءته ليس مفتاحًا خاصًا. على Ubuntu، الدليل /etc/ssl/private مضبوط أصلًا على 710 root:ssl-cert، ما يبعد النظرات العابثة، لكن اضبط الملف نفسه صراحة:

sudo chown root:root /etc/ssl/private/git.internal.key
sudo chmod 600 /etc/ssl/private/git.internal.key

يقرأ كل من nginx وApache الشهادات بصلاحيات root قبل أن يتخليا عن امتيازاتهما، لذا فإن root:root بالنمط 600 يناسبهما. أما إذا كان المفتاح لخدمة تعمل بمستخدمها الخاص وتحمّل المفتاح بنفسها — تطبيق Node، أو Gitea، أو برنامج خفي (daemon) بلغة Python — فاستخدم chown لتحويل ملكيته إلى مستخدم تلك الخدمة بدلًا من ذلك، مع الإبقاء على النمط 600. ما لا تفعله أبدًا: النمط 644، أو نسخة في مستودع git، أو نسخة في /tmp.

اربطه بـ nginx

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name git.internal.lan;

    ssl_certificate     /etc/ssl/certs/git.internal.crt;
    ssl_certificate_key /etc/ssl/private/git.internal.key;

    location / {
        proxy_pass http://127.0.0.1:3000;
    }
}
sudo nginx -t && sudo systemctl reload nginx

يجب أن يطبع nginx -t كلًا من syntax is ok وtest is successful قبل أن تفعل إعادة التحميل أي شيء. إذا طبع بدلًا من ذلك SSL_CTX_use_PrivateKey_file() failed ... key values mismatch، فالشهادة والمفتاح من عمليتي توليد مختلفتين — راجع قسم أنماط الفشل.

اربطه بـ Apache

sudo a2enmod ssl proxy proxy_http

ssl وحده لا يكفي هنا: الـ vhost أدناه يستخدم ProxyPass، وبلا mod_proxy وmod_proxy_http يموت اختبار الإعداد برسالة Invalid command 'ProxyPass', perhaps misspelled or defined by a module not included in the server configuration. احفظ الـ vhost باسم /etc/apache2/sites-available/git-internal.conf:

<VirtualHost *:443>
    ServerName git.internal.lan
    SSLEngine on
    SSLCertificateFile      /etc/ssl/certs/git.internal.crt
    SSLCertificateKeyFile   /etc/ssl/private/git.internal.key

    ProxyPass        / http://127.0.0.1:3000/
    ProxyPassReverse / http://127.0.0.1:3000/
</VirtualHost>
sudo a2ensite git-internal
sudo apache2ctl configtest && sudo systemctl reload apache2

يجب أن يجيب configtest بـ Syntax OK. اختبر الآن من جهاز عميل:

curl -v https://git.internal.lan/

وستحصل على خطأ:

curl: (60) SSL certificate problem: self-signed certificate

هذا ليس خللًا. هذا هو TLS يعمل كما ينبغي: curl لم يسمع قط بشهادتك ويرفض التحدث إلى خادم لا يستطيع مصادقته. القسم التالي هو الحل الحقيقي — وهو ليس ما يفعله نصف الإنترنت في هذه اللحظة بالذات.

اجعل العملاء يثقون بها — والأنماط المضادة التي ينبغي رفضها

الحلول الخاطئة أولًا، مُسمّاة على حقيقتها. curl -k (أو --insecure) مُرسَّخ في سكربت، أو verify=False في Python requests، أو NODE_TLS_REJECT_UNAUTHORIZED=0 في Node — لا شيء من هذا يجعل شهادتك موثوقة. فهذه الخيارات تعطّل التحقق من الشهادة، ما يعني أن العميل سيتحدث بارتياح إلى أي خادم يقدّم أي شهادة، بما في ذلك شهادة وضعها مهاجم في المسار. أنت تحتفظ بتكلفة TLS وتخسر المصادقة التي كانت الغاية منه أصلًا. والأسوأ أن هذه الخيارات تتفشى: تُلصق في مهمة cron واحدة، ثم في سكربت نشر، ثم في كود الإنتاج، حتى لا يعود أحد يتذكر أي الاتصالات كان من المفترض أن تبقى مؤقتة. إذا نجا verify=False من جلسة التصحيح التي أنشأته، فالتصميم نفسه خاطئ.

الحل الصحيح هو تعليم كل نظام تشغيل عميل أن هذه الشهادة جذر موثوق (trusted root). على عملاء Ubuntu وDebian:

sudo cp git.internal.crt /usr/local/share/ca-certificates/git.internal.crt
sudo update-ca-certificates

السطر المهم في المخرجات (تتبعه كتلة Running hooks in /etc/ca-certificates/update.d...):

Updating certificates in /etc/ssl/certs...
1 added, 0 removed; done.

يختبئ فخّان في هذه الأسطر. الملف يجب أن ينتهي بـ .crt — امتداد .pem يُتجاهل بصمت وتحصل على 0 added من دون أي رسالة خطأ. والمحتوى يجب أن يكون بصيغة PEM — يبدأ الملف بـ -----BEGIN CERTIFICATE-----؛ حوّل أولًا أي ثنائي DER بالأمر openssl x509 -inform der -in file.der -out file.crt. إضافة الشهادة الموقّعة ذاتيًا نفسها كجذر يعمل لأن الشهادة الموقّعة ذاتيًا هي جذرها الخاص.

بعد ذلك، تثق curl وَwget وَgit وَapt وأي شيء آخر يستخدم OpenSSL مقابل الحزمة النظامية بالخادم دون أي خيارات إطلاقًا. تحمل حفنة من العملاء مخازن ثقة خاصة بها وتحتاج إلى معالجة فردية:

  • Chrome/Chromium على Linux يقرأ قاعدة بيانات NSS، لا مخزن النظام: sudo apt install libnss3-tools، ثم certutil -d sql:$HOME/.pki/nssdb -A -t "C,," -n "git.internal" -i git.internal.crt لكل مستخدم على حدة.
  • Firefox له مخزنه الخاص: Settings → Privacy & Security → Certificates → Import، أو بدّل security.enterprise_roots.enabled إلى true في about:config ليقرأ مخزن النظام.
  • Python requests يأتي بحزمة CA خاصة به (certifi) ويتجاهل مخزن النظام: مرّر verify="/usr/local/share/ca-certificates/git.internal.crt" أو صدّر REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt.
  • Node.js: صدّر NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/git.internal.crt.

على عملاء Windows، انقر نقرًا مزدوجًا على ملف .crt وثبّته في Trusted Root Certification Authorities؛ وعلى macOS، أضفه إلى سلسلة مفاتيح System في Keychain Access وعلّمه بـ Always Trust.

جذر واحد لخدمات عديدة: CA خاصة صغيرة

الثقة على مستوى كل شهادة على حدة تتوقف عن التوسّع فورًا: ستّ خدمات في أربعة أجهزة عميلة يعني أربعًا وعشرين عملية تثبيت ثقة، وكل خدمة جديدة تضيف المزيد. الحل هو CA خاصة — يثق العملاء بجذر واحد، وأنت توقّع شهادة كل خدمة به.

الخيار الودود هو mkcert، الموجود في مستودعات Ubuntu 24.04 والذي يتولى مخازن NSS (Chrome، Firefox) التي لا يغطيها update-ca-certificates:

sudo apt install -y mkcert libnss3-tools
mkcert -install
mkcert git.internal.lan "*.internal.lan" 10.8.0.1

ينشئ mkcert -install جذرًا ويسجّله في كل مخزن ثقة على تلك الآلة؛ ويصدر الأمر الثالث الملفين git.internal.lan+2.pem وَgit.internal.lan+2-key.pem، جاهزَين للإدراج في مقتطفات nginx أو Apache أعلاه. صُمم أصلًا لآلة تطوير — إذ يقيم مفتاح الجذر على أي جهاز نفّذ -install — فهو مثالي لحاسوب مطوّر محمول وغير مناسب لأسطول من الخوادم.

أما للخوادم، فإن OpenSSL وحده يُنجز الـ CA بأكملها في خمسة أوامر:

openssl genrsa -out lab-ca.key 4096
openssl req -x509 -new -key lab-ca.key -sha256 -days 3650 \
  -out lab-ca.crt -subj "/CN=Lab Internal CA" \
  -addext "basicConstraints=critical,CA:TRUE,pathlen:0" \
  -addext "keyUsage=critical,keyCertSign,cRLSign"
openssl genrsa -out git.key 2048
openssl req -new -key git.key -out git.csr -subj "/CN=git.internal.lan" \
  -addext "subjectAltName=DNS:git.internal.lan,IP:10.8.0.1"
openssl x509 -req -in git.csr -CA lab-ca.crt -CAkey lab-ca.key \
  -CAcreateserial -days 730 -sha256 -copy_extensions copy -out git.crt

الفخّ كامن في الأمر الأخير: openssl x509 -req يُسقط كل امتدادات CSR (طلب توقيع الشهادة) افتراضيًا، بما في ذلك SAN الذي أضفته بعناية. الخيار -copy_extensions copy (خيار من OpenSSL 3.x، فيعمل إذًا على 24.04) ينقلها معه؛ أما إغفاله فيجعل الشهادة الموقَّعة بلا SAN، ويستقبلك Chrome برسالة NET::ERR_CERT_COMMON_NAME_INVALID من جديد. تحقق بالفحص نفسه openssl x509 -noout -ext subjectAltName كما سبق.

وزّع lab-ca.crt على العملاء عبر خطوات مخزن الثقة أعلاه — مرة واحدة لكل آلة، إلى الأبد. احرس lab-ca.key كما تحرس أثمن ما تملك الآن: نمط 600، ويُفضَّل أن يبقى على آلة ليست أحد الخوادم التي يوقّع لها، لأن من يملكه يستطيع توليد شهادة لأي اسم سيثق به عملاؤك.

انتهاء الصلاحية والتدوير

آجال شهادات الـ CA العامة تتقلّص باستمرار — فقد حدّد منتدى CA/Browser (CA/Browser Forum) سقف الشهادات العامة الموثوقة المُصدَرة حديثًا بـ 200 يوم في مارس 2026 (بعد أن كانت 398)، لينخفض إلى 100 يوم في 2027 ثم 47 يومًا بحلول مارس 2029 — لكن هذه القواعد تُلزم فقط جهات الـ CA العامة الموثوقة. الـ CA الخاصة بك لا تخضع لها، والمتصفحات لا تفرضها على الجذور المثبَّتة يدويًا. لكن قيدًا واقعيًا واحدًا ينطبق فعلًا: منصات Apple ترفض أي شهادة خادم TLS صالحة لأكثر من 825 يومًا أيًّا كانت الجهة المُصدِرة، فإذا كانت أجهزة iPhone أو Mac ستتصل، أبقِ الشهادات الطرفية (leaf certificates) عند سنتين أو أقل. -days 730 يجتاز هذا الحد في كل مكان؛ وجذر مدته عشر سنوات مع شهادات طرفية مدتها سنتان شكل داخلي مريح.

الشهادات طويلة الأمد تفشل بطريقة واحدة بالضبط: بصمت، دفعة واحدة، في تاريخ لا يتذكر أحد أنه اختاره. تحقق مما لديك:

openssl x509 -in /etc/ssl/certs/git.internal.crt -noout -enddate

ضع التجديد في تقويم فعلي، أو اجعل cron يذكّرك قبل 30 يومًا — openssl x509 -checkend 2592000 -in cert.crt يخرج برمز غير صفري بمجرد أن يصبح انتهاء الصلاحية خلال ذلك العدد من الثواني. وإذا كنت تشغّل بالفعل Uptime Kuma لمراقبة الحالة، فإن مراقبات HTTPS فيه تنبّهك مجانًا لاقتراب انتهاء صلاحية الشهادة.

التدوير مع CA خاصة مملّ بطريقة مريحة: أعد تشغيل أوامر إنشاء CSR والتوقيع، بدّل الملفات، أعد تحميل خادم الويب. الجذر لم يتغيّر، فلا يلاحظ أي عميل شيئًا.

أنماط الفشل، مع النصوص التي ستراها

NET::ERR_CERT_AUTHORITY_INVALID — الحالة المتوقعة قبل أن تُثبّت الثقة، لا عيب في الشهادة. إذا استمرت بعد تثبيت الجذر: على Linux، يقرأ Chrome NSS بدلًا من مخزن النظام (راجع خطوة certutil)؛ أو أن الملف المنسوخ لم ينتهِ بـ .crt وأظهر update-ca-certificates عبارة 0 added؛ أو أن الخادم يقدّم شهادة مختلفة عن تلك التي وثقت بها — قارن البصمات (fingerprints) بالأمر openssl s_client -connect git.internal.lan:443 </dev/null 2>/dev/null | openssl x509 -noout -fingerprint -sha256.

NET::ERR_CERT_COMMON_NAME_INVALID — الشهادة لا تحمل SAN، أو أن SAN لا يغطي الاسم الموجود في شريط العنوان. الحالة الكلاسيكية: يذكر SAN القيمة DNS:git.internal.lan لكن المستخدم تصفّح https://10.8.0.1. تغييرات مخزن الثقة لا تصلح هذه الحالة؛ أعد الإصدار مع الإدخال الناقص.

curl: (60) SSL certificate problem: self-signed certificate — curl لا يثق بالشهادة. المتغيّر self-signed certificate in certificate chain يعني الشيء نفسه لشهادة موقّعة بواسطة CA الخاصة بك. حل لمرة واحدة: curl --cacert lab-ca.crt https://...؛ الحل الدائم: مخزن الثقة. وليس -k.

unable to load certificate ... Expecting: TRUSTED CERTIFICATE (أو Expecting: CERTIFICATE REQUEST، أو no start line) — خلط بين صيغ PEM. لقّمت OpenSSL النوع الخاطئ من الملفات: مفتاحًا أو CSR حيث كان يتوقع شهادة، أو ثنائي DER حيث كان يتوقع PEM. الأمر head -1 filename يخبرك بما لديك فعلًا — الشهادة تبدأ بـ -----BEGIN CERTIFICATE-----. أما DER، فحوّله بالأمر openssl x509 -inform der -in file.der -out file.crt.

nginx: [emerg] SSL_CTX_use_PrivateKey_file(...) failed (SSL: error ... key values mismatch) — الشهادة والمفتاح لا ينتميان معًا، غالبًا لأن أمر التوليد نُفّذ مرتين واختلطت الملفات. تأكد بمقارنة openssl x509 -in git.internal.crt -noout -pubkey | sha256sum مقابل openssl pkey -in git.internal.key -pubout | sha256sum؛ تطابق البصمتين (hashes) يعني زوجًا متطابقًا. إذا اختلفتا، أعد توليد الاثنين معًا.

FAQ

لماذا يقول Chrome ما زال "غير آمن" بعد أن أنشأت شهادة موقّعة ذاتيًا؟

إذا كان الخطأ NET::ERR_CERT_AUTHORITY_INVALID، فالشهادة سليمة — لا يملك Chrome ببساطة أي سبب للوثوق بها بعد. ثبّتها (أو جذر CA الخاصة بك) في مخزن ثقة العميل، وتذكّر أن Chrome على Linux يستخدم قاعدة بيانات NSS عبر certutil، لا مخزن النظام. إذا كان الخطأ NET::ERR_CERT_COMMON_NAME_INVALID، فالشهادة تفتقر إلى Subject Alternative Name يطابق الرابط ويجب إعادة إصدارها بالخيار -addext "subjectAltName=...".

كيف أجعل curl يثق بشهادة موقّعة ذاتيًا دون -k؟

انسخ الشهادة (بصيغة PEM، وامتداد .crt) إلى /usr/local/share/ca-certificates/ ونفّذ sudo update-ca-certificates — يجب أن تقول المخرجات 1 added. من تلك اللحظة يتحقق curl منها مثل أي شهادة عامة. لطلب واحد دون المساس بالنظام، يتحقق curl --cacert /path/to/cert.crt مقابل ذلك الملف وحده؛ أما -k فيعطّل التحقق كليًا ولا مكان له في سكربتات أي أحد.

إلى متى يمكن أن تبقى الشهادة الموقّعة ذاتيًا صالحة؟

من الناحية التقنية، طالما شئت — فحدود منتدى CA/Browser (200 يوم الآن، و47 بحلول 2029) تُلزم جهات الـ CA العامة الموثوقة، لا الثقة الخاصة. عمليًا، اجعل سقف شهادات الخادم 825 يومًا، لأن أجهزة Apple ترفض ما هو أطول من ذلك بغض النظر عن الجهة المُصدِرة. جذر خاص عمره عشر سنوات مع شهادات طرفية عمرها سنتان (-days 730) قيمة افتراضية معقولة؛ فقط ضع التجديد في تقويمك، لأن شهادة داخلية منتهية الصلاحية تُسقط كل شيء بصمت في تاريخ لا يتذكره أحد.

هل أستخدم شهادة موقّعة ذاتيًا أم Let's Encrypt؟

إذا كانت الخدمة تحمل اسم DNS عامًا ويمكن الوصول إليها من الإنترنت، فاستخدم Let's Encrypt دائمًا — مجاني، وتلقائي، وموثوق مسبقًا لدى كل عميل. الشهادة الموقّعة ذاتيًا (أو CA خاصة) مخصصة لما لا يستطيع Let's Encrypt إصداره: عناوين IP خاصة، وأسماء مضيفين داخلية فقط مثل .lan، وشبكات معزولة (air-gapped)، وخدمات مخبّأة عمدًا خلف VPN. القرار يتعلق بإمكانية الوصول والتسمية، لا بقوة الأمان — فالتشفير نفسه مطابق تمامًا في الحالتين.

لماذا تُرفض شهادتي حتى بعد إضافتها إلى /usr/local/share/ca-certificates؟

تحقق من ثلاثة أمور. يجب أن ينتهي الملف بـ .crt — فامتداد .pem يُتخطى بصمت ويبلّغ update-ca-certificates عن 0 added. ويجب أن يكون المحتوى نص PEM يبدأ بـ -----BEGIN CERTIFICATE-----، لا ثنائي DER. ويجب أن يستخدم التطبيق فعلًا مخزن النظام — إذ يحتفظ كل من Chrome على Linux وFirefox وPython requests وNode.js وJava بمخزن ثقة خاص به ويحتاج إلى إضافة الشهادة إليه على حدة.

#openssl#tls#self-signed#ubuntu#أمان