Ubuntu 24.04 এ self-signed certificate তৈরি করুন
Ubuntu 24.04 এ SAN সহ একটি openssl কমান্ড দিয়ে self-signed TLS certificate তৈরি করুন যা Chrome গ্রহণ করে। nginx ও Apache কনফিগ এবং curl -k ছাড়াই বিশ্বস্ত করার পদ্ধতি দেখুন।
আপনি যা তৈরি করছেন
একটি স্ব-স্বাক্ষরিত TLS সার্টিফিকেট যা আধুনিক ব্রাউজার এবং ক্লায়েন্ট বাস্তবে গ্রহণ করে — সঠিক subjectAltName, যৌক্তিক কী অনুমতি, nginx বা Apache-এর সাথে সংযুক্ত — সেই সাথে একটি বিষয় যা প্রায় প্রতিটি গাইড বাদ দেয়: আপনার ক্লায়েন্টগুলিকে সতর্কতা উপেক্ষা করে এবং স্ক্রিপ্টে চিরকালের জন্য curl -k হার্ড-কোড না করে এটিকে যথাযথভাবে বিশ্বস্ত করে তোলা। শেষে, একটি পাঁচ-কমান্ডের প্রাইভেট CA, যখন একটি অভ্যন্তরীণ পরিষেবা ছয়টিতে পরিণত হয়।
প্রথমে সিদ্ধান্তটি নিন, কারণ স্ব-স্বাক্ষরিত সার্টিফিকেট খুব কম ক্ষেত্রেই সঠিক উপায়, কিন্তু এটি অনেক বেশি ব্যবহৃত হয়। পরিষেবাটি যদি একটি আসল DNS নামের অধীনে পাবলিক ইন্টারনেট থেকে অ্যাক্সেসযোগ্য হয়, তবে পড়া বন্ধ করুন এবং এর পরিবর্তে nginx-এ certbot দিয়ে একটি বিনামূল্যের Let's Encrypt সার্টিফিকেট বা Apache-এর সমতুল্য সংস্করণ ব্যবহার করুন। এর কোনো খরচ নেই, এটি নিজে নিজেই নবায়ন হয়, এবং পৃথিবীর প্রতিটি ব্রাউজার ইতিমধ্যেই এটিকে বিশ্বস্ত বলে মানে। কোনো পাবলিক সাইটে স্ব-স্বাক্ষরিত সার্টিফিকেট ব্যবহার করলে আপনার ব্যবহারকারীরা নিরাপত্তা সতর্কতা উপেক্ষা করতে অভ্যস্ত হয়ে পড়ে, যা সাধারণ HTTP-এর চেয়েও খারাপ অভ্যাস।
যখন কোনো পাবলিক ইন্টারনেট জড়িত নেই, তখনই স্ব-স্বাক্ষরিত সার্টিফিকেট সঠিক পছন্দ: আপনার VPS-এ একটি WireGuard টানেল ঠিকানায় আবদ্ধ একটি অ্যাডমিন প্যানেল, একটি প্রাইভেট নেটওয়ার্কে একটি স্টেজিং বক্স, ব্যাকএন্ডগুলির মধ্যে পরিষেবা-থেকে-পরিষেবা ট্রাফিক, একটি হোম-ল্যাব অ্যাপ্লায়েন্স, অথবা 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)। এখানে কোনো কিছুর জন্যই ইন্টারনেট সংযোগের প্রয়োজন নেই; এগুলো সবই এয়ার-গ্যাপড পরিবেশে কাজ করে।
কেন পুরোনো এক লাইনের কমান্ড এমন সার্টিফিকেট তৈরি করে যা 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এটি ধারাবাহিক কিছু ইন্টারঅ্যাকটিভ প্রশ্ন করে, আপনার hostname-টি Common Name ফিল্ডে রাখে, এবং কোনো subjectAltName এক্সটেনশন ছাড়াই একটি সার্টিফিকেট তৈরি করে। সেই সার্টিফিকেটটি তৈরি হওয়ার সাথে সাথেই অকেজো। Chrome 58 সংস্করণে, 2017 সালের এপ্রিলে Common Name পড়া বন্ধ করে দিয়েছিল — RFC 2818 আগেই 2000 সালে CN ম্যাচিং বাতিল করেছিল — এবং 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.ট্রাস্ট-স্টোর নিয়ে কোনো কাজই এই ত্রুটি ঠিক করে না, কারণ সার্টিফিকেটটি সত্যিই কিছুর নাম বহন করে না। আপনি যদি এখন NET::ERR_CERT_COMMON_NAME_INVALID দেখছেন, তাহলে আপনার সার্টিফিকেটে কোনো SAN নেই (অথবা ভুল SAN আছে) এবং আপনাকে একটি নতুন সার্টিফিকেট তৈরি করতে হবে। সৌভাগ্যবশত সমাধানটি মাত্র একটি কমান্ডের ব্যাপার।
ব্রাউজার গ্রহণযোগ্য সার্টিফিকেট তৈরি করুন: একটি কমান্ডে
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একই ধাপে একটি নতুন কী তৈরি করে। RSA 4096 কোনো পুরোনো ক্লায়েন্টে সমস্যা তৈরি করে না; সব ক্লায়েন্ট আধুনিক হলে-newkey ec -pkeyopt ec_paramgen_curve:P-256ছোট এবং দ্রুত।-noencহলো পুরোনো-nodes-এর OpenSSL 3.x রূপ: কী-তে কোনো পাসফ্রেজ থাকে না। দুটি রূপই কাজ করে। পাসফ্রেজ যুক্ত কী ব্যবহার করলে প্রতিবার বুট হওয়ার সময় ইনপুটের জন্য অপেক্ষা করে 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 নেই এবং ব্রাউজার এটি প্রত্যাখ্যান করবে — এগিয়ে যাওয়ার বদলে আবার তৈরি করুন।
কী লক করুন
সিস্টেমের প্রতিটি ব্যবহারকারীর দ্বারা পঠনযোগ্য একটি প্রাইভেট কী আর প্রাইভেট কী নয়। 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 mode 600 তাদের জন্য কাজ করে। যদি কীটি এমন একটি পরিষেবার জন্য হয় যা নিজস্ব ব্যবহারকারী হিসেবে চলে এবং কী নিজে লোড করে — একটি Node অ্যাপ, Gitea, একটি Python ডেমন — chown সেই পরিষেবা ব্যবহারকারীর কাছে, এখনও mode 600। আপনি যা কখনও করবেন না: mode 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 nginxreload কিছু করার আগে nginx -t-কে অবশ্যই syntax is ok এবং test is successful প্রিন্ট করতে হবে। এর পরিবর্তে যদি এটি SSL_CTX_use_PrivateKey_file() failed ... key values mismatch প্রিন্ট করে, তাহলে সার্টিফিকেট এবং কী দুটি ভিন্ন জেনারেশন রান থেকে এসেছে — failure-modes বিভাগটি দেখুন।
Apache-এ যুক্ত করুন
sudo a2enmod ssl proxy proxy_httpssl একাকী এখানে যথেষ্ট নয়: নিচের 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 apache2configtest-এর Syntax OK-এ সাড়া দেওয়া উচিত। এখন একটি ক্লায়েন্ট মেশিন থেকে পরীক্ষা করুন:
curl -v https://git.internal.lan/এবং আপনি একটি ত্রুটি পাবেন:
curl: (60) SSL certificate problem: self-signed certificateএটি কোনো বাগ নয়। এটি TLS সঠিকভাবে কাজ করছে বলে প্রমাণ: curl আপনার সার্টিফিকেট সম্পর্কে জানে না এবং এমন একটি সার্ভারের সাথে যোগাযোগ করতে অস্বীকার করে যাকে এটি প্রমাণীকরণ করতে পারে না। পরবর্তী বিভাগে আসল সমাধান রয়েছে — এবং এটি এই মুহূর্তে ইন্টারনেটের অর্ধেক যা করে, তা নয়।
ক্লায়েন্টদের সার্টিফিকেট বিশ্বাস করান — এবং যে অ্যান্টি-প্যাটার্নগুলো এড়িয়ে চলা উচিত
প্রথমেই ভুল সমাধানগুলো দেখা যাক, যথাযথ নামে। স্ক্রিপ্টে বসানো curl -k (বা --insecure), Python requests-এ verify=False, Node-এ NODE_TLS_REJECT_UNAUTHORIZED=0 — এর কোনোটিই আপনার সার্টিফিকেটকে বিশ্বস্ত করে না। এগুলো সার্টিফিকেট যাচাইকরণ বন্ধ করে দেয়। ফলে ক্লায়েন্ট যেকোনো সার্ভারের যেকোনো সার্টিফিকেট তাৎক্ষণিকভাবে মেনে নেয়, এমনকি একজন আক্রমণকারীর দেওয়া সার্টিফিকেটও। আপনি TLS-এর ওভারহেড বহন করেন, আর এর মূল উদ্দেশ্য অর্থাৎ প্রমাণীকরণ হারিয়ে ফেলেন। এর চেয়েও খারাপ ব্যাপার হলো, এই ফ্ল্যাগগুলো ছড়িয়ে পড়ে। একটি cron জবে পেস্ট করা হয়, তারপর একটি deploy স্ক্রিপ্টে, তারপর প্রোডাকশন কোডে, যতক্ষণ না কেউ মনে রাখে না কোন কানেকশনগুলো অস্থায়ী ছিল। ডিবাগিং সেশনে তৈরি করা একটি verify=False যদি সেই সেশনের পরেও থেকে যায়, তবে ডিজাইনটি ভুল।
সঠিক সমাধান হলো প্রতিটি ক্লায়েন্ট OS-কে শেখানো যে এই সার্টিফিকেটটি একটি বিশ্বস্ত রুট। 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 ব্যবহার করে এমন আর যা কিছু আছে, সবই কোনো ফ্ল্যাগ ছাড়াই সার্ভারকে বিশ্বাস করে। কয়েকটি ক্লায়েন্ট তাদের নিজস্ব ট্রাস্ট স্টোর বহন করে এবং আলাদাভাবে সেট আপ করা প্রয়োজন:
- Linux-এ Chrome/Chromium সিস্টেম স্টোর নয়, বরং একটি 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, অথবা
about:config-এsecurity.enterprise_roots.enabledকেtrue-এ পরিবর্তন করুন যাতে এটি সিস্টেম স্টোর পড়ে। - 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-এ, Keychain Access-এ এটি System keychain-এ যোগ করুন এবং Always Trust হিসেবে চিহ্নিত করুন।
অনেক পরিষেবার জন্য একটি রুট: একটি ছোট ব্যক্তিগত CA
প্রতি-সার্টিফিকেট ভরসা দ্রুত স্কেল করতে পারে না: ছয়টি পরিষেবা গুণ চারটি ক্লায়েন্ট মেশিন মানে চব্বিশটি ভরসা ইনস্টল, এবং প্রতিটি নতুন পরিষেবা এটি আরও বাড়ায়। সমাধান হল একটি ব্যক্তিগত CA — ক্লায়েন্টরা একটি রুট বিশ্বাস করে, এবং আপনি প্রতিটি পরিষেবার সার্টিফিকেট এটি দিয়ে সাইন করেন।
ব্যবহারে সহজ বিকল্প হল mkcert, যা Ubuntu 24.04 রিপোজিটরিতে আছে এবং update-ca-certificates যে NSS স্টোরগুলো (Chrome, Firefox) মিস করে সেগুলো হ্যান্ডেল করে:
sudo apt install -y mkcert libnss3-tools
mkcert -install
mkcert git.internal.lan "*.internal.lan" 10.8.0.1mkcert -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 Forum 2026 সালের মার্চে নতুন পাবলিকলি ট্রাস্টেড সার্টিফিকেটের মেয়াদ 200 দিনে সীমিত করেছে (আগে ছিল 398), 2027 সালে তা 100 দিনে নেমে আসবে এবং 2029 সালের মার্চের মধ্যে 47 দিনে পৌঁছাবে — কিন্তু এই নিয়মগুলো শুধু পাবলিকলি ট্রাস্টেড CA-তেই প্রযোজ্য। আপনার প্রাইভেট CA এগুলোর আওতায় পড়ে না, এবং ব্রাউজার ম্যানুয়ালি ইনস্টল করা রুটের ক্ষেত্রে এগুলো প্রয়োগ করে না। একটি বাস্তব সীমাবদ্ধতা প্রযোজ্য: Apple প্ল্যাটফর্ম যেকোনো TLS সার্ভার সার্টিফিকেট প্রত্যাখ্যান করে যদি তার মেয়াদ 825 দিনের বেশি হয়, ইস্যুকারী যেই-ই হোন না কেন। তাই iPhone বা Mac সংযুক্ত হবে যদি, লিফ সার্টিফিকেট দুই বছর বা তার কম রাখুন। -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; অথবা সার্ভার আপনি যে সার্টিফিকেটটিতে ট্রাস্ট করেছেন তার থেকে ভিন্ন একটি সার্টিফিকেট উপস্থাপন করছে — 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, অথবা যেখানে PEM প্রত্যাশিত ছিল সেখানে একটি DER বাইনারি। 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
নিজে স্বাক্ষরিত সার্টিফিকেট তৈরি করার পরেও Chrome কেন এখনও "Not secure" দেখাচ্ছে?
ত্রুটি যদি NET::ERR_CERT_AUTHORITY_INVALID হয়, তাহলে সার্টিফিকেট ঠিক আছে — Chrome এর এখনও এটি বিশ্বাস করার কোনো কারণ নেই। এটি ক্লায়েন্টের ট্রাস্ট স্টোরে ইনস্টল করুন (বা আপনার প্রাইভেট CA রুট)। মনে রাখবেন, Linux-এ Chrome সিস্টেম স্টোর ব্যবহার করে না, বরং certutil-এর মাধ্যমে NSS ডেটাবেস ব্যবহার করে। ত্রুটি যদি NET::ERR_CERT_COMMON_NAME_INVALID হয়, তাহলে সার্টিফিকেটে URL-এর সাথে মিলে যাওয়া একটি Subject Alternative Name নেই এবং -addext "subjectAltName=..." দিয়ে এটি নতুন করে ইস্যু করতে হবে।
-k ছাড়া curl কীভাবে একটি নিজে স্বাক্ষরিত সার্টিফিকেট বিশ্বাস করবে?
সার্টিফিকেটটি (PEM ফরম্যাট, .crt এক্সটেনশন) /usr/local/share/ca-certificates/-এ কপি করুন এবং sudo update-ca-certificates রান করুন — আউটপুটে অবশ্যই 1 added লেখা থাকতে হবে। এরপর থেকে curl এটিকে যেকোনো পাবলিক সার্টিফিকেটের মতোই যাচাই করবে। সিস্টেমে কিছু না ছুঁয়ে একবারের জন্য রিকোয়েস্ট করতে, curl --cacert /path/to/cert.crt শুধুমাত্র সেই ফাইলের বিপরীতে যাচাই করে; -k যাচাই সম্পূর্ণ বন্ধ করে দেয় এবং কারও স্ক্রিপ্টে এর কোনো স্থান নেই।
একটি নিজে স্বাক্ষরিত সার্টিফিকেট কতদিন বৈধ থাকতে পারে?
প্রযুক্তিগতভাবে আপনার যত খুশি তত দিন — CA/Browser Forum-এর সীমা (এখন 200 দিন, 2029-এ 47 দিন) শুধুমাত্র পাবলিকভাবে বিশ্বস্ত CA-গুলিকে বাঁধে, প্রাইভেট ট্রাস্টকে নয়। বাস্তবে, সার্ভার সার্টিফিকেট 825 দিনের বেশি রাখবেন না, কারণ ইস্যুয়ার যেই হোক না কেন, Apple ডিভাইস এর চেয়ে দীর্ঘ সময়ের সার্টিফিকেট প্রত্যাখ্যান করে। দশ বছরের একটি প্রাইভেট রুট এবং দুই বছরের (-days 730) লিফ সার্টিফিকেট একটি যুক্তিযুক্ত ডিফল্ট; শুধু নবায়নের তারিখ ক্যালেন্ডারে চিহ্নিত করে রাখবেন, কারণ একটি মেয়াদোত্তীর্ণ অভ্যন্তরীণ সার্টিফিকেট এমন একটি তারিখে নীরবে সবকিছু বন্ধ করে দেয় যা কেউ মনে রাখে না।
আমার কি নিজে স্বাক্ষরিত সার্টিফিকেট ব্যবহার করা উচিত নাকি Let's Encrypt?
সার্ভিসের যদি একটি পাবলিক DNS নাম থাকে এবং এটি ইন্টারনেট থেকে অ্যাক্সেসযোগ্য হয়, তাহলে সবসময় Let's Encrypt ব্যবহার করুন — এটি বিনামূল্যে, স্বয়ংক্রিয় এবং প্রতিটি ক্লায়েন্টের কাছে আগে থেকেই বিশ্বস্ত। নিজে স্বাক্ষরিত সার্টিফিকেট (বা প্রাইভেট CA) তখনই ব্যবহার করুন যখন Let's Encrypt ইস্যু করতে পারে না: প্রাইভেট IP, শুধুমাত্র অভ্যন্তরীণ হোস্টনাম যেমন .lan, এয়ার-গ্যাপড নেটওয়ার্ক এবং ইচ্ছাকৃতভাবে VPN-এর পেছনে লুকানো সার্ভিস। এই সিদ্ধান্তটি অ্যাক্সেসযোগ্যতা এবং নামকরণের উপর নির্ভর করে, নিরাপত্তার শক্তির উপর নয় — ক্রিপ্টোগ্রাফি উভয় ক্ষেত্রেই একই।
/usr/local/share/ca-certificates-এ যোগ করার পরেও আমার সার্টিফিকেট কেন প্রত্যাখ্যান করা হচ্ছে?
তিনটি বিষয় পরীক্ষা করুন। ফাইলের নাম অবশ্যই .crt দিয়ে শেষ হতে হবে — .pem এক্সটেনশন নীরবে উপেক্ষা করা হয় এবং update-ca-certificates এর আউটপুট 0 added দেখায়। ফাইলের বিষয়বস্তু অবশ্যই PEM টেক্সট হতে হবে যা -----BEGIN CERTIFICATE----- দিয়ে শুরু হয়, DER বাইনারি নয়। এবং অ্যাপ্লিকেশনটিকে অবশ্যই সিস্টেম স্টোর ব্যবহার করতে হবে — Linux-এ Chrome, Firefox, Python requests, Node.js এবং Java প্রত্যেকেই আলাদা প্রাইভেট ট্রাস্ট স্টোর রাখে এবং সার্টিফিকেট আলাদাভাবে যোগ করতে হয়।