Sửa lỗi error:0906D06C:PEM routines:PEM_read_bio:no start line Khi File PEM Bị Lỗi Định Dạng

intermediate🔒 SSL/TLS2026-06-20| Linux / macOS / Windows WSL — OpenSSL 1.0.x, 1.1.x, 3.x — mọi công cụ đọc file PEM (nginx, Apache, curl, Python ssl, Node.js tls)

Error Message

error:0906D06C:PEM routines:PEM_read_bio:no start line
#openssl#pem#ssl-tls

Tình huống

2 giờ sáng. Bạn đang triển khai chứng chỉ TLS mới trên server. Bạn chạy lệnh reload và nhận được:

error:0906D06C:PEM routines:PEM_read_bio:no start line

nginx từ chối khởi động. Website bị sập. OpenSSL không thể phân tích file chứng chỉ — nhưng file rõ ràng vẫn đang nằm trên đĩa. Chuyện gì đã xảy ra?

OpenSSL đã quét file nhưng không tìm thấy header như -----BEGIN CERTIFICATE-----. Điều này có nghĩa là file bị sai định dạng hoàn toàn, bị hỏng trong quá trình truyền, dính mã hóa rác, hoặc đơn giản là không phải file mà config của bạn đang trỏ đến.

Chẩn đoán nhanh

Chạy ba bước kiểm tra này trước — chúng sẽ thu hẹp nguyên nhân trong vòng chưa đầy một phút:

# Kiểm tra dòng đầu tiên — phải là header -----BEGIN ... -----
head -1 /etc/ssl/certs/server.crt

# Kiểm tra mã hóa file và BOM
file /etc/ssl/certs/server.crt

# Thử phân tích bằng OpenSSL
openssl x509 -in /etc/ssl/certs/server.crt -text -noout 2>&1 | head -5

Nếu head -1 trả về ký tự rác, dòng trống, hoặc dữ liệu nhị phân thô — đó chính là nguyên nhân rồi.

Nguyên nhân và cách khắc phục

Nguyên nhân 1: File ở định dạng DER, không phải PEM

DER là mã hóa nhị phân của cùng dữ liệu chứng chỉ. Các tổ chức cấp chứng chỉ — và các công cụ như keytool của Java — mặc định xuất ra định dạng DER. Dấu hiệu nhận biết rõ nhất: file bắt đầu bằng byte nhị phân, không phải -----BEGIN. Các đuôi file như .cer.der cũng là gợi ý mạnh.

Xác nhận file là DER:

file server.crt
# Kết quả: server.crt: data  (nhị phân, không phải ASCII)

Chuyển đổi DER sang PEM:

# Với chứng chỉ
openssl x509 -inform DER -in server.crt -out server.pem

# Với private key
openssl rsa -inform DER -in server.key -out server.key.pem

# Với gói PKCS#12 (.p12 / .pfx)
openssl pkcs12 -in bundle.p12 -out server.pem -nodes

Nguyên nhân 2: File có BOM (Byte Order Mark)

Notepad và nhiều công cụ trên Windows thường âm thầm thêm BOM UTF-8 (\xEF\xBB\xBF) vào đầu file khi lưu. Ba byte vô hình trước -----BEGIN là đủ để phá vỡ hoàn toàn quá trình phát hiện header của OpenSSL.

Kiểm tra BOM:

xxd server.pem | head -1
# Nếu thấy: ef bb bf 2d 2d 2d 2d 2d  — đó là BOM trước các dấu gạch ngang

Xóa BOM:

sed -i '1s/^\xEF\xBB\xBF//' server.pem

Nguyên nhân 3: Ký tự xuống dòng kiểu Windows (CRLF)

Các file được chỉnh sửa bằng công cụ Windows thường có ký tự xuống dòng \r\n thay vì \n. OpenSSL mong đợi ký tự xuống dòng kiểu Unix và sẽ bị lỗi với ký tự carriage return thừa.

# Kiểm tra ký tự carriage return
cat -A server.pem | head -3
# ^M ở cuối dòng = \r đang có mặt

# Sửa bằng dos2unix
dos2unix server.pem
# Hoặc không cần dos2unix:
sed -i 's/\r//' server.pem

Nguyên nhân 4: File rỗng hoặc sai đường dẫn

Đáng loại trừ sớm: một lệnh scp bị lỗi, biến môi trường $CERT_PATH cấu hình sai, hoặc typo trong config có thể âm thầm trỏ nginx đến một file rỗng hoặc không tồn tại. Lỗi trả về trông giống hệt như với chứng chỉ bị hỏng.

