« Blog

Chứng chỉ TLS hết hạn: nguyên nhân và cách phòng

Chứng chỉ hết hạn là sự cố rất phổ biến nhưng phòng được gần như hoàn toàn. Bài này liệt kê các nguyên nhân thật sự hay gặp (gia hạn tự động hỏng, quên nạp lại máy chủ, email nhắc gửi nhầm người) và cách đặt giám sát bằng openssl.

Chuyện gì xảy ra khi chứng chỉ hết hạn

Trình duyệt hiện cảnh báo đỏ toàn màn hình, phần lớn người đọc sẽ rời đi. Ứng dụng di động, API, máy quét mã vạch và các hệ thống khác kết nối tới website cũng báo lỗi. Nếu website đã bật HSTS thì người dùng thậm chí không có nút bỏ qua. Điều đáng nói là sự cố này gần như luôn phòng được.

Thời hạn chứng chỉ cũng đang ngắn dần. Theo Ballot SC-081 của CA/Browser Forum, thời hạn tối đa là 200 ngày từ 15/3/2026 (đã áp dụng), 100 ngày từ 15/3/2027 và 47 ngày từ 15/3/2029, nên chứng chỉ mua theo năm không còn tồn tại và gia hạn thủ công ngày càng khó theo kịp. Let's Encrypt hiện cấp chứng chỉ 90 ngày và theo thông báo của họ sẽ rút xuống 64 ngày từ 10/2/2027 rồi 45 ngày từ 16/2/2028 (lịch có thể thay đổi, hãy xem trang chính thức). Tự động hoá gia hạn là bắt buộc.

Những nguyên nhân hay gặp

  1. Gia hạn thủ công và quên. Chứng chỉ mua từ nhà cung cấp, người đặt mua đã nghỉ việc, email nhắc gửi vào hộp thư không ai đọc.
  2. Gia hạn tự động có nhưng đang hỏng âm thầm. Certbot cần chứng minh bạn kiểm soát tên miền. Nó hỏng khi cổng 80 bị tường lửa chặn, bản ghi DNS trỏ sang máy khác, cấu hình web đổi chỗ thư mục, hoặc plugin DNS dùng khoá API đã hết hạn.
  3. Đã gia hạn nhưng chưa nạp lại. Tệp chứng chỉ mới nằm trên đĩa, nhưng Nginx hay Apache vẫn giữ bản cũ trong bộ nhớ cho đến khi được nạp lại. Phổ biến nhất sau khi dùng certbot renew mà thiếu bước reload.
  4. Nhiều máy chủ. Chứng chỉ mới cài ở máy A nhưng máy B, bộ cân bằng tải hoặc máy dự phòng còn dùng bản cũ.
  5. Quên các điểm cuối khác. Website chính ổn nhưng mail.example.vn, api.example.vn, cổng VPN hay máy chủ nhận thư (cho MTA-STS) dùng chứng chỉ riêng chưa ai theo dõi.
  6. Thông báo không còn. Theo thông báo của Let's Encrypt, họ đã ngừng gửi email nhắc hết hạn từ giữa năm 2025, nên không thể dựa vào email đó làm lớp bảo hiểm.

Một lỗi liên quan nhưng khác bản chất: chứng chỉ sai tên (thiếu www), tự ký, hoặc thiếu chuỗi chứng chỉ trung gian. Trên Nginx hãy dùng fullchain.pem, không phải cert.pem, cho ssl_certificate.

Cách phòng, theo thứ tự ưu tiên

Bật gia hạn tự động và thử nó. Với certbot, chạy thử:

certbot renew --dry-run

Bảo đảm có bộ hẹn giờ chạy (systemctl list-timers | grep certbot) và thêm bước nạp lại tự động sau khi gia hạn. Cách bền nhất là tạo một tệp thực thi trong thư mục hook của certbot, vì certbot luôn chạy mọi hook ở đó sau mỗi lần gia hạn thành công:

#!/bin/sh
# /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh  (chmod +x)
systemctl reload nginx

(thay nginx bằng apache2 nếu cần). Đừng chỉ dựa vào certbot renew --deploy-hook: tuỳ chọn đó chỉ được lưu lại khi có chứng chỉ thật sự được gia hạn trong lần chạy đó. Đặt giám sát độc lập, vì cơ chế gia hạn có thể hỏng mà không ai biết. Một tập lệnh nhỏ chạy hằng ngày:

#!/bin/sh
host="example.vn"
if ! echo | openssl s_client -connect "$host:443" -servername "$host" 2>/dev/null \
     | openssl x509 -noout -checkend 1814400 >/dev/null 2>&1; then
  echo "Chung chi cua $host het han trong 21 ngay hoac khong doc duoc"
fi

