SSD Nodes Learn Hosting plans →
गाइड Matt Connorलेखक: Matt Connor

Ubuntu 24.04 पर self-signed TLS certificate कैसे बनाएं

Ubuntu 24.04 पर Chrome द्वारा स्वीकार्य self-signed TLS certificate बनाने का सही तरीका जानें। SAN के साथ openssl कमांड, nginx कॉन्फ़िगरेशन और बिना -k के ट्रस्ट सेटअप करें।

आप क्या बना रहे हैं

एक self-signed TLS certificate जिसे आधुनिक ब्राउज़र और क्लाइंट वास्तव में स्वीकार करते हैं, सही subjectAltName, उचित key permissions, जिसे nginx या Apache में कॉन्फ़िगर किया गया हो, और वह हिस्सा जिसे लगभग हर गाइड छोड़ देती है: अपने क्लाइंट्स को इसे सही तरीके से trust करवाना, बजाय इसके कि आप बार-बार सुरक्षा चेतावनियों (warnings) को अनदेखा करें और स्क्रिप्ट्स में हमेशा के लिए curl -k को hard-code करें। अंत में, एक पांच-कमांड वाली private CA, जब एक internal service बढ़कर छह हो जाए।

सबसे पहले, निर्णय लें, क्योंकि self-signed certificate का उपयोग उतनी बार नहीं किया जाना चाहिए जितनी बार लोग करते हैं। यदि सेवा सार्वजनिक इंटरनेट से एक वास्तविक DNS नाम के तहत पहुंच योग्य है, तो इसे पढ़ना बंद करें और इसके बजाय nginx पर certbot के साथ एक मुफ्त Let's Encrypt certificate या Apache के लिए समान विकल्प प्राप्त करें। यह मुफ्त है, अपने आप renew होता है, और मुख्यधारा के ब्राउज़र और ऑपरेटिंग सिस्टम पहले से ही इस पर भरोसा करते हैं। सार्वजनिक साइट पर self-signed certificate का उपयोग करना आपके उपयोगकर्ताओं को सुरक्षा चेतावनियों को अनदेखा करने के लिए प्रशिक्षित करता है, जो सादे HTTP से भी बुरी आदत है।

Self-signed तब सही विकल्प है जब सार्वजनिक इंटरनेट का कोई संबंध न हो: जैसे आपके VPS पर WireGuard tunnel address से जुड़ा एक admin panel, एक private network पर staging box, backends के बीच service-to-service traffic, एक home-lab appliance, या उस placeholder certificate को बदलना जिसे Webmin पोर्ट 10000 पर स्वयं जनरेट करता है। Let's Encrypt वैसे भी 10.8.0.1 या git.internal.lan के लिए certificate जारी नहीं कर सकता, कोई भी सार्वजनिक CA किसी private IP या मनगढ़ंत TLD को certificate में नहीं डालेगा। उन नामों के लिए, आप स्वयं CA हैं।

नीचे दी गई हर चीज़ एक नए Ubuntu 24.04 बॉक्स पर चलती है, जिसमें OpenSSL 3.0.x (पुष्टि करने के लिए openssl version) शामिल है। यहाँ किसी भी चीज़ के लिए इंटरनेट एक्सेस की आवश्यकता नहीं है; यह सब air-gapped वातावरण में काम करता है।

पुराना one-liner Chrome द्वारा अस्वीकृत certificates क्यों बनाता है

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

यह आपसे कई इंटरैक्टिव प्रश्न पूछती है, आपके hostname को Common Name फ़ील्ड में डालती है, और एक ऐसा certificate बनाती है जिसमें कोई subjectAltName एक्सटेंशन नहीं होता। वह certificate पूरी तरह से बेकार है। Chrome ने version 58 में, अप्रैल 2017 में, Common Name को पढ़ना बंद कर दिया था। RFC 2818 ने वर्ष 2000 में ही CN मैचिंग को deprecated घोषित कर दिया था, और Firefox तथा Safari भी इसी तरह व्यवहार करते हैं। curl और Python का ssl मॉड्यूल अभी भी Common Name पर वापस (fallback) चला जाता है यदि certificate में कोई SAN न हो, यही कारण है कि बिना SAN वाला certificate एक त्वरित curl टेस्ट पास कर सकता है लेकिन हर ब्राउज़र में विफल हो जाता है। ब्राउज़र के लिए, एक certificate अपने सर्वर की पहचान 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 में कोई भी बदलाव इस त्रुटि को ठीक नहीं कर सकता, क्योंकि certificate वास्तव में किसी भी चीज़ का नाम नहीं बताता है। यदि आप अभी NET::ERR_CERT_COMMON_NAME_INVALID देख रहे हैं, तो आपके certificate में कोई SAN नहीं है (या गलत है) और आपको एक नया certificate बनाना होगा। सौभाग्य से, इसका समाधान केवल एक कमांड है।

