TL;DR
Máy chủ của bạn đang thiếu hoặc có file CA bundle (Certificate Authority) lỗi thời, khiến WordPress không thể xác minh chứng chỉ SSL của máy chủ từ xa. Trên VPS, cập nhật gói ca-certificates chỉ mất khoảng 30 giây và giải quyết vĩnh viễn vấn đề. Trên shared hosting, bạn cần trỏ cURL đến một CA bundle mới theo cách thủ công — hoặc tạm thời tắt xác minh SSL trên máy dev local mà thôi.
Nguyên nhân gây ra lỗi
WordPress liên tục gọi đến các URL bên ngoài — cổng thanh toán, REST API, máy chủ license, nguồn thông tin thời tiết. Mỗi lần gọi đều đi qua wp_remote_get() hoặc wp_remote_post(), bên trong sử dụng cURL của PHP. cURL kiểm tra chứng chỉ SSL của máy chủ từ xa với danh sách các root CA đáng tin cậy được lưu trên máy chủ của bạn. Danh sách đó bị lỗi thời, bị thiếu, hoặc trỏ sai file? Bạn sẽ gặp:
cURL error 60: SSL certificate problem: unable to get local issuer certificate
Các nguyên nhân phổ biến:
- VPS mới cài đặt với image OS tối giản (chưa cài gói
ca-certificates) - Shared hosting cũ với CA bundle lỗi thời — root cert của Let's Encrypt đã thay đổi vào tháng 9 năm 2021 và làm hỏng nhiều máy chủ cũ hơn
- PHP được biên dịch với
--with-curltrỏ đếncacert.pemsai hoặc bị thiếu - Môi trường dev local trên Windows (XAMPP và WAMP không đi kèm CA bundle hệ thống)
- Docker container được build từ base image slim như
debian:slimhoặcalpine
Chẩn đoán trước
Vội vàng thay đổi cài đặt một cách mù quáng chỉ tốn thêm thời gian. Hãy dành 60 giây xác nhận xem vấn đề có thực sự nằm ở CA bundle hay không — hay là chứng chỉ tự ký, URL từ xa bị lỗi, hoặc cấu hình PHP không khớp.
SSH vào máy chủ và chạy:
curl -v https://api.example.com 2>&1 | grep -E 'SSL|certificate|issuer'
Nếu bạn thấy unable to get local issuer certificate ở cấp OS, thì CA bundle hệ thống là thủ phạm. Nếu curl chạy tốt nhưng WordPress thì không, cURL của PHP được cấu hình riêng biệt với cURL hệ thống — hãy kiểm tra xem nó đang trỏ đến đâu:
php -r "echo curl_version()['ssl_version'];"
php -r "$ch = curl_init('https://api.example.com'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_exec($ch); var_dump(curl_error($ch));"
Cách sửa 1: Cập nhật CA certificates hệ thống (VPS / quyền root)
Nếu bạn có quyền root hoặc sudo trên máy chủ, hãy thực hiện bước này trước. Nó giải quyết vấn đề ở cấp độ OS — nghĩa là mọi ứng dụng PHP trên máy chủ đều được hưởng lợi, không chỉ riêng WordPress.
Ubuntu / Debian:
sudo apt-get update
sudo apt-get install --reinstall ca-certificates
sudo update-ca-certificates
CentOS / RHEL / AlmaLinux:
sudo yum update ca-certificates
# hoặc trên các hệ thống mới hơn:
sudo dnf update ca-certificates
Sau khi cập nhật, khởi động lại PHP-FPM hoặc Apache để PHP nhận bundle mới:
# PHP-FPM
sudo systemctl restart php8.1-fpm
# Apache với mod_php
sudo systemctl restart apache2 # Debian/Ubuntu
sudo systemctl restart httpd # CentOS/RHEL
Kích hoạt lại lệnh gọi API đang bị lỗi từ WordPress để xác nhận đã được khắc phục.
Cách sửa 2: Trỏ cURL của PHP đến cacert.pem mới
Không có quyền root? Cách này hoạt động trên shared hosting, managed container, và mọi môi trường mà bạn không thể chỉnh sửa gói hệ thống.
Tải CA bundle chính thức của Mozilla do nhóm curl.se duy trì và cập nhật liên tục trong năm:
cd /path/to/your/wordpress
wget https://curl.se/ca/cacert.pem -O cacert.pem
Cấu hình PHP sử dụng file này. Trong php.ini:
[curl]
curl.cainfo = /path/to/your/wordpress/cacert.pem
[openssl]
openssl.cafile = /path/to/your/wordpress/cacert.pem
Không chỉnh sửa được php.ini? Thêm đoạn này vào wp-config.php trước dòng require:
// Trỏ cURL đến CA bundle đáng tin cậy
define( 'CURL_CA_BUNDLE', __DIR__ . '/cacert.pem' );
Sau đó tạo một must-use plugin để hook vào các HTTP request của WordPress:
<?php
// mu-plugins/fix-curl-ca.php
add_action( 'http_api_curl', function( $handle ) {
if ( defined( 'CURL_CA_BUNDLE' ) && file_exists( CURL_CA_BUNDLE ) ) {
curl_setopt( $handle, CURLOPT_CAINFO, CURL_CA_BUNDLE );
}
} );
Cách sửa 3: Chỉ dùng trên môi trường dev local — tắt xác minh SSL
Tuyệt đối không dùng cách này trên môi trường production. Tắt xác minh chứng chỉ khiến site của bạn dễ bị tấn công man-in-the-middle, nơi kẻ tấn công có thể chặn và chỉnh sửa các phản hồi API.
Dành cho môi trường XAMPP, WAMP, hoặc Docker local mà bạn chỉ cần bỏ chặn để tiếp tục phát triển:
// Chỉ dùng trong wp-config.php trên máy local
add_filter( 'https_ssl_verify', '__return_false' );
add_filter( 'https_local_ssl_verify', '__return_false' );
Hoặc truyền trực tiếp khi thực hiện lệnh gọi API:
$response = wp_remote_get( 'https://api.example.com/data', [
'sslverify' => false, // chỉ dùng khi dev!
] );
Cách sửa 4: Máy chủ từ xa có chứng chỉ lỗi
Đôi khi vấn đề không nằm ở phía bạn. Chính API từ xa có chứng chỉ tự ký hoặc chuỗi chứng chỉ không đầy đủ. Kiểm tra bằng lệnh:
openssl s_client -connect api.example.com:443 -showcerts 2>/dev/null | openssl x509 -noout -issuer -subject -dates
Nếu issuer và subject giống hệt nhau, đó là chứng chỉ tự ký. Chuỗi không đầy đủ thường có nghĩa là máy chủ từ xa thiếu intermediate cert. Các lựa chọn của bạn:
- Liên hệ nhà cung cấp API — cấu hình chứng chỉ của họ đang bị lỗi
- Thêm root cert của họ vào kho tin cậy của máy chủ bạn
- Dùng
CURLOPT_CAINFOtrỏ đến file chỉ chứa cert của họ (chỉ thực tế với các API nội bộ do bạn kiểm soát)
Xác minh đã sửa xong
Đừng giả định là đã xong. Dán đoạn code này vào một plugin thử nghiệm hoặc tạm thời vào functions.php của theme, sau đó tải trang khi đang đăng nhập với quyền admin:
// Dán tạm vào một plugin thử nghiệm hoặc functions.php của theme
add_action( 'init', function() {
if ( ! current_user_can( 'manage_options' ) ) return;
$response = wp_remote_get( 'https://api.example.com/endpoint' );
if ( is_wp_error( $response ) ) {
error_log( 'Vẫn còn lỗi: ' . $response->get_error_message() );
} else {
error_log( 'HTTP status: ' . wp_remote_retrieve_response_code( $response ) );
}
} );
Kiểm tra wp-content/debug.log — bật WP_DEBUG_LOG trong wp-config.php nếu chưa có. HTTP 200 nghĩa là bạn đã xong. Nhớ xóa đoạn code này sau đó.
Thích dùng dòng lệnh hơn? Kiểm tra cURL của PHP trực tiếp:
php -r "
\$ch = curl_init('https://api.example.com');
curl_setopt(\$ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt(\$ch, CURLOPT_VERBOSE, 1);
curl_exec(\$ch);
echo curl_error(\$ch);
curl_close(\$ch);
"
Ghi chú nhanh
- File
cacert.pemtừ curl.se được làm mới nhiều lần trong năm. Nếu bạn dùng Cách sửa 2, hãy đặt nhắc nhở lịch để tải lại mỗi 6 tháng — bundle lỗi thời sẽ lại gây rắc rối cho bạn. - Root cert cũ của Let's Encrypt (DST Root CA X3) đã hết hạn vào ngày 30 tháng 9 năm 2021. Các máy chủ vẫn đang chạy Ubuntu 16.04 hoặc CentOS 6 chỉ tin tưởng root LE đó, đó là lý do hàng chục API được bảo mật bằng LE đột nhiên bắt đầu bị lỗi trên các máy chủ đó vào khoảng thời gian đó.
- Docker: thêm
RUN apt-get install -y ca-certificatesvào Dockerfile của bạn. Các base image slim nhưdebian:slimbỏ qua gói này theo thiết kế. - Cloudways, Kinsta, WP Engine: mở ticket hỗ trợ. Bạn không thể tự cập nhật gói hệ thống, nhưng đội ops của họ có thể làm mới CA bundle trên node — thường hoàn tất trong vài giờ.