Lệnh -checkend 1814400 kiểm tra chứng chỉ có hết hạn trong 21 ngày (1.814.400 giây) tới không; nếu có thì lệnh trả mã lỗi và tập lệnh in cảnh báo. Dòng >/dev/null 2>&1 ngăn openssl in "Certificate will not expire" mỗi lần chạy (nếu không, cron sẽ gửi email hằng ngày). Với chứng chỉ chỉ sống 45 đến 64 ngày, ngưỡng cảnh báo 21 ngày vẫn hợp lý. Gắn đầu ra vào email gửi đến một địa chỉ nhóm (không phải email cá nhân) hoặc một công cụ giám sát uptime. Cuối cùng, thêm một nhắc lịch trước hạn 30 ngày gắn với ít nhất hai người.

Theo nền tảng

Cloudflare. Chứng chỉ Universal SSL ở mặt trước (giữa Cloudflare và người đọc) do Cloudflare tự gia hạn. Nhưng chứng chỉ ở máy chủ gốc vẫn là việc của bạn; chế độ SSL/TLS nên là Full (strict) kèm chứng chỉ hợp lệ ở máy chủ gốc, ví dụ Let's Encrypt hoặc chứng chỉ Origin của Cloudflare (thời hạn dài, chỉ tin cậy với Cloudflare).

cPanel. Vào SSL/TLS Status, chọn tên miền và bấm Run AutoSSL. Kiểm tra AutoSSL đang bật (WHM hoặc nhờ nhà cung cấp hosting). AutoSSL không cấp được khi tên miền không còn trỏ về máy chủ này (ví dụ đã chuyển qua proxy hoặc dịch vụ khác).

DirectAdmin. Vào SSL Certificates, chọn Free & automatic certificate from Let's Encrypt, tích tên miền và www, bấm Save. Hệ thống tự gia hạn; vẫn nên xem lại ngày hết hạn sau khi thay đổi cấu hình.

Nginx. Sau khi gia hạn, kiểm tra cấu hình bằng nginx -t rồi nạp lại bằng systemctl reload nginx. Dùng ssl_certificate trỏ vào fullchain.pem.

Apache. Sau khi gia hạn, nạp lại bằng systemctl reload apache2 (hoặc httpd). Apache 2.4.8 trở lên dùng fullchain cho SSLCertificateFile; bản cũ hơn cần thêm SSLCertificateChainFile.

Cách tự kiểm tra

Xem ngày hết hạn, tên và nhà phát hành của chứng chỉ mà máy chủ đang thực sự phục vụ:

echo | openssl s_client -connect example.vn:443 -servername example.vn 2>/dev/null | openssl x509 -noout -dates -subject -issuer

Dòng notAfter là ngày hết hạn. Kiểm tra cả chuỗi chứng chỉ:

echo | openssl s_client -connect example.vn:443 -servername example.vn -verify_hostname example.vn 2>/dev/null | grep "Verify return code"

Kết quả mong muốn là Verify return code: 0 (ok). Tuỳ chọn -verify_hostname là bắt buộc để kiểm tra tên: thiếu nó, OpenSSL chỉ kiểm tra chuỗi chứng chỉ và vẫn báo 0 (ok) dù chứng chỉ không thuộc tên miền đó (-servername chỉ gửi tên cho máy chủ chọn chứng chỉ); khi tên sai bạn sẽ thấy 62 (hostname mismatch). Lặp lại cho mọi tên miền con đang dùng HTTPS. Hệ thống không nằm ở cổng 443 (máy chủ nhận thư, VPN) thì đổi cổng trong lệnh.

Nếu website đã bật HSTS, hãy đọc thêm bài HSTS: bật thế nào mà không tự khoá website để hiểu vì sao chứng chỉ hết hạn lúc này nghiêm trọng hơn.

Nguồn tham khảo

  1. Let's Encrypt: tài liệu
  2. Certbot: hướng dẫn cài đặt
  1. MTA-STS và TLS-RPT cho người mới

    · 5 phút đọc

    MTA-STS buộc các máy chủ gửi thư tới bạn phải dùng kết nối mã hoá, TLS-RPT gửi báo cáo khi có lỗi. Bài này giải thích cách hoạt động, cách triển khai an toàn ở chế độ testing và những chỗ hay sai.

    #email #mta-sts #tls

  2. HSTS: bật thế nào mà không tự khoá website

    · 4 phút đọc

    HSTS buộc trình duyệt luôn dùng HTTPS cho website của bạn, nhưng đặt sai có thể khiến cả tên miền con hoặc cả website không truy cập được. Bài này đưa ra lộ trình tăng max-age từng bước và cách bật trên Nginx, Apache, cPanel, DirectAdmin, Cloudflare.

    #web #https #hsts

  3. Content-Security-Policy và các security header cơ bản

    · 4 phút đọc

    Security header là nội quy website gửi cho trình duyệt. Bài này giải thích các header cơ bản (nosniff, frame-ancestors, Referrer-Policy, Permissions-Policy) và cách đưa CSP vào dần dần bằng chế độ Report-Only, kèm cấu hình cho Nginx, Apache, .htaccess, Cloudflare.

    #web #csp #headers