ऐसा सर्टिफिकेट बनाएँ जिसे ब्राउज़र स्वीकार करें: एक कमांड

OpenSSL ने 1.1.1 में -addext फ्लैग जोड़ा है, जिसका अर्थ है कि अब आपको 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 उसी चरण में एक नई की (key) बनाता है। RSA 4096 किसी भी पुराने क्लाइंट को प्रभावित नहीं करता; यदि कनेक्ट होने वाले सभी क्लाइंट आधुनिक हैं, तो -newkey ec -pkeyopt ec_paramgen_curve:P-256 छोटा और तेज़ है।
  • -noenc पुराने -nodes का OpenSSL 3.x संस्करण है: की (key) पर कोई पासफ़्रेज़ नहीं। दोनों स्पेलिंग काम करती हैं। पासफ़्रेज़ वाली की का मतलब है कि Nginx हर बूट पर इनपुट के लिए इंतज़ार करेगा, इसलिए सर्वर की के लिए आपको इसकी आवश्यकता है।
  • -days 730, दो वर्ष; उस संख्या के बारे में अधिक जानकारी समाप्ति अनुभाग में दी गई है।
  • -subj इंटरैक्टिव प्रश्नों का उत्तर इनलाइन देता है। CN अब केवल दिखावे के लिए है, लेकिन इसे प्राथमिक नाम पर सेट करें; कुछ उपकरण इसे प्रदर्शित करते हैं।
  • -addext "subjectAltName=..." सबसे महत्वपूर्ण फ्लैग है। उन सभी नामों और सभी IP की सूची बनाएँ जिन्हें क्लाइंट टाइप करेंगे: होस्टनेम के लिए DNS: प्रविष्टियाँ (DNS:*.internal.lan जैसे वाइल्डकार्ड ठीक हैं), पतों के लिए IP: प्रविष्टियाँ। यदि कोई https://10.8.0.1 पर ब्राउज़ करेगा, तो IP:10.8.0.1 प्रविष्टि का होना अनिवार्य है, अन्यथा केवल DNS वाला SAN उन्हें फिर से 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 नहीं है और ब्राउज़र इसे अस्वीकार कर देंगे, आगे बढ़ने के बजाय इसे फिर से बनाएँ।

Key को सुरक्षित करें

यदि किसी सर्वर पर मौजूद private key को कोई भी user पढ़ सकता है, तो वह private key नहीं है। एक standard Ubuntu 24.04 सिस्टम पर, /etc/ssl/private पहले से ही 700 root:root होता है, इसलिए केवल root ही इसे list कर सकता है; यह केवल तब 710 root:ssl-cert बनता है यदि किसी प्रक्रिया ने ssl-cert package को install किया हो (apache2 इसे recommend करता है)। किसी भी स्थिति में, file के permissions को स्पष्ट रूप से सेट करें:

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

nginx और Apache दोनों ही privileges drop करने से पहले root के रूप में certificates को पढ़ते हैं, इसलिए उनके लिए root:root mode 600 काम करता है। यदि key किसी ऐसी service के लिए है जो अपने स्वयं के user के रूप में चलती है और key को खुद load करती है, जैसे कि Node app, Gitea, या Python daemon, तो इसे उस service user को chown करें, और mode 600 ही रखें। जो आपको कभी नहीं करना चाहिए: mode 644 का उपयोग, git repository में copy रखना, या /tmp में copy रखना।

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 को reload करने से पहले syntax is ok और test is successful प्रिंट करना चाहिए। यदि इसके बजाय SSL_CTX_use_PrivateKey_file() failed ... key values mismatch प्रिंट होता है, तो इसका मतलब है कि certificate और key दो अलग-अलग generation runs से हैं, इसके लिए failure-modes सेक्शन देखें।

