WordPress

Guía definitiva para solucionar el cURL Error 28: Operation Timed Out en WordPress

Introducción al cURL Error 28 en WordPress

El mensaje cURL error 28: Operation timed out after x milliseconds with y bytes received es una de las incidencias técnicas más complejas de diagnosticar en el ecosistema de WordPress. Esta falla se produce cuando el servidor donde está alojado tu sitio web intenta realizar una petición HTTP/HTTPS saliente mediante la biblioteca libcurl y no recibe una respuesta dentro del límite de tiempo predefinido.

Dado que el núcleo de WordPress depende de solicitudes de bucle de retorno (loopback requests) para ejecutar tareas programadas via Cron, validar la REST API, verificar actualizaciones del Core y comunicarse con plugins de terceros (como pasarelas de pago o herramientas SEO), el bloqueo de cURL 28 paraliza funciones críticas. En la herramienta de Salud del Sitio (Site Health), esto suele manifestarse con errores como 'La API REST encontró un error' o 'Tu sitio no pudo completar una solicitud de bucle de retorno'.

Análisis exhaustivo de las causas raíz del error

Para solucionar de forma definitiva el cURL error 28, es fundamental comprender qué mecanismo de la infraestructura está provocando la interrupción de la conexión. Las causas principales incluyen:

  • Latencia o fallos en la resolución DNS: Si el resolvedor DNS de tu servidor (nameservers localizados en /etc/resolv.conf) tarda demasiado en traducir un nombre de dominio a su dirección IP, el tiempo asignado a cURL se agota antes de iniciar la transferencia de datos.
  • Bloqueos por Firewall de Red o WAF: Reglas estrictas en iptables, UFW, ModSecurity o Firewalls de Aplicación Web (WAF) como Cloudflare pueden interceptar o soltar (drop) los paquetes de las peticiones loopback o salientes del servidor.
  • Conflictos con la pila de red IPv6: En servidores donde IPv6 está habilitado pero mal configurado en el enrutamiento, cURL intentará conectar primero a través de IPv6, esperará el tiempo límite antes de fallar y recién intentará la conexión por IPv4.
  • Recursos PHP-FPM y configuraciones de timeout reducidas: Directivas de PHP extremadamente restrictivas en default_socket_timeout o max_execution_time cortan los sockets abiertos prematuramente.
  • Sobrepartición de peticiones por plugins de terceros: Plugins que realizan llamadas externas síncronas no optimizadas hacia APIs remotas lentas o caídas.

Método 1: Optimización de límites de tiempo en PHP y la API HTTP de WordPress

El primer paso técnico consiste en ampliar las tolerancias de tiempo de espera tanto a nivel de la configuración global de PHP como en las capas internas del framework de WordPress.

Ajuste de variables en php.ini / .htaccess

Si tienes acceso al archivo php.ini de tu entorno de hospedaje, incrementa los socket timeouts y tiempos de ejecución agregando o modificando las siguientes directivas:

max_execution_time = 60
memory_limit = 256M
default_socket_timeout = 60

En servidores web Apache donde no tengas acceso directo a la configuración global de PHP, puedes insertar estas directivas en tu archivo .htaccess ubicado en la raíz del sitio:

php_value max_execution_time 60
php_value default_socket_timeout 60

Aumento del Timeout de cURL mediante un Plugin Imprescindible (MU-Plugin)

WordPress impone por defecto un tiempo de espera muy reducido (normalmente 5 segundos) para peticiones no bloqueantes. Puedes forzar un tiempo de espera mayor para todas las solicitudes HTTP salientes creando un archivo de código personalizado.

  1. Accede a tu servidor vía FTP o SSH y navega hasta el directorio wp-content/mu-plugins/ (si la carpeta mu-plugins no existe, créala).
  2. Crea un archivo llamado incrementar-curl-timeout.php e inserta el siguiente fragmento de código PHP:
<?php
/*
Plugin Name: Incrementar Timeout de cURL HTTP API
Description: Aumenta el tiempo de espera predeterminado de las peticiones HTTP de WordPress para corregir el cURL Error 28.
*/

add_filter('http_request_args', function($args, $url) {
    $args['timeout'] = 30;
    return $args;
}, 10, 2);

add_action('http_api_curl', function($handle) {
    curl_setopt($handle, CURLOPT_CONNECTTIMEOUT, 30);
    curl_setopt($handle, CURLOPT_TIMEOUT, 30);
}, 10, 1);

