Sửa lỗi SSL 'cannot load certificate' của Nginx khi khởi động hoặc reload

intermediate Nginx2026-04-20| Nginx 1.18+ trên Ubuntu 20.04/22.04, Debian 11/12, CentOS 7/8, RHEL — mọi hệ thống Linux chạy Nginx với SSL/TLS

Error Message

nginx: [emerg] cannot load certificate "/etc/nginx/ssl/cert.pem": BIO_new_file() failed (SSL: error:02001002:system library:fopen:No such file or directory)
#nginx#ssl#tls#chứng chỉ#https

Lỗi Gặp Phải

Nginx từ chối khởi động hoặc reload, và bạn thấy thông báo này trong logs:

nginx: [emerg] cannot load certificate "/etc/nginx/ssl/cert.pem": BIO_new_file() failed (SSL: error:02001002:system library:fopen:No such file or directory)

Đường dẫn trong thông báo lỗi khớp với giá trị bạn đặt trong ssl_certificate của file cấu hình Nginx. Lời gọi OpenSSL bên dưới là BIO_new_file() đã thất bại. Điều này thường có ba nguyên nhân: file không tồn tại tại đường dẫn đó, Nginx không đọc được file, hoặc đường dẫn bị sai.

Nguyên Nhân Gốc Rễ

  • File certificate đơn giản là không tồn tại tại đường dẫn đã cấu hình
  • Đường dẫn trong nginx.conf bị gõ nhầm hoặc trỏ đến vị trí sai
  • File tồn tại nhưng thuộc sở hữu của root và không thể đọc được bởi user www-data / nginx
  • Symlink trỏ đến cert bị hỏng (thường xảy ra sau khi gia hạn Let's Encrypt)
  • Cert được lưu trên một volume được mount mà chưa được mount tại thời điểm khởi động

Cách Sửa 1: Xác Nhận File Có Thực Sự Tồn Tại Không

Bắt đầu từ điều đơn giản nhất — file có thực sự tồn tại tại đường dẫn đó không?

ls -la /etc/nginx/ssl/cert.pem

Nếu lệnh trả về No such file or directory, file đang bị thiếu. Hãy kiểm tra xem certificate của bạn thực sự nằm ở đâu:

# Cert của Let's Encrypt nằm ở đây:
ls -la /etc/letsencrypt/live/yourdomain.com/

# Output thường thấy của Certbot / acme.sh:
# cert.pem  chain.pem  fullchain.pem  privkey.pem

Đang dùng Let's Encrypt? Hãy trỏ ssl_certificate đến fullchain.pem, không phải cert.pem. Nginx cần toàn bộ chuỗi certificate — chỉ có cert lá sẽ gây lỗi TLS handshake với hầu hết các client. Private key thì trỏ đến privkey.pem:

ssl_certificate     /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;

Cách Sửa 2: Sửa Lại Đường Dẫn Trong Cấu Hình Nginx

Quét toàn bộ file cấu hình Nginx để tìm directive ssl_certificate:

grep -r 'ssl_certificate' /etc/nginx/

Sau đó cập nhật lại các đường dẫn cho khớp với vị trí thực tế của cert. Ví dụ với cert tự quản lý lưu trong /etc/nginx/ssl/:

server {
    listen 443 ssl;
    server_name yourdomain.com;

    ssl_certificate     /etc/nginx/ssl/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/privkey.pem;

    # ... phần cấu hình còn lại
}

Sau khi chỉnh sửa, hãy luôn kiểm tra cú pháp trước khi reload:

nginx -t

Cách Sửa 3: Tạo Thư Mục SSL Và Sao Chép Cert Vào

Có cert từ một CA thương mại (ví dụ họ gửi cho bạn file .crt qua email)? Hãy đặt nó vào đúng chỗ:

# Tạo thư mục nếu chưa có
mkdir -p /etc/nginx/ssl

# Sao chép các file certificate
cp yourdomain.crt /etc/nginx/ssl/cert.pem
cp yourdomain.key /etc/nginx/ssl/privkey.pem

# Đặt quyền truy cập hạn chế
chmod 600 /etc/nginx/ssl/privkey.pem
chmod 644 /etc/nginx/ssl/cert.pem
chown root:root /etc/nginx/ssl/privkey.pem

Cách Sửa 4: Kiểm Tra Symlink Bị Hỏng (Let's Encrypt)

Let's Encrypt lưu cert đang dùng dưới dạng symlink trỏ vào /etc/letsencrypt/archive/. Một lần gia hạn thất bại có thể để lại symlink trỏ đến file không còn tồn tại:

# Kiểm tra xem symlink có hợp lệ không
ls -la /etc/letsencrypt/live/yourdomain.com/

# Symlink bị hỏng trông như thế này:
# cert.pem -> ../../archive/yourdomain.com/cert3.pem  (file không tồn tại)

# Xác minh các file trong archive có tồn tại không
ls -la /etc/letsencrypt/archive/yourdomain.com/

Nếu các file trong archive đã biến mất, hãy buộc gia hạn lại:

certbot renew --force-renewal -d yourdomain.com

Hoặc nếu bạn đang dùng acme.sh:

acme.sh --renew -d yourdomain.com --force

Cách Sửa 5: Sửa Quyền Truy Cập File

File đã có đó — nhưng Nginx không mở được. Hãy tìm xem Nginx worker đang chạy với user nào:

ps aux | grep nginx | grep -v grep
# Tìm user của tiến trình worker (www-data, nginx, hoặc nobody)

Sau đó kiểm tra xem user đó có thực sự đọc được cert không:

# Với Ubuntu/Debian (user www-data)
sudo -u www-data cat /etc/nginx/ssl/cert.pem

# Với CentOS/RHEL (user nginx)
sudo -u nginx cat /etc/nginx/ssl/cert.pem

Nếu bị từ chối truy cập, hãy điều chỉnh lại quyền. Cert có thể để mọi người đọc được; private key thì không nên:

chmod 644 /etc/nginx/ssl/cert.pem
chmod 640 /etc/nginx/ssl/privkey.pem
chown root:www-data /etc/nginx/ssl/privkey.pem

Với Let's Encrypt, Nginx còn cần quyền thực thi trên các thư mục live/archive/ để theo được symlink. Nếu thiếu quyền này, quá trình duyệt thư mục sẽ thất bại âm thầm:

chmod 755 /etc/letsencrypt/live/
chmod 755 /etc/letsencrypt/archive/
chmod 755 /etc/letsencrypt/archive/yourdomain.com/

Kiểm Tra Sau Khi Sửa

Trước khi động vào Nginx, hãy chạy kiểm tra cú pháp cấu hình:

nginx -t
# Kết quả mong đợi:
# nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
# nginx: configuration file /etc/nginx/nginx.conf test is successful

Khi đã qua được kiểm tra, hãy reload (hoặc restart nếu Nginx đã bị dừng hẳn):

# Reload instance đang chạy
systemctl reload nginx

# Hoặc restart nếu đã bị dừng
systemctl restart nginx

# Xác nhận đang chạy
systemctl status nginx

Giờ hãy xác nhận HTTPS hoạt động đúng từ đầu đến cuối:

curl -I https://yourdomain.com
# Nên trả về HTTP/2 200 (hoặc 301/302), không phải lỗi kết nối

# Kiểm tra thông tin chi tiết của certificate
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com < /dev/null 2>&1 | grep -E 'subject|issuer|expire'

Phòng Ngừa

  • Dùng đường dẫn tuyệt đối trong ssl_certificate — không bao giờ dùng đường dẫn tương đối.
  • Móc vào quá trình gia hạn cert: đặt một script chứa lệnh nginx -t && systemctl reload nginx vào thư mục /etc/letsencrypt/renewal-hooks/deploy/ để Nginx tự động reload sau mỗi lần gia hạn thành công.
  • Phát hiện lỗi gia hạn sớm: chạy certbot renew --dry-run trong một cron job hàng tuần — lệnh này mô phỏng quá trình gia hạn mà không thay thế gì cả, giúp bạn biết có lỗi trước khi nó gây ra downtime.
  • Tránh lưu cert trên các mount ngoài: nếu bắt buộc phải làm vậy, hãy thêm RequiresMountsFor= vào unit systemd của Nginx để nó chờ mount sẵn sàng trước khi khởi động.

Related Error Notes