इसे 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 आपके सर्टिफिकेट के बारे में नहीं जानता है और ऐसे सर्वर से बात करने से इनकार करता है जिसे वह प्रमाणित नहीं कर सकता। अगला भाग इसका वास्तविक समाधान है, और यह वह नहीं है जो इस समय इंटरनेट का आधा हिस्सा कर रहा है।

Clients को इस पर भरोसा दिलाना, और वे anti-patterns जिन्हें अस्वीकार करना चाहिए

सबसे पहले गलत समाधान, और वे क्या हैं। स्क्रिप्ट में curl -k (या --insecure) डालना, Python requests में verify=False, या Node में NODE_TLS_REJECT_UNAUTHORIZED=0, इनमें से कोई भी आपके certificate को विश्वसनीय नहीं बनाता है। ये certificate verification को बंद कर देते हैं, जिसका अर्थ है कि client खुशी-खुशी किसी भी ऐसे server से बात करेगा जो कोई भी certificate प्रस्तुत करता है, जिसमें वह भी शामिल है जिसे किसी attacker ने बीच में रखा हो। आप TLS का overhead तो बनाए रखते हैं, लेकिन वह authentication खो देते हैं जो इसका मुख्य उद्देश्य था। इससे भी बुरा यह है कि ये flags फैल जाते हैं: एक cron job में paste किए गए, फिर एक deploy script में, और फिर production code में, जब तक कि किसी को याद न रहे कि कौन से connections अस्थायी होने चाहिए थे। यदि कोई verify=False उस debugging session के बाद भी रह जाता है जिसने इसे जन्म दिया, तो design गलत है।

सही समाधान यह है कि प्रत्येक client OS को यह सिखाया जाए कि यह certificate एक trusted root है। Ubuntu और Debian clients पर:

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... block आता है):

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

उन लाइनों में दो समस्याएं छिपी हैं। फ़ाइल का अंत .crt पर होना ही चाहिए, .pem extension को चुपचाप अनदेखा कर दिया जाता है और आपको बिना किसी error message के 0 added मिलता है। और सामग्री PEM होनी चाहिए, फ़ाइल -----BEGIN CERTIFICATE----- से शुरू होती है; DER binary को पहले openssl x509 -inform der -in file.der -out file.crt के साथ convert करें। self-signed certificate को ही root के रूप में जोड़ना काम करता है क्योंकि एक self-signed certificate स्वयं का root होता है।

उसके बाद, curl, wget, git, apt, और OpenSSL का उपयोग करके system bundle के विरुद्ध चलने वाली कोई भी चीज़ बिना किसी flag के server पर भरोसा करती है। कुछ clients अपने स्वयं के trust stores रखते हैं और उन्हें अलग से संभालने की आवश्यकता होती है:

  • Linux पर Chrome/Chromium एक NSS database पढ़ता है, system store नहीं: sudo apt install libnss3-tools, फिर प्रति user certutil -d sql:$HOME/.local/share/pki/nssdb -A -t "C,," -n "git.internal" -i git.internal.crt। वह path version 146 के बाद से Chrome का default है; यदि user के पास पुराने install से कोई legacy ~/.pki/nssdb है, तो Chrome उसे ही पढ़ता रहेगा, इसलिए उन मशीनों पर -d को sql:$HOME/.pki/nssdb पर point करें।
  • Firefox का अपना store होता है: Settings → Privacy & Security → Certificates → Import। Windows और macOS पर आप इसके बजाय about:config में security.enterprise_roots.enabled को true पर सेट कर सकते हैं ताकि यह OS store को पढ़ सके; Mozilla उस pref को Windows और macOS के लिए document करता है, Linux के लिए नहीं, इसलिए Ubuntu पर import का उपयोग करें।
  • Python requests अपना स्वयं का CA bundle (certifi) साथ लाता है और system store को अनदेखा करता है: verify="/usr/local/share/ca-certificates/git.internal.crt" पास करें या REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt export करें।
  • Node.js डिफ़ॉल्ट रूप से अपने स्वयं के bundled roots का उपयोग करता है: NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/git.internal.crt export करें, या इसे उस system store को पढ़ने के लिए कहें जिसे आपने अभी --use-system-ca flag (Linux पर Node 23.9 और बाद के संस्करण) या NODE_USE_SYSTEM_CA=1 (Node 24.6 और 22.19 और बाद के संस्करण) के साथ update किया है।