Método 2: Diagnóstico por terminal SSH y forzado de resolución IPv4

Si el problema persiste tras aumentar los tiempos de espera, la causa suele ser la latencia al intentar resolver peticiones salientes sobre IPv6. Puedes verificar el comportamiento de cURL directamente mediante la CLI del servidor.

Prueba de conectividad cURL desde el servidor

Conéctate por SSH a tu servidor y ejecuta el siguiente comando para medir el tiempo total de respuesta hacia la API de WordPress:

curl -w "\nTiempo total: %{time_total}s\n" -o /dev/null -s https://api.wordpress.org/secret-key/1.1/salt/

Si el comando se demora más de 5 a 10 segundos o arroja un error explícito de timeout, intenta realizar la misma petición forzando la pila IPv4 mediante la bandera -4:

curl -4 -w "\nTiempo total: %{time_total}s\n" -o /dev/null -s https://api.wordpress.org/secret-key/1.1/salt/

Si la petición con -4 responde instantáneamente, confirmas que el enrutamiento IPv6 del servidor está dañado. Para solucionar esto sin alterar todo el sistema operativo, puedes forzar a cURL a preferir siempre IPv4 dentro de WordPress agregando este hook en tu mu-plugins/incrementar-curl-timeout.php:

add_action('http_api_curl', function($handle) {
    curl_setopt($handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
}, 10, 1);

Método 3: Solución de bloqueos Loopback y resolución DNS Local

Las solicitudes loopback ocurren cuando el propio servidor web se hace una petición HTTP a sí mismo (por ejemplo, https://tusitio.com/wp-json/). Si el DNS externo no resuelve la IP interna correctamente o el firewall bloquea la propia IP pública del servidor, cURL generará el error 28.

Configuración del archivo /etc/hosts

En servidores VPS o dedicados (Unmanaged), una solución altamente eficaz es mapear el dominio localmente para evitar que la petición loopback salga a Internet y regrese.

  1. Abre la consola de comandos con privilegios de root o sudo: sudo nano /etc/hosts
  2. Añade la dirección de bucle local 127.0.0.1 apuntando a tu dominio principal:
127.0.0.1   tusitio.com www.tusitio.com
::1         tusitio.com www.tusitio.com

Guarda el archivo y reinicia el servicio web (sudo systemctl restart nginx o sudo systemctl restart apache2) junto con el demonio PHP-FPM (sudo systemctl restart php8.2-fpm). Esto garantiza latencia cero en peticiones internas.

Verificación de reglas de ModSecurity y WAF

Si utilizas Cloudflare o un Firewall de Aplicación Web a nivel de servidor como ModSecurity:

  • Cloudflare: Dirígete a Security > Events y comprueba si las peticiones provinientes de la IP de tu servidor están siendo desfiadas con CAPTCHA o bloqueadas. Si es así, crea una regla de pase directo (Skip / Allow) para la IP de origen de tu servidor.
  • ModSecurity: Inspecciona los registros de auditoría en /var/log/modsec_audit.log o en la sección de seguridad de cPanel para identificar si la regla 920350 o similar está matando las conexiones internas de cURL.

Método 4: Verificación de conflictos en plugins y depuración de la REST API

Si la infraestructura de red está limpia, el responsable de agotar la cola cURL suele ser un plugin específico que ejecuta llamadas síncronas bloqueantes durante la carga de las páginas del panel de administración.

Uso de WP-CLI para aislar componentes con fallas

Puedes listar la respuesta de la REST API mediante WP-CLI para identificar qué módulo provoca el retardo:

wp profile request --step=all --path=/var/www/html

Alternativamente, desactiva temporalmente todos los plugins mediante WP-CLI para comprobar si el Site Health se restaura de inmediato:

wp plugin deactivate --all

Luego reactiva los plugins uno a uno mientras ejecutas el comando wp doctor check rest-api-status hasta encontrar la extensión defectuosa que vuelve a desencadenar el cURL error 28.

Conclusión y Lista de Verificación

Corregir el error cURL 28 exige abordar tanto la pila de software de WordPress como la infraestructura de red subyacente. Para garantizar que tu sitio web no vuelva a experimentar cuellos de botella en las comunicaciones HTTP salientes, asegúrate de mantener actualizadas las librerías OpenSSL y libcurl del servidor, forzar la resolución IPv4 en los transportes de WordPress y verificar que la IP interna del servidor tenga vía libre en cualquier firewall activo.