Ubuntu 24.04 پر Chrome کے لیے درست self-signed TLS cert
Ubuntu 24.04 پر SAN کے ساتھ ایک openssl command سے ایسا self-signed TLS certificate بنائیں جسے Chrome قبول کرے، پھر nginx یا Apache میں لگائیں اور curl -k کے بغیر trust کریں۔
آپ کیا تیار کر رہے ہیں
ایک self-signed TLS certificate، جسے جدید browsers اور clients واقعی قبول کرتے ہیں، درست subjectAltName، مناسب key permissions، nginx یا Apache کے ساتھ مربوط configuration، اور وہ حصہ جسے تقریباً ہر guide چھوڑ دیتی ہے: اپنے clients کو اسے درست طور پر trust کروانا، بجائے اس کے کہ warnings کو نظرانداز کرنے کے لیے click کیا جائے اور curl -k کو ہمیشہ کے لیے scripts میں hard-code کر دیا جائے۔ آخر میں، ایک internal service کے بڑھ کر چھ services بن جانے کی صورت میں پانچ commands پر مشتمل private CA بھی شامل ہے۔
پہلے فیصلہ کریں، کیونکہ self-signed certificate اس مقصد کے لیے بہت کم درست انتخاب ہے جتنی کثرت سے اسے استعمال کیا جاتا ہے۔ اگر service حقیقی DNS name کے تحت public internet سے قابل رسائی ہے، تو پڑھنا روک دیں اور nginx پر certbot کے ذریعے مفت Let's Encrypt certificate حاصل کریں یا Apache کے لیے متعلقہ طریقہ استعمال کریں۔ اس کی کوئی لاگت نہیں، یہ خود renew ہوتا ہے، اور دنیا کا ہر browser پہلے ہی اسے trust کرتا ہے۔ کسی public site پر self-signed certificate استعمال کرنے سے آپ کے users کو security warnings نظرانداز کرنے کی عادت پڑتی ہے، جو plain HTTP سے بھی زیادہ خراب عادت ہے۔
Self-signed certificate اس وقت درست انتخاب ہے جب public internet شامل نہ ہو: آپ کے VPS پر WireGuard tunnel address سے منسلک admin panel، private network پر staging box، backends کے درمیان service-to-service traffic، home-lab appliance، یا اس placeholder certificate کی جگہ نیا certificate لگانا جو Webmin port 10000 پر خود بناتا ہے۔ Let's Encrypt 10.8.0.1 یا git.internal.lan کے لیے certificate جاری نہیں کر سکتا؛ کوئی public CA private IP یا فرضی TLD کو certificate میں شامل نہیں کرے گا۔ ان names کے لیے CA آپ خود ہیں۔
ذیل کے تمام مراحل ایک fresh Ubuntu 24.04 box پر چلتے ہیں، جس میں OpenSSL 3.0.x شامل ہے (تصدیق کے لیے openssl version)۔ یہاں internet access کی ضرورت نہیں؛ یہ تمام مراحل air-gapped ماحول میں بھی کام کرتے ہیں۔
پرانا one-liner ایسے سرٹیفکیٹس کیوں بناتا ہے جنہیں Chrome مسترد کر دیتا ہے
ہر pre-2017 tutorial میں دیا جانے والا command کچھ یوں دکھائی دیتا ہے:
# 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یہ interactive سوالات کا ایک سلسلہ پوچھتا ہے، آپ کے hostname کو Common Name field میں رکھتا ہے، اور ایسا certificate بناتا ہے جس میں subjectAltName extension موجود نہیں ہوتی۔ ایسا certificate شروع ہی سے ناقابلِ استعمال ہوتا ہے۔ Chrome نے version 58 میں، April 2017 میں، Common Name پڑھنا بند کر دیا تھا۔ RFC 2818 پہلے ہی year 2000 میں CN matching کو deprecated قرار دے چکا تھا، اور Firefox، Safari، curl، اور Python بھی اسی طرح کام کرتے ہیں۔ Certificate اپنے server کی شناخت SAN extension کے ذریعے کرتا ہے، ورنہ بالکل نہیں کرتا۔ Browser آپ کو یہ بات عین ان الفاظ میں بتاتا ہے:
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 میں تبدیلیاں کرنے سے یہ error درست نہیں ہوتا، کیونکہ certificate میں واقعی کسی نام کی شناخت موجود نہیں ہے۔ اگر آپ اس وقت NET::ERR_CERT_COMMON_NAME_INVALID دیکھ رہے ہیں تو آپ کے certificate میں SAN موجود نہیں ہے، یا SAN غلط ہے، اور آپ کو نیا certificate بنانا ہوگا۔ خوش قسمتی سے اس کا حل ایک command ہے۔
ایسا سرٹیفکیٹ بنائیں جسے براؤزر قبول کریں: ایک کمانڈ
OpenSSL نے 1.1.1 میں -addext flag شامل کیا۔ اس کے بعد SAN شامل کرنے کے لیے پرانی guides میں استعمال ہونے والی config-file کی پیچیدہ ترکیبیں درکار نہیں رہیں۔ 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"ہر flag کا کام:
-x509signing request کے بجائے براہِ راست self-signed certificate بناتا ہے۔-newkey rsa:4096اسی مرحلے میں نئی key بناتا ہے۔ RSA 4096 کسی پرانے client کے لیے مسئلہ نہیں بنتا؛ اگر تمام connecting clients جدید ہوں تو-newkey ec -pkeyopt ec_paramgen_curve:P-256زیادہ چھوٹا اور تیز ہے۔-noencOpenSSL 3.x میں پرانے-nodesکا نام ہے: key پر passphrase نہیں لگائی جاتی۔ دونوں نام کام کرتے ہیں۔ passphrase والی key کی وجہ سے nginx ہر boot پر input کا انتظار کرتے ہوئے رک جاتا ہے، اس لیے server key کے لیے یہ اختیار استعمال کریں۔-days 730دو سال کی مدت مقرر کرتا ہے؛ اس عدد کے بارے میں expiry section میں مزید بتایا گیا ہے۔-subjinteractive سوالات کے جواب inline فراہم کرتا ہے۔ اب CN صرف ظاہری معلومات ہے، لیکن اسے پھر بھی primary name پر set کریں؛ کچھ tools اسے دکھاتے ہیں۔-addext "subjectAltName=..."بنیادی اہمیت رکھنے والا flag ہے۔ ہر وہ name اور ہر وہ IP درج کریں جو clients استعمال کریں گے: hostnames کے لیےDNS:entries (DNS:*.internal.lanجیسے wildcards بھی درست ہیں)، اور addresses کے لیےIP:entries۔ اگر کوئیhttps://10.8.0.1پر browse کرے گا توIP:10.8.0.1entry لازمی موجود ہونی چاہیے؛ صرف DNS والا SAN رکھنے سےNET::ERR_CERT_COMMON_NAME_INVALIDکا مسئلہ دوبارہ پیدا ہو جائے گا۔
کسی بھی configuration کو جوڑنے سے پہلے تصدیق کریں کہ SAN واقعی شامل ہوا ہے:
openssl x509 -in /etc/ssl/certs/git.internal.crt -noout -ext subjectAltNameدرست output:
X509v3 Subject Alternative Name:
DNS:git.internal.lan, IP Address:10.8.0.1اگر اس کے بجائے No extensions in certificate ظاہر ہو تو certificate میں SAN موجود نہیں ہے۔ آگے بڑھنے کے بجائے اسے دوبارہ generate کریں، کیونکہ browsers اسے reject کر دیں گے۔
کلید کو محفوظ کریں
ایسی نجی کلید جسے سسٹم کا ہر صارف پڑھ سکے، نجی کلید نہیں رہتی۔ 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.keynginx اور Apache دونوں مراعات کم کرنے سے پہلے سرٹیفکیٹس کو root کے طور پر پڑھتے ہیں، اس لیے root:root موڈ 600 ان کے لیے کافی ہے۔ اگر کلید ایسی سروس کے لیے ہے جو اپنے الگ صارف کے طور پر چلتی ہے اور خود کلید لوڈ کرتی ہے، مثلاً Node app، Gitea یا Python daemon، تو chown اسے اس سروس کے صارف کو تفویض کریں اور موڈ 600 برقرار رکھیں۔ یہ کام کبھی نہ کریں: موڈ 644 مقرر کرنا، کلید کی نقل git repository میں رکھنا، یا کلید کی نقل /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کسی بھی reload سے پہلے nginx -t کو 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 کے بغیر config test 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 apache2configtest کو Syntax OK کا جواب دینا چاہیے۔ اب کسی client machine سے ٹیسٹ کریں:
curl -v https://git.internal.lan/اور آپ کو ایک خرابی ملے گی:
curl: (60) SSL certificate problem: self-signed certificateیہ کوئی bug نہیں ہے۔ یہ TLS کے درست طور پر کام کرنے کی علامت ہے: curl آپ کے certificate سے واقف نہیں ہے اور ایسے server سے رابطہ کرنے سے انکار کرتا ہے جس کی تصدیق نہیں ہو سکتی۔ اگلا حصہ اصل حل بیان کرتا ہے، اور یہ وہ طریقہ نہیں ہے جو اس وقت آدھی internet استعمال کر رہی ہے۔
کلائنٹس کو اس پر اعتماد کرنے کے قابل بنائیں، اور جن غلط طریقوں سے انکار کرنا چاہیے
سب سے پہلے غلط اصلاحات کو ان کے اصل نام سے بیان کرتے ہیں۔ کسی اسکرپٹ میں curl -k (یا --insecure) شامل کرنا، Python requests میں verify=False استعمال کرنا، یا Node میں NODE_TLS_REJECT_UNAUTHORIZED=0 لگانا، ان میں سے کوئی بھی آپ کے سرٹیفکیٹ کو قابلِ اعتماد نہیں بناتا۔ یہ سرٹیفکیٹ کی تصدیق بند کر دیتے ہیں۔ اس کا مطلب ہے کہ کلائنٹ خوشی سے کسی بھی ایسے سرور سے رابطہ کرے گا جو کوئی بھی سرٹیفکیٹ پیش کرے، حتیٰ کہ ایسا سرٹیفکیٹ بھی جو حملہ آور نے نیٹ ورک کے راستے میں نصب کیا ہو۔ آپ TLS کا اضافی بوجھ برقرار رکھتے ہیں، لیکن وہ تصدیق ختم کر دیتے ہیں جس کے لیے TLS استعمال کیا گیا تھا۔ اس سے بھی بدتر یہ ہے کہ یہ flags پھیلتے جاتے ہیں: پہلے ایک cron job میں paste ہوتے ہیں، پھر deploy script میں، اور آخرکار production code میں، یہاں تک کہ کسی کو یاد نہیں رہتا کہ کون سے connections عارضی ہونے تھے۔ اگر کوئی verify=False اس debugging session کے بعد بھی باقی رہ جائے جس کے دوران اسے شامل کیا گیا تھا، تو ڈیزائن غلط ہے۔
درست حل یہ ہے کہ ہر کلائنٹ OS کو بتایا جائے کہ یہ سرٹیفکیٹ ایک trusted root ہے۔ Ubuntu اور Debian کلائنٹس پر:
sudo cp git.internal.crt /usr/local/share/ca-certificates/git.internal.crt
sudo update-ca-certificatesOutput میں اہم سطر (اس کے بعد ایک 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 کے ذریعے تبدیل کریں۔ Self-signed certificate کو خود root کے طور پر شامل کرنا اس لیے کام کرتا ہے کہ self-signed certificate اپنا root ہوتا ہے۔
اس کے بعد curl، wget، git، apt، اور ہر وہ چیز جو system bundle کے خلاف OpenSSL استعمال کرتی ہے، بغیر کسی flags کے server پر اعتماد کرے گی۔ کچھ کلائنٹس اپنے trust stores رکھتے ہیں اور ان کے لیے الگ کارروائی درکار ہوتی ہے:
- Linux پر Chrome/Chromium system store کے بجائے NSS database پڑھتا ہے:
sudo apt install libnss3-tools، پھر ہر user کے لیےcertutil -d sql:$HOME/.pki/nssdb -A -t "C,," -n "git.internal" -i git.internal.crt۔ - Firefox کا اپنا store ہوتا ہے: Settings → Privacy & Security → Certificates → Import، یا
about:configمیںsecurity.enterprise_roots.enabledکوtrueمیں تبدیل کریں تاکہ یہ system store پڑھے۔ - Python requests اپنا CA bundle (certifi) فراہم کرتا ہے اور system store کو نظرانداز کرتا ہے:
verify="/usr/local/share/ca-certificates/git.internal.crt"پاس کریں یاREQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crtexport کریں۔ - Node.js:
NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/git.internal.crtexport کریں۔
Windows کلائنٹس پر .crt پر double-click کریں اور اسے Trusted Root Certification Authorities میں install کریں۔ macOS پر اسے Keychain Access میں System keychain میں شامل کریں اور Always Trust منتخب کریں۔
متعدد سروسز کے لیے ایک root: ایک چھوٹا نجی CA
ہر سرٹیفکیٹ پر الگ اعتماد فوراً قابلِ توسیع نہیں رہتا: چھ سروسز کو چار کلائنٹ مشینوں سے ضرب دیں تو اعتماد کی 24 تنصیبات درکار ہوتی ہیں، اور ہر نئی سروس مزید تنصیبات کا باعث بنتی ہے۔ حل ایک نجی CA ہے۔ کلائنٹس صرف ایک root پر اعتماد کرتے ہیں، اور آپ ہر سروس کے سرٹیفکیٹ پر اسی سے دستخط کرتے ہیں۔
آسان انتخاب mkcert ہے۔ یہ Ubuntu 24.04 کے repositories میں موجود ہے اور ان NSS stores (Chrome، Firefox) کو بھی سنبھالتا ہے جنہیں update-ca-certificates نظرانداز کرتا ہے:
sudo apt install -y mkcert libnss3-tools
mkcert -install
mkcert git.internal.lan "*.internal.lan" 10.8.0.1mkcert -install ایک root بناتا ہے اور اسے اس مشین کے ہر trust store میں رجسٹر کرتا ہے؛ تیسری command git.internal.lan+2.pem اور git.internal.lan+2-key.pem تیار کرتی ہے، جنہیں اوپر دیے گئے nginx یا Apache snippets میں شامل کیا جا سکتا ہے۔ اس کا ڈیزائن مفروضہ development machine ہے۔ root key اس machine پر رہتی ہے جہاں -install چلایا گیا تھا۔ اسی لیے یہ dev laptop کے لیے بہترین، لیکن server fleet کے لیے ناموزوں ہے۔
Servers کے لیے plain 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 بطور default CSR کی تمام extensions خارج کر دیتا ہے، جن میں آپ کی احتیاط سے شامل کردہ SAN بھی شامل ہے۔ -copy_extensions copy (یہ OpenSSL 3.x کا option ہے، اس لیے 24.04 پر کام کرتا ہے) ان extensions کو برقرار رکھتا ہے۔ اسے چھوڑنے پر signed certificate میں SAN نہیں ہوگا، اور Chrome دوبارہ NET::ERR_CERT_COMMON_NAME_INVALID دکھائے گا۔ پہلے کی طرح اسی openssl x509 -noout -ext subjectAltName check سے تصدیق کریں۔
اوپر دیے گئے trust-store مراحل کے ذریعے ہر client machine پر صرف ایک بار lab-ca.crt تقسیم کریں۔ lab-ca.key کی اسی طرح حفاظت کریں جیسے اب یہ نہایت قیمتی cryptographic key ہو: mode 600 رکھیں، اور بہتر ہے کہ اسے ایسی machine پر رکھا جائے جو ان servers میں شامل نہ ہو جن کے لیے یہ دستخط کرتی ہے، کیونکہ جس کے پاس یہ key ہوگی وہ کسی بھی ایسے نام کے لیے certificate بنا سکتا ہے جس پر آپ کے clients اعتماد کریں گے۔
میعاد اور گردش
عوامی CA سرٹیفکیٹس کی میعاد مسلسل کم ہو رہی ہے۔ CA/Browser Forum نے مارچ 2026 میں نئے جاری کیے گئے عوامی طور پر قابلِ اعتماد سرٹیفکیٹس کی زیادہ سے زیادہ میعاد 200 دن مقرر کی، جو پہلے 398 دن تھی۔ یہ حد 2027 میں 100 دن اور مارچ 2029 تک 47 دن ہو جائے گی۔ تاہم یہ قواعد عوامی طور پر قابلِ اعتماد CAs پر لاگو ہوتے ہیں۔ آپ کی نجی CA ان قواعد کی پابند نہیں ہے، اور browsers دستی طور پر نصب کیے گئے 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تجدید کو باقاعدہ calendar میں درج کریں، یا cron کو کہیں کہ 30 دن پہلے یاد دہانی کرائے۔ openssl x509 -checkend 2592000 -in cert.crt اس وقت non-zero کے ساتھ ختم ہوتا ہے جب expiry میں اتنے seconds یا اس سے کم باقی رہ جائیں۔ اگر آپ پہلے ہی status monitoring کے لیے Uptime Kuma چلا رہے ہیں تو اس کے HTTPS monitors آنے والی certificate expiry کی اطلاع بلا معاوضہ دیتے ہیں۔
نجی CA کے ساتھ rotation معمولی عمل ہے: CSR اور signing commands دوبارہ چلائیں، files تبدیل کریں، اور web server کو reload کریں۔ root تبدیل نہیں ہوا، اس لیے کسی client کو کچھ محسوس نہیں ہوگا۔
خرابی کی صورتیں اور آپ کو نظر آنے والے پیغامات
NET::ERR_CERT_AUTHORITY_INVALID، اعتماد قائم کرنے سے پہلے متوقع حالت ہے، سرٹیفکیٹ میں خرابی نہیں۔ اگر root انسٹال کرنے کے بعد بھی یہ برقرار رہے: Linux پر Chrome سسٹم اسٹور کے بجائے NSS پڑھتا ہے (certutil مرحلہ دیکھیں)؛ یا نقل کی گئی فائل کا اختتام .crt پر نہیں ہوا اور update-ca-certificates نے 0 added بتایا؛ یا server آپ کے منظور کردہ سرٹیفکیٹ سے مختلف سرٹیفکیٹ پیش کر رہا ہے۔ فنگر پرنٹس کا 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 address bar میں موجود نام کا احاطہ نہیں کرتا۔ عام صورت یہ ہے: SAN میں DNS:git.internal.lan درج ہے، لیکن user نے https://10.8.0.1 کھولا۔ trust-store کی تبدیلیاں اس مسئلے کو حل نہیں کر سکتیں؛ missing entry کے ساتھ سرٹیفکیٹ دوبارہ جاری کریں۔
curl: (60) SSL certificate problem: self-signed certificate، curl سرٹیفکیٹ پر اعتماد نہیں کرتا۔ self-signed certificate in certificate chain variant کا مطلب بھی یہی ہے، جب سرٹیفکیٹ آپ کے private CA سے دستخط شدہ ہو۔ عارضی حل: curl --cacert lab-ca.crt https://...؛ مستقل حل: trust store۔ -k نہیں۔
unable to load certificate ... Expecting: TRUSTED CERTIFICATE (یا Expecting: CERTIFICATE REQUEST، یا no start line)، PEM سے متعلق الجھن ہے۔ آپ نے OpenSSL کو غلط قسم کی فائل دی: جہاں certificate درکار تھا وہاں key یا CSR دی، یا جہاں PEM درکار تھا وہاں DER binary دی۔ head -1 filename بتاتا ہے کہ آپ کے پاس اصل میں کیا ہے؛ certificate کا آغاز -----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)، certificate اور key ایک دوسرے سے متعلق نہیں ہیں۔ عموماً ایسا اس لیے ہوتا ہے کہ generation command دو بار چلائی گئی اور فائلیں آپس میں مل گئیں۔ openssl x509 -in git.internal.crt -noout -pubkey | sha256sum اور openssl pkey -in git.internal.key -pubout | sha256sum کا موازنہ کر کے تصدیق کریں؛ یکساں hashes کا مطلب ہے کہ جوڑا درست ہے۔ اگر یہ مختلف ہوں تو دونوں کو ایک ساتھ دوبارہ تیار کریں۔
FAQ
Chrome کی جانب سے self-signed certificate بنانے کے بعد بھی "Not secure" کیوں دکھایا جاتا ہے؟
اگر خرابی NET::ERR_CERT_AUTHORITY_INVALID ہے تو certificate درست ہے، لیکن Chrome کے پاس ابھی اسے trusted سمجھنے کی کوئی وجہ نہیں ہے۔ اسے، یا اپنے private CA root کو، client کے trust store میں install کریں۔ یہ بھی یاد رکھیں کہ Linux پر Chrome، system store کے بجائے certutil کے ذریعے NSS database استعمال کرتا ہے۔ اگر خرابی 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 کے خلاف verification کرتا ہے۔ -k verification مکمل طور پر بند کرتا ہے، اس لیے اسے کسی کے scripts میں شامل نہیں ہونا چاہیے۔
self-signed certificate کتنے عرصے تک valid رہ سکتا ہے؟
تکنیکی طور پر اسے آپ کی مرضی کے مطابق زیادہ عرصے تک valid رکھا جا سکتا ہے۔ CA/Browser Forum کی limits، جو اس وقت 200 days اور 2029 تک 47 ہوں گی، public trust والے CAs پر لاگو ہوتی ہیں، private trust پر نہیں۔ عملی طور پر server certificates کو 825 days تک محدود رکھیں، کیونکہ Apple devices issuer سے قطع نظر اس سے زیادہ مدت والے certificates مسترد کر دیتے ہیں۔ دو سالہ (-days 730) leaf certificates کے ساتھ دس سالہ private root ایک مناسب default ہے۔ Renewal کی تاریخ calendar میں درج کریں، کیونکہ expired internal certificate کسی کو یاد نہ رہنے والی تاریخ پر پورا system خاموشی سے بند کر سکتا ہے۔
کیا مجھے self-signed certificate استعمال کرنا چاہیے یا Let's Encrypt؟
اگر service کا public DNS name ہے اور وہ internet سے reachable ہے تو ہمیشہ Let's Encrypt استعمال کریں۔ یہ مفت اور automated ہے، اور ہر client پہلے ہی اسے trust کرتا ہے۔ Self-signed certificate، یا private CA، ان حالات کے لیے ہے جن میں Let's Encrypt certificate جاری نہیں کر سکتا: private IPs، .lan جیسے internal-only hostnames، air-gapped networks، اور وہ services جنہیں جان بوجھ کر VPN کے پیچھے hidden رکھا گیا ہو۔ فیصلہ reachability اور naming پر منحصر ہے، security strength پر نہیں۔ Cryptography دونوں صورتوں میں یکساں ہے۔
/usr/local/share/ca-certificates میں شامل کرنے کے بعد بھی میرا certificate مسترد کیوں کیا جاتا ہے؟
تین چیزیں چیک کریں۔ File کا اختتام .crt پر ہونا چاہیے۔ .pem extension والی file خاموشی سے skip ہو جاتی ہے، اور update-ca-certificates، 0 added رپورٹ کرتا ہے۔ مواد PEM text ہونا چاہیے جو -----BEGIN CERTIFICATE----- سے شروع ہو، DER binary نہیں۔ یہ بھی یقینی بنائیں کہ application واقعی system store استعمال کرتی ہے۔ Linux پر Chrome، Firefox، Python requests، Node.js، اور Java ہر ایک اپنا private trust store رکھتے ہیں، اس لیے certificate کو ہر application میں الگ شامل کرنا پڑتا ہے۔