Windows clients पर, .crt पर double-click करें और इसे Trusted Root Certification Authorities में install करें; macOS पर, इसे Keychain Access में System keychain में जोड़ें और इसे Always Trust के रूप में चिह्नित करें।

कई सेवाओं के लिए एक root: एक छोटा private CA

प्रति-certificate trust का पैमाना तुरंत छोटा पड़ जाता है: छह सेवाएँ और चार client मशीनें होने पर चौबीस trust installs की आवश्यकता होती है, और हर नई सेवा के साथ यह संख्या बढ़ती जाती है। इसका समाधान एक private CA है, जहाँ clients केवल एक root पर भरोसा करते हैं और आप प्रत्येक सेवा के certificate को उसी से sign करते हैं।

सबसे सरल विकल्प mkcert है, जो Ubuntu 24.04 repos में उपलब्ध है और उन NSS stores (Firefox, और नीचे दी गई एक शर्त के साथ Chrome) को संभालता है जिन्हें update-ca-certificates नहीं देख पाता:

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

mkcert -install एक root बनाता है और उसे system store में रजिस्टर करता है। यह उन browser NSS stores में भी रजिस्टर करता है जिन्हें यह ढूँढ सकता है, और यदि JAVA_HOME सेट हो तो Java के store में भी। Node system store को तब तक नहीं पढ़ता जब तक उसे निर्देश न दिया जाए, इसलिए Node apps को ऊपर बताए अनुसार --use-system-ca (या NODE_USE_SYSTEM_CA=1) के साथ शुरू करें, या NODE_EXTRA_CA_CERTS="$(mkcert -CAROOT)/rootCA.pem" को export करें। तीसरा command git.internal.lan+2.pem और git.internal.lan+2-key.pem जारी करता है, जो ऊपर दिए गए nginx या Apache snippets में उपयोग के लिए तैयार होते हैं। इसका डिज़ाइन एक development मशीन के लिए है, जहाँ root key उस मशीन पर रहती है जिसने -install चलाया है, इसलिए यह dev laptop के लिए तो सही है लेकिन server fleet के लिए उपयुक्त नहीं है।

अक्टूबर 2026 की स्थिति के अनुसार, एक समस्या यह है: mkcert केवल Chrome के NSS database को पुराने ~/.pki/nssdb path पर ढूँढता है, न कि ~/.local/share/pki/nssdb पर, जिसका उपयोग Chrome version 146 के बाद से डिफ़ॉल्ट रूप से कर रहा है। जिस मशीन पर पुराना database नहीं है, वहाँ Chrome के लिए root को स्वयं certutil command का उपयोग करके जोड़ें, जिसमें -i "$(mkcert -CAROOT)/rootCA.pem" का प्रयोग करें।

Servers के लिए, सामान्य OpenSSL पाँच commands में पूरा 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

इसमें मुख्य सावधानी अंतिम command में है: openssl x509 -req डिफ़ॉल्ट रूप से CSR से सभी extensions हटा देता है, जिसमें आपके द्वारा सावधानीपूर्वक जोड़ा गया SAN भी शामिल है। -copy_extensions copy (एक OpenSSL 3.x विकल्प, जो 24.04 पर काम करता है) उन्हें सुरक्षित रखता है; यदि आप इसे छोड़ देंगे, तो signed certificate में कोई SAN नहीं होगा, और Chrome आपको फिर से NET::ERR_CERT_COMMON_NAME_INVALID दिखाएगा। पहले की तरह openssl x509 -noout -ext subjectAltName check के साथ इसकी पुष्टि करें।

lab-ca.crt को ऊपर बताए गए trust-store चरणों के माध्यम से clients में वितरित करें, यह काम प्रति मशीन केवल एक बार करना है। lab-ca.key की सुरक्षा वैसे ही करें जैसे आप सबसे कीमती संपत्ति की करते हैं: mode 600 रखें, और आदर्श रूप से इसे ऐसी मशीन पर रखें जो उन servers में से न हो जिनके लिए यह certificates sign करता है, क्योंकि जिसके पास यह key है, वह किसी भी नाम के लिए certificate बना सकता है जिस पर आपके clients भरोसा करेंगे।

