# cURL error 28: Operation timed out sur WordPress : solutions

> « cURL error 28: Operation timed out » dans la Santé du site ou les mises à jour WordPress : testez la requête sortante, DNS, pare-feu, boucle locale et délai.

- Auteur : WordPress Développement
- Publié le : 2026-10-02
- Mis à jour le : 2026-10-02
- URL : https://www.wpmoderne.fr/erreurs-wordpress/curl-error-28/

> Une requête sortante de WordPress (mises à jour, API, requête de bouclage) n’a pas obtenu de réponse dans le délai de 5 secondes. Testez la requête avec curl depuis le serveur : pare-feu sortant, DNS ou IPv6 lent, service distant ou boucle bloquée.

Dans l’écran « Santé du site », sous « Mises à jour » ou dans le journal d’erreurs, vous lisez « cURL error 28: Operation timed out after 5001 milliseconds with 0 bytes received ». Selon l’endroit, il s’accompagne d’un test critique (« Votre site n’a pas pu terminer la requête de bouclage »), d’un message « Impossible de rejoindre WordPress.org », de mises à jour qui ne se détectent plus, de tâches planifiées qui ne se lancent pas, ou d’une extension qui n’arrive pas à joindre son service distant.

Il s’agit d’une erreur de **requête sortante** : c’est votre serveur WordPress, et non le visiteur, qui a tenté d’appeler une autre adresse (le site de WordPress, une API, ou lui-même) sans obtenir de réponse à temps. Le visiteur ne voit généralement rien ; c’est l’administrateur qui le constate.

## Ce que signifie cette erreur

WordPress envoie ses requêtes HTTP avec la classe `WP_Http` (`wp-includes/class-wp-http.php`), qui s’appuie sur la bibliothèque Requests et, quand l’extension PHP cURL est disponible, sur le transport cURL (`wp-includes/Requests/src/Transport/Curl.php`). Si cURL échoue, Requests construit le message « cURL error %s: %s » à partir du code d’erreur et du texte de libcurl, et WordPress le renvoie dans un objet `WP_Error` de code `http_request_failed`.

Le code 28 de cURL correspond à `CURLE_OPERATION_TIMEDOUT` : le délai est écoulé. Le texte après les deux-points précise à quel stade, avec des variantes à connaître :

- `Resolving timed out after N milliseconds` : la **résolution DNS** n’a pas abouti à temps ;
- `Connection timed out after N milliseconds` : la **connexion TCP** n’a pas pu être établie (pare-feu qui ignore la requête, adresse injoignable) ;
- `Operation timed out after N milliseconds with 0 bytes received` : la connexion est établie, mais **aucune réponse** n’est arrivée (service distant lent, serveur local saturé) ;
- `Operation timed out after N milliseconds with X out of Y bytes received` : la réponse a commencé mais **n’a pas été terminée**.

