Перестали работать запросы в WordPress: cURL error 60: SSL certificate has expired

C 30 сентября 2021 года на сайтах WordPress, для которых был установлен сертификат Let's Encrypt, могут перестать работать HTTP API запросы.

Например такой запрос будет выдавать ошибку:

$res = wp_remote_get( 'https://wp-kama.ru/' );

if( is_wp_error( $res ) ){
	echo $res->get_error_message();
}

Получим:

cURL error 60: SSL certificate problem: certificate has expired

Такую ошибку можно будет увидеть где угодно, например:

  • в админке при проверке обновлений WordPress
  • при проверке обновлений плагинов
  • при обращении к апи любого сервиса. Например, перестанет работать плагин TinyPNG — JPEG, PNG & WebP image compression и куча других, которые используют какие бы то ни было запросы.

Почему мы видим ошибку certificate has expired?

Почему так происходит подробно расписано на хабре.

Если коротко, то в ядре WP есть файл корневых сертификатов /wp-includes/certificates/ca-bundle.crt который используется для проверки SSL всех запросов созданных через HTTP API. В этом файле просрочен один из корневых сертификатов на основе которого был создан сертификат для вашего сайта. Поэтому запрос не может пройти проверку и выдается такая ошибка.

С очередными обновлениями WP эта ошибка должна пропасть, но вот что делать если решение нужно уже сегодня, или если вы не планируете обновлять WordPress, а рабочие HTTP запросы нужны.

Решение ошибки: cURL error 60: SSL certificate has expired

Вариант 1

Нужно обновить контент файла /wp-includes/certificates/ca-bundle.crt изменить его на контент этого файла https://curl.haxx.se/ca/cacert.pem.

Изменять в данном случае файл ядра допустимо, потому что при следующем обновлении WP проблема исчезнет. См. соответствующий коммит на GitHub.

Это можно сделать вручную:

  1. Скачайте файл по ссылке https://curl.haxx.se/ca/cacert.pem.
  2. Обновите контент /wp-includes/certificates/ca-bundle.crt контентом из скаченного файла.

Или используйте следующий код

Использовать код удобно, когда у вас есть возможность запустить код из админки или как-то еще, например через плагин Code Snippets.

Добавьте следующий код куда угодно и перейдите на страницу http://ВАШСАЙТ.com/?update-wp-ca-bundle.

/**
 * Goto http://yoursite.com/?update-wp-ca-bundle
 */
if( isset( $_GET['update-wp-ca-bundle'] ) ){

	$crt_file = ABSPATH . WPINC . '/certificates/ca-bundle.crt';
	$new_crt_url = 'https://curl.haxx.se/ca/cacert.pem';

	if( is_writable( $crt_file ) ){
		$new_str = file_get_contents( $new_crt_url );

		if( $new_str && strpos( $new_str, 'Bundle of CA Root Certificates' ) ){
			$up = file_put_contents( $crt_file, $new_str );

			echo $up ? 'OK: ca-bundle.crt updated' : 'ERROR: can`t put data to ca-bundle.crt';
		}
		else {
			echo 'ERROR: cant download https://curl.haxx.se/ca/cacert.pem';
		}
	}
	else {
		echo 'ERROR: ca-bundle.crt not writable';
	}

	exit;
}

После использования, код нужно удалить.

Вариант 2

Решить проблему можно через хук http_request_args. Этот хук нужно использовать в MU плагине.

  1. Создайте файл loader.php в папке wp-content/mu-plugins (если такой папки у вас нет, создайте её).

  2. Добавьте следующий код в этот файл:

    <?php
    
    require_once __DIR__ .'/fix-wp-ca-bundle/main.php';
  3. Создайте папку wp-content/mu-plugins/fix-wp-ca-bundle.

  4. Создайте файлы: main.php и ca-bundle.crt в папке fix-wp-ca-bundle.

    Добавьте следующий код в эти файлы.

    Код файла main.php:

    <?php
    
    defined( 'ABSPATH' ) || exit;
    
    /**
     * Update the path to the WordPress trusted root certificates.
     *
     * Actual certificates can be downloaded at this link: http://curl.haxx.se/ca/cacert.pem
     */
    add_filter( 'http_request_args', 'http_request_change_sslsertificates' );
    
    function http_request_change_sslsertificates( $parsed_args ){
    
    	$parsed_args[ 'sslcertificates' ] = __DIR__ . '/ca-bundle.crt';
    
    	return $parsed_args;
    }

    Контент файла ca-bundle.crt:

    Скопируйте контент этого файла http://curl.haxx.se/ca/cacert.pem

Должна получится такая структура:

Готово! Теперь все должно работать как и прежде.