समाप्ति और रोटेशन

Public CA certificate की वैधता अवधि कम होती जा रही है। CA/Browser Forum ने मार्च 2026 में नए जारी किए गए publicly trusted certificates की सीमा 200 दिन (398 दिन से कम) तय की है, जो 2027 में 100 दिन और मार्च 2029 तक 47 दिन हो जाएगी। हालाँकि, ये नियम केवल publicly trusted CAs पर लागू होते हैं। आपका private CA इन नियमों से बंधा नहीं है और browsers manually installed roots के लिए इन्हें लागू नहीं करते हैं। एक वास्तविक सीमा जरूर लागू होती है: Apple platforms किसी भी ऐसे TLS server certificate को अस्वीकार कर देते हैं जो 825 दिनों से अधिक वैध हो, चाहे उसे किसी ने भी जारी किया हो। इसलिए, यदि iPhones या Macs कनेक्ट होंगे, तो leaf certificates को दो साल या उससे कम पर रखें। -days 730 हर जगह इस सीमा को पूरा करता है; दस साल का root और दो साल के leaves एक सुविधाजनक आंतरिक संरचना है।

लंबे समय तक चलने वाले certificates केवल एक ही तरीके से विफल होते हैं: चुपचाप, एक साथ, उस तारीख पर जिसे चुनना किसी को याद नहीं रहता। जाँचें कि आपके पास क्या है:

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

नवीनीकरण (renewal) को वास्तविक कैलेंडर में दर्ज करें, या cron से 30 दिन पहले सूचना प्राप्त करें। यदि समाप्ति की अवधि निर्धारित सेकंड के भीतर हो, तो openssl x509 -checkend 2592000 -in cert.crt non-zero exit code देता है। यदि आप पहले से ही status monitoring के लिए Uptime Kuma चला रहे हैं, तो इसके HTTPS monitors बिना किसी अतिरिक्त शुल्क के certificate की समाप्ति तिथि निकट आने पर चेतावनी दे देते हैं।

Private CA के साथ रोटेशन काफी सरल प्रक्रिया है: CSR-and-sign commands को फिर से चलाएं, फाइलों को बदलें और web server को reload करें। Root में कोई बदलाव नहीं हुआ है, इसलिए किसी भी client को इसका पता नहीं चलता है।

विफलता के प्रकार और दिखाई देने वाले स्ट्रिंग्स

NET::ERR_CERT_AUTHORITY_INVALID, ट्रस्ट इंस्टॉल करने से पहले की अपेक्षित स्थिति है, यह सर्टिफिकेट में कोई खराबी नहीं है। यदि रूट इंस्टॉल करने के बाद भी यह समस्या बनी रहती है, तो इसके कारण ये हो सकते हैं: Linux पर, Chrome सिस्टम स्टोर के बजाय NSS को पढ़ता है (देखें certutil चरण), और Chrome 146 के बाद से वह डेटाबेस ~/.local/share/pki/nssdb पर स्थित होता है, जब तक कि कोई पुराना ~/.pki/nssdb मौजूद न हो, इसलिए दूसरे पाथ पर जोड़ा गया रूट दिखाई नहीं देता; या कॉपी की गई फाइल .crt पर समाप्त नहीं हुई और update-ca-certificates ने 0 added दिखाया; या सर्वर उस सर्टिफिकेट से अलग सर्टिफिकेट प्रस्तुत कर रहा है जिस पर आपने भरोसा किया है, 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 को गलत प्रकार की फाइल दी है: एक की (key) या 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), सर्टिफिकेट और की (key) एक-दूसरे से संबंधित नहीं हैं, आमतौर पर ऐसा इसलिए होता है क्योंकि जनरेशन कमांड दो बार चलाई गई और फाइलें आपस में मिल गईं। openssl x509 -in git.internal.crt -noout -pubkey | sha256sum बनाम openssl pkey -in git.internal.key -pubout | sha256sum के साथ पुष्टि करें; मेल खाते हुए हैश का मतलब है कि वे एक जोड़ा हैं। यदि वे अलग हैं, तो दोनों को एक साथ फिर से जनरेट करें।