# Kiểm tra kích thước file
ls -lh server.pem
# 0 bytes = file rỗng

# Kiểm tra file nào ứng dụng thực sự đang đọc
strace -e openat nginx -t 2>&1 | grep pem
# Hoặc kiểm tra trực tiếp config của bạn
nginx -T | grep ssl_certificate

Nguyên nhân 5: Chuỗi chứng chỉ PEM bị thiếu

Nhiều cấu hình cần toàn bộ chuỗi — chứng chỉ lá cộng với CA trung gian. Một lần paste bị cắt ngắn hoặc thiếu CA trung gian gây ra lỗi này đáng tin cậy như với file bị hỏng.

# Đếm số chứng chỉ trong file
grep -c 'BEGIN CERTIFICATE' server.pem

# Xem chi tiết từng chứng chỉ trong gói
openssl crl2pkcs7 -nocrl -certfile server.pem | openssl pkcs7 -print_certs -text -noout | grep Subject

Tái tạo chuỗi nếu cần:

cat server.crt intermediate.crt root.crt > fullchain.pem

Nguyên nhân 6: Private key và chứng chỉ bị hoán đổi

nginx và Apache dùng các chỉ thị riêng biệt cho chứng chỉ và key. Nhầm đường dẫn là lỗi dễ mắc — và thông báo lỗi của OpenSSL sẽ không cho bạn biết đó là vấn đề.

# Xác nhận file nào là file nào
openssl x509 -in server.pem -noout -subject 2>/dev/null && echo "Đây là chứng chỉ"
openssl rsa -in server.pem -noout -check 2>/dev/null && echo "Đây là private key"

Xác minh

Sau khi áp dụng bất kỳ cách sửa nào, hãy xác minh OpenSSL có thể phân tích file thành công trước khi khởi động lại server:

# Chứng chỉ
openssl x509 -in server.pem -text -noout
# Sẽ in ra: Subject:, Issuer:, Validity:, v.v.

# Private key
openssl rsa -in server.key -check
# Sẽ in ra: RSA key ok

# Kiểm tra chứng chỉ và key khớp nhau (modulus phải giống hệt nhau)
openssl x509 -noout -modulus -in server.pem | openssl md5
openssl rsa -noout -modulus -in server.key | openssl md5
# Cả hai dòng phải cho cùng một hash

# Kiểm tra toàn bộ cấu hình TLS (ví dụ nginx)
nginx -t
# nginx: configuration file /etc/nginx/nginx.conf test is successful

Giải pháp lâu dài: Checklist xử lý chứng chỉ

  • Truyền file chứng chỉ bằng scp hoặc secrets manager — không bao giờ copy-paste qua terminal hay text editor.
  • Đã chỉnh sửa chứng chỉ trên máy Windows? Chạy dos2unix ngay khi file đặt lên server.
  • Sau mỗi lần xuất từ CA, xác thực bằng openssl x509 -in file -noout -subject — chỉ mất hai giây và tránh được sự cố lúc nửa đêm.
  • Giữ chứng chỉ, key và chuỗi CA trong các file riêng biệt. Chỉ ghép thành fullchain khi ứng dụng yêu cầu rõ ràng.
  • Trong CI/CD, thêm bước pre-deploy chạy openssl verify trước khi reload nginx hoặc Apache. Phát hiện chứng chỉ lỗi ngay trong pipeline, không phải trên production.

Ngữ cảnh Python / Node.js

Lỗi tương tự xuất hiện trong log ứng dụng khi code của bạn tải chứng chỉ trực tiếp:

# Python: ssl.SSLError bọc cùng lỗi OpenSSL
import ssl
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
ctx.load_cert_chain('/path/to/server.pem', '/path/to/server.key')
# Ném ra ssl.SSLError: [SSL] PEM lib (_ssl.c:4045) nếu file bị lỗi

# Node.js: cùng nền tảng OpenSSL
https.createServer({
  cert: fs.readFileSync('/path/to/server.pem'),  // Sẽ ném lỗi nếu file bị lỗi
  key: fs.readFileSync('/path/to/server.key'),
})

Cùng nguyên nhân gốc, cùng cách sửa. Hãy chạy openssl x509 -in server.pem -noout -subject trên file trước — nếu OpenSSL từ chối nó ở dòng lệnh, ứng dụng của bạn cũng sẽ từ chối nó.

Related Error Notes