Utiliser curl avec WordPress et Docker
Récemment j’ai eu quelques soucis pour faire fonctionner curl
avec WordPress en utilisant Docker. Voici comment je m’y suis pris pour résoudre le problème.
Le contexte
J’utilise Docker-compose et Traefik pour faire du développement local sur WordPress. J’ai un plugin WordPress qui utilise wp_get_remote
pour lire un fichier .json
et pour ensuite utiliser son contenu. Tout fonctionne sur un serveur distant. En local, avec LAMP et un certificat auto-signé par mkcert, je sais qu’il faut ajouter un hook pour faire fonctionner curl
. Je pensais donc que la même chose pouvait s’appliquer avec Docker. La démarche est un peu plus compliquée.
Premières manipulations
Comme, je le disais, avec un certificat auto-signé, il faut ajouter un hook WordPress pour que la fonction wp_get_remote
fonctionne correctement. J’utilise pour cela un mu-plugin :
<?php
/**
* Plugin Name: Local Certs
* Plugin URI: https://stackoverflow.com/q/44632619/881743
* Description: Ensure WordPress curl requests compatibility with local SSL certs. Based on Kevin Leary answer: https://github.com/FiloSottile/mkcert/issues/165#issuecomment-616002942
* Version: 1.0.0
* Author: Armand Philippot
* Author URI: https://wp.armandphilippot.com/
* License: MIT
*/
/**
* Replace Localhost cURL Certificates
*
* If the URL for an HTTP request in WordPress contains a custom TLD, replace
* the WordPress local /certificates/ca-bundle.crt with the PHP supplied bundle.
*/
function local_certs_http_request_args( $parsed_args, $url ) {
$custom_tld = array( 'test', 'local', 'localhost' );
// Get the URL TLD
$test_url = wp_parse_url( $url, PHP_URL_HOST );
$test_tld = explode( '.', $test_url );
$test_tld = end( $test_tld );
if ( in_array( $test_tld, $custom_tld ) ) {
// Replace WordPress local certificates with PHP's default cacert path
$openssl_cert_locations = openssl_get_cert_locations();
if ( isset( $openssl_cert_locations[ 'default_cert_file' ] ) ) {
$parsed_args[ 'sslcertificates' ] = $openssl_cert_locations[ 'default_cert_file' ];
}
}
return $parsed_args;
}
add_filter( 'http_request_args', 'local_certs_http_request_args', 10, 2 );
Je me doutais que ce ne serait pas suffisant. Docker risque de se plaindre à cause du certificat. J’ai tout de même testé pour m’en assurer.
1er problème : cURL Error 6: Could not resolve host
Il semble que même si j’arrive à accéder à mon site avec un serveur virtuel, via curl
le nom de domaine n’est pas reconnu. Après quelques recherches, j’ai fini par trouver une piste : les alias de réseaux.
J’ai donc modifié la partie networks
du service Traefik dans le fichier docker-compose.yml
:
version: '3.8'
services:
traefik:
image: traefik:${DWP_TRAEFIK_VERSION:-2.3.1}
container_name: dwp_traefik
restart: on-failure
ports:
- '127.0.0.1:80:80'
- '127.0.0.1:443:443'
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./traefik/traefik.yml:/etc/traefik/traefik.yml
- ./traefik/ssl.yml:/etc/traefik/ssl.yml
- ./certs:/etc/traefik/certs
networks:
dwp-proxy:
aliases:
- ${DWP_DOMAIN_NAME}
- www.${DWP_DOMAIN_NAME}
labels:
- 'traefik.enable=true'
- 'traefik.http.routers.traefik.entrypoints=https'
- 'traefik.http.routers.traefik.rule=Host(`traefik.${DWP_DOMAIN_NAME}`)'
- 'traefik.http.routers.traefik.service=api@internal'
- 'traefik.http.routers.traefik.tls=true'
volumes:
db_data:
networks:
dwp-proxy:
name: dwp-proxy
dwp-web:
name: dwp-web
Ensuite, il suffit d’arrêter puis de démarrer à nouveau les conteneurs :
sudo docker-compose stop
sudo docker-compose up -d
Ça fonctionne ! Enfin presque… Le nom de domaine est bien résolu, mais une nouvelle erreur pointe son nez.
2e problème : cURL Error 77: Error setting certificate verify locations
Ce problème, je m’y attendais. Docker a besoin du fichier rootCA généré par mkcert pour résoudre la commande curl
. La solution n’est pas aussi simple. Il faut rentrer dans le conteneur pour mettre à jour les certificats manuellement.
Pour commencer, j’ai du copier les fichiers rootCA générés par mkcert dans le dossier ./certs
que j’utilise déjà. Là, il faut soit les renommer en .crt
au lieu de .pem
pour qu’ils puissent être découverts automatiquement, soit faire un lien symbolique.
ln -s rootCA.pem rootCA.crt
Ensuite, j’ai ajouté un volume au service WordPress pour monter les certificats :
version: '3.8'
services:
wordpress:
depends_on:
- db
image: wordpress:${DWP_WORDPRESS_VERSION:-latest}
container_name: dwp_wordpress
restart: on-failure
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_NAME: ${DWP_DB_NAME:-wordpress}
WORDPRESS_DB_USER: ${DWP_DB_USER:-wordpress}
WORDPRESS_DB_PASSWORD: ${DWP_DB_PASSWORD:-wordpress}
WORDPRESS_TABLE_PREFIX: ${DWP_TABLE_PREFIX:-wp_}
WORDPRESS_CONFIG_EXTRA: |
define( 'WP_DISABLE_FATAL_ERROR_HANDLER', true );
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', true );
define( 'SCRIPT_DEBUG', true );
define( 'SAVEQUERIES', true );
working_dir: /var/www/html
volumes:
- ./wp-content:/var/www/html/wp-content
- ./uploads.ini:/usr/local/etc/php/conf.d/uploads.ini
- ./certs:/usr/local/share/ca-certificates/certs
networks:
dwp-proxy:
dwp-web:
labels:
- 'traefik.enable=true'
- 'traefik.http.routers.wordpress.entrypoints=http,https,browserSync'
- 'traefik.http.routers.wordpress.rule=Host(`www.${DWP_DOMAIN_NAME}`) || Host(`${DWP_DOMAIN_NAME}`)'
- 'traefik.http.routers.wordpress.tls=true'
volumes:
db_data:
networks:
dwp-proxy:
name: dwp-proxy
dwp-web:
name: dwp-web
Puis, encore une fois, j’ai arrêté et redémarré les conteneurs. Maintenant il faut entrer dans le conteneur de WordPress. Pour cela, j’ai exécuté :
sudo docker-compose exec wordpress bash
Dans le conteneur, j’ai alors exécuté la commande update-ca-certificate
pour mettre à jour la liste des certificats.
Seulement, ça ne suffit pas… curl
cherche le fichier au mauvais endroit : CAfile: /usr/lib/ssl/cert.pem
. Ce fichier n’existe pas. Toujours dans le conteneur, j’ai donc exécuté :
ln -s /etc/ssl/certs/ca-certificates.crt /usr/lib/ssl/cert.pem
exit
Maintenant vous pouvez actualiser votre page, et curl
devrait fonctionner !
3e problème : le lien symbolique n’est pas persistant
Si vous arrêtez vos conteneurs Docker pour les redémarrer ensuite, vous serez à nouveau confronté au problème n°2. Le lien symbolique est apparemment détruit au redémarrage.
Je n’ai pas trouvé comment le rendre persistent. Ou plutôt, la seule solution semble de créer sa propre image WordPress mais je n’ai pas testé.
Il faut donc recréer le lien symbolique manuellement à chaque redémarrage des conteneurs.
4e problème : cURL error 60: SSL certificate problem
Ce problème n’en est pas réellement un si vous avez suivi toutes les étapes ci-dessus. Il survient si vous avez appliqué les différentes modifications proposées sans ajouter le hook WordPress.
La solution est donc simple : soit utiliser votre propre hook dans votre fichier functions.php
soit copier le mu-plugins dans le répertoire wp-content/mu-plugins
/.
Épilogue
Même si ce n’est pas la solution idéale, je m’en contenterais pour le moment et, si vous êtes confronté au même problème, j’espère que ça vous aidera.
0 commentaire
Laisser un commentaire