FAQ

self-signed certificate बनाने के बाद भी Chrome "Not secure" क्यों दिखाता है?

यदि error NET::ERR_CERT_AUTHORITY_INVALID है, तो certificate सही है, Chrome के पास अभी उस पर भरोसा करने का कोई कारण नहीं है। इसे (या अपने private CA root को) client के trust store में install करें। याद रखें कि Linux पर, Chrome system store के बजाय certutil के माध्यम से NSS database का उपयोग करता है (Chrome 146 के बाद से ~/.local/share/pki/nssdb पर, या यदि कोई मौजूद हो तो legacy ~/.pki/nssdb पर)। यदि error NET::ERR_CERT_COMMON_NAME_INVALID है, तो certificate में URL से मेल खाने वाला Subject Alternative Name नहीं है और इसे -addext "subjectAltName=..." के साथ फिर से जारी किया जाना चाहिए।

मैं -k के बिना curl को self-signed certificate पर भरोसा करने के लिए कैसे कहूँ?

Certificate (PEM format, .crt extension) को /usr/local/share/ca-certificates/ में copy करें और sudo update-ca-certificates चलाएँ, output में 1 added दिखना चाहिए। इसके बाद curl इसे किसी भी public certificate की तरह verify करेगा। system को छुए बिना एक बार के request के लिए, curl --cacert /path/to/cert.crt केवल उस file के आधार पर verify करता है; -k verification को पूरी तरह से disable कर देता है और इसे किसी की भी scripts में इस्तेमाल नहीं करना चाहिए।

एक self-signed certificate कितने समय तक वैध रह सकता है?

तकनीकी रूप से आप जितना चाहें उतना लंबा रख सकते हैं, CA/Browser Forum की सीमाएं (अब 200 दिन, 2029 तक 47 दिन) publicly trusted CAs को बांधती हैं, private trust को नहीं। व्यवहार में, server certificates को 825 दिनों तक सीमित रखें, क्योंकि Apple devices issuer की परवाह किए बिना इससे अधिक लंबी अवधि वाले certificates को अस्वीकार कर देते हैं। दो साल (-days 730) के leaf certificates के साथ दस साल का private root एक उचित default है; बस renewal के लिए calendar में note लगा लें, क्योंकि एक expired internal cert किसी को याद न रहने वाली तारीख पर सब कुछ चुपचाप बंद कर देता है।

क्या मुझे self-signed certificate का उपयोग करना चाहिए या Let's Encrypt का?

यदि service का public DNS नाम है और वह internet से पहुँच योग्य है, तो हमेशा Let's Encrypt का उपयोग करें। यह मुफ्त, स्वचालित है, और अधिकांश browsers और operating systems द्वारा पहले से ही विश्वसनीय है (यदि बहुत पुराने devices को connect करना है तो Let's Encrypt की compatibility list देखें)। Self-signed (या private CA) उन चीजों के लिए है जिन्हें Let's Encrypt जारी नहीं कर सकता: private IPs, केवल internal hostnames जैसे .lan, air-gapped networks, और जानबूझकर VPN के पीछे छिपी services। यह निर्णय पहुँच और नामकरण के बारे में है, सुरक्षा की मजबूती के बारे में नहीं, cryptography दोनों में समान है।

/usr/local/share/ca-certificates में जोड़ने के बाद भी मेरा certificate अस्वीकार क्यों किया जाता है?

तीन चीजों की जाँच करें। File का अंत .crt पर होना चाहिए, .pem extension को चुपचाप छोड़ दिया जाता है और update-ca-certificates, 0 added रिपोर्ट करता है। सामग्री PEM text होनी चाहिए जो -----BEGIN CERTIFICATE----- से शुरू हो, न कि DER binary। और application को वास्तव में system store का उपयोग करना चाहिए; Linux पर Chrome, Firefox, Python requests, Node.js (जब तक कि --use-system-ca के साथ शुरू न किया गया हो), और Java प्रत्येक अपना एक private trust store रखते हैं और उनमें certificate को अलग से जोड़ने की आवश्यकता होती है।