Tạo chứng chỉ tự ký trên Ubuntu 24.04 đúng cách
Tạo TLS certificate tự ký trên Ubuntu 24.04 để Chrome chấp nhận: lệnh openssl có SAN, cấu hình nginx/Apache và trust đúng cách, không dùng curl -k.
Bạn sẽ xây dựng gì
Một TLS certificate tự ký mà các browser và client hiện đại thực sự chấp nhận, có subjectAltName chính xác, quyền truy cập key hợp lý, được tích hợp với nginx hoặc Apache, cùng phần mà gần như mọi hướng dẫn đều bỏ qua: cấu hình để client thực sự trust certificate đúng cách, thay vì bỏ qua các cảnh báo và hard-code curl -k vào script mãi mãi. Cuối cùng là một private CA gồm 5 command, dùng khi một service nội bộ tăng lên thành 6 service.
Trước hết là quyết định có nên dùng hay không, vì self-signed certificate phù hợp trong ít trường hợp hơn nhiều so với mức độ thường được sử dụng. Nếu service có thể truy cập từ public internet bằng một DNS name thực, hãy dừng ở đây và dùng Let's Encrypt certificate miễn phí với certbot trên nginx hoặc cách tương tự trên Apache. Cách này không tốn phí, tự gia hạn, và các browser cùng operating system phổ biến đã trust certificate đó. Dùng self-signed certificate trên public site khiến người dùng quen với việc bỏ qua cảnh báo bảo mật. Đây là thói quen tệ hơn dùng HTTP thuần.
Self-signed là lựa chọn phù hợp khi không liên quan đến public internet: một admin panel bind vào địa chỉ WireGuard tunnel trên VPS của bạn, một staging box trong private network, network traffic giữa các backend, một thiết bị home lab, hoặc thay certificate mặc định mà Webmin tự tạo cho chính nó trên port 10000. Let's Encrypt cũng không thể issue certificate cho 10.8.0.1 hoặc git.internal.lan. Không có public CA nào đưa private IP hoặc TLD tự đặt vào certificate. Với những tên này, bạn là CA.
Toàn bộ nội dung bên dưới chạy trên một box Ubuntu 24.04 mới cài, đi kèm OpenSSL 3.0.x (openssl version để xác nhận). Không phần nào cần internet access; tất cả đều hoạt động trong môi trường air-gapped.
Vì sao one-liner cũ tạo ra certificate bị Chrome từ chối
Lệnh mà mọi tutorial trước năm 2017 đều hướng dẫn thường có dạng sau:
# 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.crtLệnh này yêu cầu bạn trả lời một loạt câu hỏi tương tác, ghi hostname vào trường Common Name và tạo certificate không có extension subjectAltName. Certificate đó sẽ bị từ chối ngay. Chrome ngừng đọc Common Name từ version 58, vào tháng 4 năm 2017. RFC 2818 đã deprecated việc đối chiếu CN từ năm 2000, còn Firefox và Safari cũng xử lý tương tự. curl và module ssl của Python vẫn fallback về Common Name khi certificate hoàn toàn không có SAN. Vì vậy, certificate không có SAN có thể vượt qua một bài test curl nhanh nhưng vẫn fail trên mọi browser. Với browser, certificate chỉ xác định server thông qua extension SAN; nếu không có extension này thì certificate không xác định được server nào. Browser sẽ báo chính xác như sau:
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.Không thể sửa lỗi này bằng cách chỉnh trust store, vì certificate thực sự không chứa tên nào. Nếu hiện tại bạn đang thấy NET::ERR_CERT_COMMON_NAME_INVALID, certificate của bạn không có SAN hoặc có SAN sai, và bạn cần tạo certificate mới. May là chỉ cần một lệnh để sửa lỗi này.
Tạo certificate được trình duyệt chấp nhận: một lệnh
OpenSSL bổ sung flag -addext trong phiên bản 1.1.1. Vì vậy, bạn không còn cần các thủ thuật với file cấu hình như trong những hướng dẫn cũ để thêm SAN. Trên 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"Tác dụng của từng flag:
-x509tạo trực tiếp certificate tự ký thay vì certificate signing request.-newkey rsa:4096tạo key mới trong cùng bước. RSA 4096 tương thích với mọi client cũ; nếu tất cả client kết nối đều hiện đại,-newkey ec -pkeyopt ec_paramgen_curve:P-256có kích thước nhỏ hơn và nhanh hơn.-noenclà cú pháp của OpenSSL 3.x cho-nodestrước đây: không đặt passphrase cho key. Cả hai cú pháp đều hoạt động. Nếu key có passphrase, nginx sẽ treo ở trạng thái chờ input mỗi lần boot. Vì vậy, với key của server, bạn nên dùng tùy chọn này.-days 730, thời hạn hai năm; xem thêm về con số này trong phần expiry.-subjtrả lời các câu hỏi tương tác ngay trong lệnh. CN hiện chỉ mang tính hình thức, nhưng vẫn đặt nó thành tên chính; một số tool sẽ hiển thị giá trị này.-addext "subjectAltName=..."là flag quan trọng nhất. Liệt kê mọi tên và mọi IP mà client sẽ nhập: các entryDNS:cho hostname (wildcard nhưDNS:*.internal.lanđược phép), các entryIP:cho địa chỉ IP. Nếu người dùng sẽ truy cậphttps://10.8.0.1, entryIP:10.8.0.1phải có mặt; chỉ dùng SAN dạng DNS sẽ khiến họ lại gặp lỗiNET::ERR_CERT_COMMON_NAME_INVALID.
Xác nhận SAN thực sự đã được thêm trước khi cấu hình các thành phần khác:
openssl x509 -in /etc/ssl/certs/git.internal.crt -noout -ext subjectAltNameKết quả đúng:
X509v3 Subject Alternative Name:
DNS:git.internal.lan, IP Address:10.8.0.1Nếu lệnh thay vào đó in ra No extensions in certificate, certificate không có SAN và trình duyệt sẽ từ chối nó. Hãy tạo lại certificate thay vì tiếp tục.
Bảo vệ chặt private key
Private key mà mọi user trên máy đều có thể đọc thì không còn là private key. Trên Ubuntu 24.04 mặc định, /etc/ssl/private đã ở trạng thái 700 root:root, nên chỉ root mới có thể liệt kê nó; nó chỉ chuyển sang 710 root:ssl-cert nếu có thành phần cài package ssl-cert (apache2 khuyến nghị package này). Dù theo cách nào, hãy đặt quyền rõ ràng cho chính file đó:
sudo chown root:root /etc/ssl/private/git.internal.key
sudo chmod 600 /etc/ssl/private/git.internal.keyNginx và Apache đều đọc certificate dưới quyền root trước khi hạ quyền, nên mode 600 trong root:root hoạt động với chúng. Nếu private key được dùng cho một service chạy bằng user riêng và tự tải key, chẳng hạn app Node, Gitea hoặc một daemon Python, hãy chown cho service user đó, vẫn dùng mode 600. Không bao giờ làm các việc sau: đặt mode 644, lưu một bản sao trong git repository hoặc lưu một bản sao trong /tmp.
Tích hợp với 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 nginxnginx -t phải in syntax is ok và test is successful trước khi reload thực hiện bất kỳ thay đổi nào. Nếu lệnh in SSL_CTX_use_PrivateKey_file() failed ... key values mismatch, certificate và key được tạo trong hai lần chạy khác nhau; xem phần các trường hợp lỗi.
Tích hợp vào Apache
sudo a2enmod ssl proxy proxy_httpssl là chưa đủ: virtual host bên dưới dùng ProxyPass, và nếu thiếu mod_proxy cùng mod_proxy_http thì kiểm tra cấu hình sẽ dừng với lỗi Invalid command 'ProxyPass', perhaps misspelled or defined by a module not included in the server configuration. Lưu virtual host vào /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 phải trả về Syntax OK. Bây giờ hãy kiểm tra từ một máy client:
curl -v https://git.internal.lan/và bạn sẽ nhận được lỗi:
curl: (60) SSL certificate problem: self-signed certificateĐó không phải là bug. Đó là TLS đang hoạt động: curl chưa biết chứng chỉ của bạn và từ chối kết nối với một server mà nó không thể xác thực. Phần tiếp theo là cách xử lý thực sự, và không phải cách mà một nửa Internet đang làm tại thời điểm này.
Để client tin cậy chứng chỉ và các anti-pattern cần tránh
Trước tiên là những cách sửa sai, được gọi đúng bản chất. curl -k (hoặc --insecure) được ghi cứng trong script, verify=False trong Python requests, NODE_TLS_REJECT_UNAUTHORIZED=0 trong Node — không cách nào khiến client tin cậy chứng chỉ của bạn. Chúng tắt việc xác minh chứng chỉ. Khi đó, client sẽ thoải mái kết nối với bất kỳ server nào cung cấp bất kỳ chứng chỉ nào, kể cả chứng chỉ do kẻ tấn công đưa vào đường truyền. Bạn vẫn chịu overhead của TLS nhưng mất cơ chế xác thực vốn là mục đích chính của TLS. Tệ hơn, các flag này dễ lan rộng: được dán vào một cron job, rồi một deploy script, rồi code production, cho đến khi không ai còn nhớ những kết nối nào ban đầu chỉ cần tạm thời. Nếu một verify=False vẫn còn sau phiên debug đã tạo ra nó, thì thiết kế đó là sai.
Cách sửa đúng là cấu hình cho hệ điều hành của từng client biết rằng chứng chỉ này là một root được tin cậy. Trên client Ubuntu và Debian:
sudo cp git.internal.crt /usr/local/share/ca-certificates/git.internal.crt
sudo update-ca-certificatesDòng cần chú ý trong output (sau đó là một block Running hooks in /etc/ca-certificates/update.d...):
Updating certificates in /etc/ssl/certs...
1 added, 0 removed; done.Có 2 điểm dễ gây lỗi trong các dòng này. File phải kết thúc bằng .crt. Extension .pem sẽ bị bỏ qua một cách im lặng, và bạn nhận 0 added mà không có thông báo lỗi. Nội dung file cũng phải ở định dạng PEM; file bắt đầu bằng -----BEGIN CERTIFICATE-----. Trước tiên hãy chuyển đổi file DER nhị phân bằng openssl x509 -inform der -in file.der -out file.crt. Việc thêm chính chứng chỉ self-signed làm root có tác dụng vì chứng chỉ self-signed chính là root của nó.
Sau đó, curl, wget, git, apt và mọi client khác dùng OpenSSL với system bundle sẽ tin cậy server mà không cần flag nào. Một số client có trust store riêng và cần xử lý riêng:
- Chrome/Chromium trên Linux đọc cơ sở dữ liệu NSS, không đọc system store:
sudo apt install libnss3-tools, sau đó chạycertutil -d sql:$HOME/.local/share/pki/nssdb -A -t "C,," -n "git.internal" -i git.internal.crtcho từng user. Đây là đường dẫn mặc định của Chrome từ version 146. Nếu user vẫn có~/.pki/nssdbtừ một bản cài đặt cũ, Chrome tiếp tục đọc file đó. Vì vậy, trên các máy đó hãy trỏ-dđếnsql:$HOME/.pki/nssdb. - Firefox có store riêng: Settings → Privacy & Security → Certificates → Import. Trên Windows và macOS, bạn có thể chuyển
security.enterprise_roots.enabledsangtruetrongabout:configđể Firefox đọc OS store. Mozilla chỉ tài liệu hóa pref này cho Windows và macOS, không áp dụng cho Linux. Vì vậy trên Ubuntu hãy dùng thao tác import. - Python requests đi kèm CA bundle riêng (certifi) và bỏ qua system store: truyền
verify="/usr/local/share/ca-certificates/git.internal.crt"hoặc exportREQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt. - Node.js mặc định dùng các root được bundle riêng: export
NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/git.internal.crt, hoặc yêu cầu Node đọc system store vừa cập nhật bằng flag--use-system-ca(Node 23.9 trở lên trên Linux) hoặcNODE_USE_SYSTEM_CA=1(Node 24.6 và 22.19 trở lên).
Trên client Windows, nhấp đúp vào .crt và cài đặt vào Trusted Root Certification Authorities. Trên macOS, thêm chứng chỉ vào System keychain trong Keychain Access và đặt thành Always Trust.
Một root cho nhiều service: private CA nhỏ
Cài trust riêng cho từng certificate nhanh chóng không còn phù hợp: sáu service nhân với bốn máy client là hai mươi bốn lần cài trust, và mỗi service mới lại làm tăng con số này. Cách xử lý là dùng private CA. Client chỉ cần trust một root, sau đó bạn ký certificate của từng service bằng root đó.
Lựa chọn đơn giản là mkcert. Gói này có trong repo Ubuntu 24.04 và xử lý các NSS store (Firefox và Chrome, với một lưu ý bên dưới) mà update-ca-certificates không xử lý được:
sudo apt install -y mkcert libnss3-tools
mkcert -install
mkcert git.internal.lan "*.internal.lan" 10.8.0.1mkcert -install tạo một root và đăng ký root đó vào system store, các browser NSS store mà nó tìm thấy, và store của Java khi JAVA_HOME được đặt. Node không đọc system store nếu không được chỉ định, vì vậy hãy chạy các app Node với --use-system-ca (hoặc NODE_USE_SYSTEM_CA=1) như trên, hoặc export NODE_EXTRA_CA_CERTS="$(mkcert -CAROOT)/rootCA.pem". Lệnh thứ ba tạo ra git.internal.lan+2.pem và git.internal.lan+2-key.pem, sẵn sàng để đưa vào các đoạn cấu hình nginx hoặc Apache ở trên. Công cụ này được thiết kế cho máy development: root key nằm trên máy đã chạy -install. Vì vậy, nó rất phù hợp với laptop dev nhưng không phù hợp với một fleet server.
Lưu ý tính đến tháng 10 năm 2026: mkcert chỉ tìm NSS database của Chrome tại đường dẫn legacy ~/.pki/nssdb, không tìm tại ~/.local/share/pki/nssdb, là đường dẫn Chrome dùng mặc định từ version 146. Trên máy không có database legacy, hãy tự thêm root cho Chrome bằng lệnh certutil từ section trước và dùng -i "$(mkcert -CAROOT)/rootCA.pem".
Đối với server, OpenSSL thuần có thể tạo toàn bộ CA bằng năm lệnh:
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.crtLỗi thường nằm ở lệnh cuối: theo mặc định, openssl x509 -req loại bỏ toàn bộ extension khỏi CSR, bao gồm cả SAN mà bạn đã thêm cẩn thận. -copy_extensions copy (một option của OpenSSL 3.x nên hoạt động trên 24.04) giữ lại các extension này; nếu bỏ option đó, certificate được ký sẽ không có SAN và Chrome lại hiển thị NET::ERR_CERT_COMMON_NAME_INVALID. Hãy xác minh bằng cùng kiểm tra openssl x509 -noout -ext subjectAltName như trước.
Phân phối lab-ca.crt cho các client bằng các bước trust-store ở trên, một lần cho mỗi máy là đủ. Bảo vệ lab-ca.key như một tài sản tối quan trọng: đặt mode 600, lý tưởng nhất là lưu trên một máy không phải là một trong các server mà nó ký certificate, vì người giữ key này có thể tạo certificate cho bất kỳ tên nào mà client của bạn tin cậy.
Hạn sử dụng và xoay vòng
Thời hạn của chứng chỉ CA public đang bị rút ngắn nhanh chóng. CA/Browser Forum đã giới hạn chứng chỉ được cấp mới bởi các CA được tin cậy công khai ở mức 200 ngày vào tháng 3 năm 2026, giảm từ 398 ngày, rồi giảm tiếp xuống 100 ngày vào năm 2027 và 47 ngày vào tháng 3 năm 2029. Tuy nhiên, các quy định này chỉ áp dụng cho CA được tin cậy công khai. Private CA của bạn không chịu các quy định đó, và trình duyệt cũng không thực thi chúng đối với các root được cài đặt thủ công. Có một giới hạn thực tế vẫn áp dụng: các nền tảng Apple từ chối mọi chứng chỉ TLS của server có thời hạn dài hơn 825 ngày, bất kể chứng chỉ do ai cấp. Vì vậy, nếu iPhone hoặc Mac sẽ kết nối, hãy giữ chứng chỉ leaf ở mức không quá hai năm. -days 730 đáp ứng giới hạn đó trên mọi nền tảng; root có thời hạn mười năm cùng các chứng chỉ leaf có thời hạn hai năm là mô hình nội bộ phù hợp.
Chứng chỉ có thời hạn dài chỉ hỏng theo một cách: âm thầm hết hạn cùng lúc vào một ngày mà không ai nhớ đã chọn. Hãy kiểm tra các chứng chỉ hiện có:
openssl x509 -in /etc/ssl/certs/git.internal.crt -noout -enddateHãy đưa việc gia hạn vào lịch thực tế, hoặc dùng cron để nhắc trước 30 ngày. openssl x509 -checkend 2592000 -in cert.crt trả về mã khác 0 khi thời điểm hết hạn còn trong số giây đó. Nếu bạn đã chạy Uptime Kuma để giám sát trạng thái, các HTTPS monitor của Uptime Kuma sẽ miễn phí cảnh báo khi chứng chỉ sắp hết hạn.
Xoay vòng với private CA khá đơn giản: chạy lại các lệnh tạo CSR và ký, thay các file, rồi reload web server. Root không thay đổi, nên không client nào nhận thấy.
Các lỗi thường gặp và chuỗi bạn sẽ thấy
NET::ERR_CERT_AUTHORITY_INVALID, đây là trạng thái expected trước khi bạn cài trust, không phải lỗi của certificate. Nếu lỗi này vẫn xuất hiện sau khi bạn đã cài root: trên Linux, Chrome đọc NSS thay vì system store (xem bước certutil), và từ Chrome 146, database đó nằm tại ~/.local/share/pki/nssdb nếu không có ~/.pki/nssdb kiểu cũ, nên root được thêm vào path còn lại sẽ không bao giờ được phát hiện; hoặc file đã copy không kết thúc bằng .crt và update-ca-certificates hiển thị 0 added; hoặc server đang cung cấp certificate khác với certificate bạn đã trust, hãy so sánh fingerprint bằng openssl s_client -connect git.internal.lan:443 </dev/null 2>/dev/null | openssl x509 -noout -fingerprint -sha256.
NET::ERR_CERT_COMMON_NAME_INVALID, certificate không có SAN hoặc SAN không bao phủ tên trong address bar. Trường hợp kinh điển: SAN liệt kê DNS:git.internal.lan nhưng người dùng truy cập https://10.8.0.1. Thay đổi trust store không thể sửa lỗi này; hãy cấp lại certificate với entry còn thiếu.
curl: (60) SSL certificate problem: self-signed certificate, curl không trust certificate. Biến thể self-signed certificate in certificate chain cũng có nghĩa tương tự đối với certificate được ký bởi private CA của bạn. Cách sửa tạm thời cho một lần: curl --cacert lab-ca.crt https://...; cách sửa lâu dài: trust store. Không dùng -k.
unable to load certificate ... Expecting: TRUSTED CERTIFICATE (hoặc Expecting: CERTIFICATE REQUEST, hoặc no start line), nhầm định dạng PEM. Bạn đã đưa cho OpenSSL sai loại file: key hoặc CSR trong khi OpenSSL cần certificate, hoặc file nhị phân DER trong khi OpenSSL cần PEM. head -1 filename cho biết loại file thực tế, còn certificate bắt đầu bằng -----BEGIN CERTIFICATE-----. Với DER, hãy chuyển đổi bằng openssl x509 -inform der -in file.der -out file.crt.
nginx: [emerg] SSL_CTX_use_PrivateKey_file(...) failed (SSL: error ... key values mismatch), certificate và key không thuộc cùng một cặp, thường vì lệnh tạo đã được chạy 2 lần và các file bị trộn. Xác nhận bằng cách so sánh openssl x509 -in git.internal.crt -noout -pubkey | sha256sum với openssl pkey -in git.internal.key -pubout | sha256sum; hash trùng nhau nghĩa là một cặp khớp. Nếu khác nhau, hãy tạo lại cả hai cùng lúc.
FAQ
Vì sao Chrome vẫn hiển thị “Không bảo mật” sau khi tôi tạo self-signed certificate?
Nếu lỗi là NET::ERR_CERT_AUTHORITY_INVALID, certificate không có vấn đề; Chrome chỉ chưa có lý do để trust certificate đó. Hãy cài certificate đó, hoặc private CA root của bạn, vào trust store của client. Lưu ý rằng trên Linux, Chrome dùng cơ sở dữ liệu NSS thông qua certutil, tại ~/.local/share/pki/nssdb kể từ Chrome 146, hoặc dùng ~/.pki/nssdb cũ nếu có, chứ không dùng system store. Nếu lỗi là NET::ERR_CERT_COMMON_NAME_INVALID, certificate thiếu Subject Alternative Name khớp với URL và phải được cấp lại bằng -addext "subjectAltName=...".
Làm cách nào để curl trust self-signed certificate mà không dùng -k?
Sao chép certificate ở định dạng PEM, có phần mở rộng .crt, vào /usr/local/share/ca-certificates/ rồi chạy sudo update-ca-certificates. Output phải hiển thị 1 added. Từ đó, curl sẽ verify certificate này như mọi public certificate khác. Với một request riêng lẻ mà không thay đổi cấu hình hệ thống, curl --cacert /path/to/cert.crt sẽ verify dựa trên riêng file đó; -k tắt hoàn toàn việc verify và không được dùng trong bất kỳ script nào.
Self-signed certificate có thể có hiệu lực trong bao lâu?
Về mặt kỹ thuật, thời hạn có thể tùy ý. Giới hạn của CA/Browser Forum, hiện là 200 ngày và sẽ là 47 ngày vào năm 2029, áp dụng cho public CA được tin cậy, không áp dụng cho private trust. Trên thực tế, hãy giới hạn server certificate ở 825 ngày, vì thiết bị Apple sẽ từ chối certificate dài hơn bất kể issuer là gì. Một private root có thời hạn 10 năm, cùng các leaf certificate thời hạn 2 năm (-days 730), là mặc định hợp lý. Chỉ cần lập lịch renewal, vì một internal certificate hết hạn có thể âm thầm làm mọi thứ ngừng hoạt động vào một ngày không ai nhớ.
Tôi nên dùng self-signed certificate hay Let's Encrypt?
Nếu service có public DNS name và có thể truy cập từ Internet, hãy luôn dùng Let's Encrypt: miễn phí, tự động và đã được hầu hết browser và operating system trust. Nếu cần hỗ trợ các thiết bị rất cũ, hãy kiểm tra danh sách compatibility của Let's Encrypt. Self-signed certificate, hoặc private CA, phù hợp với những trường hợp Let's Encrypt không thể cấp certificate: private IP, hostname chỉ dùng nội bộ như .lan, mạng air-gapped và các service được cố ý ẩn sau VPN. Quyết định này phụ thuộc vào khả năng truy cập và cách đặt tên, không phụ thuộc vào mức độ bảo mật; cryptography là như nhau.
Vì sao certificate của tôi vẫn bị từ chối sau khi thêm vào /usr/local/share/ca-certificates?
Hãy kiểm tra 3 điểm. File phải có phần mở rộng .crt. File có phần mở rộng .pem sẽ bị bỏ qua một cách âm thầm, và update-ca-certificates sẽ báo 0 added. Nội dung phải là PEM text bắt đầu bằng -----BEGIN CERTIFICATE-----, không phải DER binary. Ngoài ra, application phải thực sự dùng system store. Chrome trên Linux, Firefox, Python requests, Node.js, trừ khi được khởi động với --use-system-ca, và Java đều có trust store riêng, nên cần thêm certificate riêng cho từng application.