Vấn đề
Bạn vừa tải xuống các chứng chỉ SSL mới từ một nhà cung cấp như Sectigo, DigiCert hoặc Let's Encrypt. Bạn thực hiện các bước thông thường: kết hợp chứng chỉ tên miền và các tệp trung gian (intermediate) thành một gói .crt duy nhất. Nhưng khi bạn cố gắng tải lại Nginx hoặc Apache, dịch vụ này gặp lỗi.
Thay vì trạng thái "active" màu xanh, dịch vụ không thể khởi động. Khi bạn kiểm tra nhật ký lỗi (error logs) hoặc chạy thử cấu hình, bạn sẽ thấy thông báo lỗi từ OpenSSL như sau:
nginx: [emerg] SSL_CTX_use_Certificate("/etc/nginx/ssl/bundle.crt") failed
(SSL: error:140AB022:SSL routines:SSL_CTX_use_Certificate:diff orders of certificates)
Tại sao lỗi này xảy ra
Lỗi này là cách OpenSSL thông báo thẳng thừng rằng tệp chứng chỉ của bạn đang bị sai thứ tự. Các máy chủ web rất khắt khe. Chúng đọc gói chứng chỉ từ trên xuống dưới và mong muốn thấy một cấp bậc cụ thể. Nếu máy chủ gặp một chứng chỉ trung gian trước khi tìm thấy chứng chỉ tên miền thực tế của bạn, nó sẽ ngừng hoạt động.
Để máy chủ web hoạt động bình thường, tệp gói của bạn phải tuân theo trình tự nghiêm ngặt từ "lá đến gốc" (leaf-to-root):
- Chứng chỉ máy chủ (Leaf): Chứng chỉ dành riêng cho tên miền của bạn (ví dụ:
example.com). - (Các) Chứng chỉ trung gian (Intermediate): Các chứng chỉ cầu nối do CA cung cấp.
- Chứng chỉ gốc (Root): Chứng chỉ CA cấp cao nhất (thường là tùy chọn, vì hầu hết các trình duyệt đã có sẵn nó).
Phần lớn thời gian, lỗi này xuất hiện vì bạn vô tình thêm chứng chỉ tên miền vào cuối tệp thay vì đặt nó ở ngay đầu tiên.
Cách khắc phục: Sắp xếp lại thứ tự gói chứng chỉ
Việc khắc phục đòi hỏi bạn phải chỉnh sửa thủ công các khối chứng chỉ. Mỗi khối là một đoạn văn bản được mã hóa bắt đầu bằng -----BEGIN CERTIFICATE----- và kết thúc bằng -----END CERTIFICATE-----.
Bước 1: Kiểm tra nội dung tệp
Đừng đoán khối nào là của chứng chỉ nào. Bạn có thể sử dụng OpenSSL để xem nội dung bên trong tệp bundle.crt và xem chứng chỉ nào hiện đang nằm ở trên cùng.
Chạy lệnh này để kiểm tra danh tính của chứng chỉ đầu tiên trong tệp:
openssl x509 -in bundle.crt -text -noout | grep -E 'Subject:|Issuer:'
Kiểm tra dòng Subject trong kết quả đầu ra. Nếu nó hiển thị tên miền của bạn (ví dụ: CN = example.com), khối đầu tiên đã đúng. Tuy nhiên, nếu Subject hiển thị tên của một CA như CN = Sectigo RSA Organization Validation, bạn đã tìm thấy nguyên nhân. Chứng chỉ trung gian đang nằm sai vị trí.
Bước 2: Chỉnh sửa lại thứ tự
Mở tệp gói của bạn bằng trình soạn thảo văn bản như nano hoặc vim:
sudo nano /etc/nginx/ssl/bundle.crt
Sắp xếp lại các khối để chúng tuân theo đúng mẫu này. Đảm bảo không có khoảng trắng thừa hoặc dòng trống giữa các thẻ END và BEGIN:
-----BEGIN CERTIFICATE-----
(Chứng chỉ tên miền của bạn: example.com)
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
(Chứng chỉ trung gian 1: ví dụ, Sectigo RSA DV Bundle)
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
(Chứng chỉ trung gian 2 - nếu có)
-----END CERTIFICATE-----
Bước 3: Xác minh cấu trúc mới
Trước khi khởi động lại máy chủ web, hãy để OpenSSL xác thực tệp. Lệnh này mô phỏng quá trình tải của máy chủ:
openssl x509 -in /etc/nginx/ssl/bundle.crt -noout -text
Nếu lệnh trả về các thông số kỹ thuật của tên miền mà không có lỗi "diff orders", bạn đã sửa lỗi chuỗi chứng chỉ thành công.
Áp dụng các thay đổi
Đối với Nginx
Nginx dựa vào chỉ thị ssl_certificate để trỏ đến tệp kết hợp này. Đảm bảo khối server của bạn trông giống như sau:
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/nginx/ssl/bundle.crt;
ssl_certificate_key /etc/nginx/ssl/example.com.key;
}
Kiểm tra lỗi cú pháp bằng lệnh nginx -t. Nếu thành công, hãy tải lại dịch vụ: systemctl reload nginx.
Đối với Apache
Trong Apache 2.4.8 và mới hơn, chỉ thị SSLCertificateFile nên trỏ đến gói chứng chỉ đã được sắp xếp lại của bạn. Tệp duy nhất này hiện xử lý cả chứng chỉ tên miền và chuỗi chứng chỉ.
<VirtualHost *:443>
ServerName example.com
SSLEngine on
SSLCertificateFile /etc/apache2/ssl/bundle.crt
SSLCertificateKeyFile /etc/apache2/ssl/example.com.key
</VirtualHost>
Chạy apachectl configtest để xác nhận mọi thứ đều hợp lệ. Nếu bạn thấy Syntax OK, hãy khởi động lại dịch vụ: systemctl restart apache2.
Xác nhận kết quả
Khi máy chủ của bạn hoạt động trở lại, hãy xác minh chuỗi chứng chỉ từ bên ngoài. Bạn có thể sử dụng trình duyệt, nhưng công cụ openssl s_client sẽ cung cấp nhiều chi tiết hơn:
openssl s_client -connect localhost:443 -showcerts
Tìm phần "Certificate chain". Bạn sẽ thấy tên miền của mình ở cấp độ 0 và chứng chỉ trung gian ở cấp độ 1. Nếu trình tự này hiển thị đúng, lỗi "diff orders" của bạn đã được giải quyết triệt để.