Le délai par défaut est court : **5 secondes** (`wp-includes/class-wp-http.php`, filtre `http_request_timeout`). Un service un peu lent suffit donc à déclencher l’erreur. Elle apparaît à plusieurs endroits du cœur : le test de bouclage de la Santé du site (`wp-admin/includes/class-wp-site-health.php`), le test de communication avec WordPress.org, les contrôles de mises à jour (`wp-includes/update.php`), et le déclenchement des tâches planifiées. Pour un délai dépassé côté navigateur, voyez plutôt la fiche [erreur 504](https://www.wpmoderne.fr/erreurs-wordpress/erreur-504/).

## Diagnostic rapide

| Symptôme / constat | Cause probable | À vérifier |
| --- | --- | --- |
| Seul le test de requête de bouclage échoue | Le serveur ne parvient pas à se joindre lui-même (DNS, pare-feu, authentification, processus saturés) | `curl -I https://votre-site/` depuis le serveur ; fichier `hosts` |
| Impossible de rejoindre WordPress.org, mises à jour introuvables | Pare-feu sortant, DNS, IPv6, HTTP bloqué par `WP_HTTP_BLOCK_EXTERNAL` | `curl -v https://api.wordpress.org/` ; test « Requêtes HTTP » de la Santé du site |
| « Resolving timed out » | Résolveur DNS lent ou injoignable | `/etc/resolv.conf` ; `dig api.wordpress.org` |
| « Connection timed out » | Pare-feu qui ignore les paquets, IPv6 mal routé | `curl -4` contre `curl -6` ; règles sortantes |
| « Operation timed out… 0 bytes received » | Service distant lent ou serveur local saturé | Statut du service ; processus PHP-FPM disponibles |
| Une seule extension concernée | Sa requête vers un service précis est trop lente | Journal de l’extension ; délai fixé dans son code |

## Les causes les plus fréquentes

1. **La requête de bouclage vers le site lui-même** bloquée : mot de passe HTTP (authentification basique), pare-feu, extension de maintenance, domaine qui pointe vers le CDN que le serveur ne peut pas joindre.
2. **Un pare-feu sortant ou une règle de l’hébergeur** qui empêche le serveur d’appeler l’extérieur.
3. **Un problème de DNS ou d’IPv6** : le résolveur répond lentement, ou le serveur essaie l’IPv6 puis attend le délai avant de basculer sur l’IPv4.
4. **Un service distant lent ou en panne** : API de licence, d’e-mailing, de paiement, serveur de mises à jour.
5. **Un serveur local saturé** : si tous les processus PHP sont occupés, la requête de bouclage attend un processus libre et expire.
6. **Un délai de 5 secondes trop court** pour l’opération (téléchargement, appel d’API volumineux).

## Solutions pas à pas

Ces opérations sont en lecture seule, sauf mention contraire. Du moins invasif au plus technique :

### 1. Tester la requête depuis le serveur lui-même

Reproduisez l’appel en ligne de commande, depuis le serveur qui héberge WordPress (pas depuis votre poste) :

```
# Vers WordPress.org
curl -sS -m 10 -o /dev/null -w '%{http_code} en %{time_total} s\n' https://api.wordpress.org/core/version-check/1.7/

# Vers votre propre site (requête de bouclage)
curl -sS -m 10 -o /dev/null -w '%{http_code} en %{time_total} s\n' https://www.exemple.fr/wp-cron.php

# Forcer IPv4 ou IPv6 pour isoler un problème de protocole
curl -4 -sS -m 10 -o /dev/null -w '%{http_code}\n' https://api.wordpress.org/
curl -6 -sS -m 10 -o /dev/null -w '%{http_code}\n' https://api.wordpress.org/
```

Un échec identique à celui de WordPress confirme que le problème est *réseau ou serveur*, pas WordPress. Si `-4` réussit et `-6` expire, la cause est l’IPv6. Pour tester depuis WordPress même, avec WP-CLI :

```
wp eval '$r = wp_remote_get( "https://api.wordpress.org/core/version-check/1.7/" ); echo is_wp_error( $r ) ? $r->get_error_message() : wp_remote_retrieve_response_code( $r );'
```

### 2. Réparer la requête de bouclage

Un serveur qui n’arrive pas à joindre son propre domaine est le cas le plus fréquent. Si le domaine passe par un CDN ou un proxy que le serveur ne peut pas atteindre, faites-le pointer vers lui-même dans le fichier `hosts` :

```
# /etc/hosts
127.0.0.1   www.exemple.fr exemple.fr
```

Si votre site est protégé par un mot de passe HTTP, WordPress ajoute ses identifiants à la requête de bouclage, mais une extension de sécurité ou un pare-feu peut la refuser : vérifiez dans l’interface de l’extension que l’adresse IP du serveur est autorisée. Une extension de maintenance qui répond 503 au bouclage fausse aussi le test.

### 3. Corriger le DNS et l’IPv6

Un résolveur lent est visible avec `dig api.wordpress.org` (cherchez la ligne `Query time`). Utilisez un résolveur fiable dans `/etc/resolv.conf` ou la configuration réseau de votre distribution. Si l’IPv6 est en cause et que vous ne l’utilisez pas, faites préférer l’IPv4 dans la résolution d’adresses du système :

```
# /etc/gai.conf : préférer l'IPv4
precedence ::ffff:0:0/96  100
```

Cette modification touche tout le système : sur un mutualisé, demandez à l’hébergeur de corriger le routage IPv6 sortant.

### 4. Vérifier le pare-feu sortant et le blocage de WordPress

Un pare-feu qui filtre le trafic sortant doit autoriser le port 443 vers `api.wordpress.org`, `downloads.wordpress.org` et les services que vos extensions appellent. Vérifiez aussi que votre `wp-config.php` ne bloque pas les appels externes :

```
wp config get WP_HTTP_BLOCK_EXTERNAL
wp config get WP_ACCESSIBLE_HOSTS
```

Si `WP_HTTP_BLOCK_EXTERNAL` est vrai, seuls les hôtes de `WP_ACCESSIBLE_HOSTS` sont joignables, et la Santé du site l’indique par « Les requêtes HTTP sont bloquées ».

### 5. Libérer le serveur local

Si les processus PHP sont tous occupés, la requête de bouclage attend et expire. Dans le journal de PHP-FPM, cherchez « server reached pm.max_children setting » et, si besoin, relevez le nombre de processus comme dans la fiche [erreur 503](https://www.wpmoderne.fr/erreurs-wordpress/erreur-503/). Les tâches planifiées s’exécutent aussi par ce bouclage : mieux vaut les confier à un vrai cron, comme l’expliquent [wp-cron : comprendre et maîtriser la planification](https://www.wpmoderne.fr/tips/wp-cron-comprendre-maitriser-planification-wordpress/) et [les pièges classiques de WP-Cron](https://www.wpmoderne.fr/extensions/wp-cron-pieges-classiques/).

```
// wp-config.php
define( 'DISABLE_WP_CRON', true );

# crontab du serveur (toutes les 5 minutes)
*/5 * * * * cd /var/www/exemple/html && wp cron event run --due-now >/dev/null 2>&1
```

### 6. Allonger le délai pour une requête précise

Si le service distant est simplement lent, donnez plus de temps à l’appel concerné. Dans votre propre code, passez un délai explicite :

```
$reponse = wp_remote_get( $url, array( 'timeout' => 20 ) );
if ( is_wp_error( $reponse ) ) {
    error_log( 'Appel API : ' . $reponse->get_error_message() );
}
```

Pour une extension dont vous ne contrôlez pas le code, allongez le délai pour un hôte donné avec le filtre `http_request_args`, sans toucher aux autres requêtes :

```
add_filter( 'http_request_args', function ( $args, $url ) {
    if ( 'api.exemple.com' === wp_parse_url( $url, PHP_URL_HOST ) ) {
        $args['timeout'] = 30;
    }
    return $args;
}, 10, 2 );
```

Le cas d’une API qui se met à expirer en production est décrit dans [une API REST WordPress qui timeout](https://www.wpmoderne.fr/headless/api-rest-timeout-lancement-produit-rate/), et la gestion complète des délais et erreurs dans [HTTP API de WordPress : wp_remote_get, timeouts et gestion d’erreurs](https://www.wpmoderne.fr/extensions/http-api-wp-remote-get-timeouts-erreurs/).

### 7. Sans accès à la ligne de commande

Sur un mutualisé, ouvrez « Outils > Santé du site » pour lire le détail des tests, désactivez temporairement les extensions de sécurité et de maintenance (renommez leur dossier dans `wp-content/plugins/` par SFTP) puis relancez le test. Si l’erreur persiste, communiquez à l’hébergeur le message exact et l’heure : lui seul peut lever un blocage réseau sortant.

## Prévenir l’erreur

- Donnez un **délai explicite** à chaque appel sortant et traitez l’erreur : un site ne doit jamais attendre sans fin un service tiers.
- Mettez en cache (transients) les réponses d’API pour réduire le nombre d’appels sortants.
- Remplacez WP-Cron par un cron système sur les sites qui comptent sur leurs tâches planifiées.
- Surveillez la Santé du site après chaque changement d’hébergement, de pare-feu ou de CDN.
- Documentez les hôtes que votre site doit pouvoir joindre pour que le pare-feu les autorise.
