Si vos permaliens WordPress renvoient soudain des 404, ou si un simple copier-coller dans .htaccess déclenche une erreur 500, le problème vient souvent d’un mélange de règles Apache incompatibles, de modules manquants, ou d’un fichier modifié au mauvais endroit.

WordPress 6.9.4 (avril 2026) continue d’utiliser .htaccess uniquement quand votre serveur est Apache (ou LiteSpeed en mode compatible). Sur Nginx, ce fichier ne sert généralement à rien. Dans mon expérience, beaucoup de “bugs WordPress” sont en réalité des règles de réécriture cassées ou une directive Apache non autorisée par l’hébergeur.


Le besoin / Le problème serveur

Vous voulez un site WordPress 6.9.4 qui :

  • sert des permaliens propres (pas de ?p=123),
  • ne casse pas l’accès à /wp-admin,
  • ne renvoie pas de 404/403 aléatoires,
  • et reste rapide sans règles “copiées d’un vieux tuto 2017”.

À la fin, vous saurez :

  • identifier ce que WordPress écrit dans .htaccess (et comment le régénérer proprement),
  • séparer “règles WordPress” et “optimisations serveur” pour éviter les conflits,
  • tester vos changements via SSH, WP-CLI et curl,
  • dépanner les erreurs 500/403/404 avec une méthode reproductible.

Résumé rapide

  • .htaccess est lu par Apache à chaque requête (sauf si AllowOverride est désactivé). Une erreur de syntaxe = souvent 500.
  • WordPress écrit ses règles entre # BEGIN WordPress et # END WordPress. Ne mettez pas vos optimisations dedans.
  • Les 404 de permaliens viennent souvent de mod_rewrite absent, ou d’un AllowOverride à None.
  • Sur Nginx, vous devez traduire les règles en nginx.conf (ou config vhost). .htaccess ne s’applique pas.
  • Avant toute modification : sauvegarde du fichier et test immédiat via apachectl -t (si vous avez la main).

Avant de commencer (prérequis)

Accès et prérequis réalistes pour un blogueur :

  • FTP/SFTP ou gestionnaire de fichiers (pour éditer .htaccess),
  • SSH (idéal) pour tester Apache/Nginx et lire les logs,
  • WP-CLI (idéal) pour régénérer des règles, vider des caches, vérifier l’URL du site,
  • Accès base de données (phpMyAdmin ou MySQL CLI) si vous devez corriger siteurl/home après migration.

Versions recommandées (avril 2026)

  • WordPress : 6.9.4
  • PHP : 8.1+ (8.2/8.3 souvent mieux selon extensions et perf)
  • MySQL : 8.0+ ou MariaDB 10.6+ (selon hébergeur)
  • Serveur web : Apache 2.4+ (ou LiteSpeed), ou Nginx 1.20+

Sauvegarde obligatoire (avant le moindre test)

Expliquez-vous ceci : .htaccess est chargé à chaque requête, donc une seule ligne invalide peut rendre votre site inaccessible. Sauvegardez avant de toucher.

Si vous avez SSH, sauvegardez le fichier :

# Sauvegarde horodatée du .htaccess à la racine WordPress
cd /chemin/vers/votre/site
cp .htaccess ".htaccess.backup.$(date +%F-%H%M%S)"

Si vous n’avez que FTP/SFTP : téléchargez .htaccess en local avant modification.

Ne modifiez jamais le core WordPress

Tout se fait dans la racine WordPress (.htaccess), dans la configuration serveur (vhost Apache/Nginx), ou dans un plugin. Le core (dossier wp-includes, wp-admin) ne se modifie pas.


Étape 1 : Comprendre ce que WordPress écrit (et pourquoi ça casse)

.htaccess est un fichier de configuration “par répertoire” d’Apache. Il est interprété seulement si le serveur autorise les overrides via AllowOverride. Si votre hébergeur a mis AllowOverride None, WordPress peut écrire .htaccess… mais Apache l’ignorera, et vos permaliens resteront cassés.

Repérer le bloc WordPress

Ouvrez .htaccess à la racine du site (au même niveau que wp-config.php). Vous verrez typiquement :

# Exemple : afficher le .htaccess (si vous avez SSH)
cd /chemin/vers/votre/site
sed -n '1,200p' .htaccess

Ce que vous cherchez :

  • # BEGIN WordPress
  • # END WordPress

Entre ces deux lignes, WordPress gère les règles de permaliens. En dehors, c’est votre zone (ou celle d’un plugin de cache).

Pourquoi une règle “innocente” casse tout

Trois causes que je vois souvent :

  • Directive non autorisée : certains hébergeurs interdisent Options ou RewriteOptions en .htaccess → 500.
  • Module Apache manquant : règles RewriteRule sans mod_rewrite → permaliens 404.
  • Ordre des règles : une redirection (www/non-www, http→https) placée après WordPress peut créer des boucles ou empêcher l’accès à wp-admin.

Apache vs Nginx (point de bascule)

Avant d’optimiser .htaccess, vérifiez votre serveur web. Avec SSH :

# Détecter le serveur web via les headers HTTP
curl -I https://votre-domaine.tld/ | sed -n '1,20p'

Regardez la ligne Server:. Si vous voyez nginx, vos optimisations doivent aller dans nginx.conf (ou conf de site). Si vous voyez Apache ou LiteSpeed, .htaccess est pertinent.

Source officielle côté WordPress (réécriture) : Apache et WordPress (developer.wordpress.org).


Étape 2 : Régénérer des règles propres (sans plugin magique)

Quand les permaliens cassent après une migration, un changement de domaine, ou un plugin de sécurité, la première action est de régénérer les règles WordPress.

Méthode “sans SSH” (interface WordPress)

Vous allez dans Réglages → Permaliens, puis vous sauvegardez. Ça force WordPress à réécrire le bloc WordPress. C’est simple, mais pas toujours possible si l’admin est inaccessible.

Méthode WP-CLI (recommandée si vous avez SSH)

WP-CLI est l’outil en ligne de commande de WordPress. Ici, l’objectif est de reconstruire les règles, puis de les écrire.

Placez-vous dans le dossier du site, puis :

# Vérifier que WP-CLI voit bien l'installation
wp core version

# Régénérer les règles de réécriture (permalinks)
# --hard tente d'écrire dans .htaccess (Apache) ou web.config (IIS)
wp rewrite flush --hard

Si wp rewrite flush --hard répond qu’il ne peut pas écrire .htaccess, c’est souvent un problème de permissions (voir plus loin) ou un hébergeur qui bloque les overrides.

Vérifier les permissions du fichier

Sur Apache classique, .htaccess doit être lisible par l’utilisateur du serveur web. En général :

  • fichiers : 644
  • dossiers : 755

Avec SSH :

# Voir propriétaire/groupe/permissions
ls -la .htaccess

# Fix "raisonnable" (à adapter selon votre hébergement)
chmod 644 .htaccess

Risque : ne passez pas en 777 “pour que ça marche”. J’ai vu des sites compromis uniquement parce que les permissions rendaient les fichiers modifiables par n’importe quel processus.

Cas fréquent : WordPress en sous-dossier

Si WordPress est installé dans /wordpress mais servi depuis la racine via un index.php déplacé, vous pouvez avoir un RewriteBase incorrect. Dans ce cas, régénérez via WP-CLI depuis le bon chemin, et vérifiez que .htaccess est bien à la racine web servie.

Source officielle WP-CLI : wp rewrite flush (developer.wordpress.org).


Étape 3 : Optimiser .htaccess côté Apache (cache, compression, headers)

Une règle d’or : ne mélangez pas les règles de permaliens WordPress et vos optimisations. Laissez WordPress gérer son bloc, et ajoutez vos optimisations avant ou après.

Activer la compression (mod_deflate) proprement

La compression réduit la taille HTML/CSS/JS. Sur Apache, c’est souvent mod_deflate. Si le module n’est pas présent, ces directives peuvent provoquer une 500 selon l’hébergement.

Ajoutez ceci en dehors du bloc WordPress :

# À coller dans .htaccess (Apache), hors bloc WordPress
# Objectif : compresser HTML/CSS/JS/JSON/SVG quand mod_deflate est disponible
<IfModule mod_deflate.c>
  # Compresser les types courants
  AddOutputFilterByType DEFLATE text/html text/plain text/css
  AddOutputFilterByType DEFLATE application/javascript application/json
  AddOutputFilterByType DEFLATE image/svg+xml

  # Éviter certains bugs de proxies anciens (rare en 2026, mais safe)
  BrowserMatch ^Mozilla/4 gzip-only-text/html
  BrowserMatch ^Mozilla/4.0[678] no-gzip
  BrowserMatch bMSIE !no-gzip !gzip-only-text/html
  Header append Vary User-Agent
</IfModule>

Oui, c’est du “code Apache”, pas du PHP. Je garde souvent ces règles minimalistes : au-delà, vous tombez vite sur des conflits avec des plugins de cache.

Cache navigateur (Expires/Cache-Control)

Le but : mettre en cache les assets statiques (images, CSS, JS) sans casser le cache des pages HTML (géré plutôt par un cache serveur ou plugin).

<IfModule mod_expires.c>
  ExpiresActive On

  # Images : 30 jours
  ExpiresByType image/jpeg "access plus 30 days"
  ExpiresByType image/png "access plus 30 days"
  ExpiresByType image/webp "access plus 30 days"
  ExpiresByType image/svg+xml "access plus 30 days"
  ExpiresByType image/gif "access plus 30 days"

  # CSS/JS : 7 jours (souvent suffisant si vous versionnez correctement)
  ExpiresByType text/css "access plus 7 days"
  ExpiresByType application/javascript "access plus 7 days"

  # Polices : 30 jours
  ExpiresByType font/woff2 "access plus 30 days"
</IfModule>

<IfModule mod_headers.c>
  # Empêcher le cache agressif du HTML (géré par cache de page si besoin)
  <FilesMatch ".(html)$">
    Header set Cache-Control "no-cache, must-revalidate"
  </FilesMatch>
</IfModule>

Compatibilité page builders : Divi 5, Elementor et Avada génèrent beaucoup d’assets. Ces règles aident, mais si votre builder “inline” du CSS dynamique, vous devez purger les caches du builder après changement (sinon vous croyez que ça ne marche pas).

Forcer HTTPS et canonical (www ou non-www)

Placez les redirections avant le bloc WordPress. Sinon, vous pouvez créer des boucles (surtout si Cloudflare, un proxy, ou un load balancer termine le SSL).

Cas simple : Apache sans proxy (HTTPS direct)

# Redirection HTTP -> HTTPS (simple, sans reverse proxy)
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

Cas fréquent en 2026 : HTTPS derrière proxy/CDN (Cloudflare, reverse proxy)

Si le SSL est terminé par un proxy, Apache “voit” parfois du HTTP en interne. Utilisez l’en-tête X-Forwarded-Proto si votre infra le fournit.

# HTTPS derrière reverse proxy : évite les boucles
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

Si vous ne savez pas, testez avec :

curl -I http://votre-domaine.tld/ | sed -n '1,20p'
curl -I https://votre-domaine.tld/ | sed -n '1,20p'

Ce que j’évite volontairement dans .htaccess

  • Des “méga snippets” de sécurité trouvés sur des forums (souvent incompatibles, et parfois dangereux).
  • Des règles de cache HTML complexes (mieux dans Varnish/Nginx/LiteSpeed Cache).
  • Des règles qui bloquent admin-ajax.php ou l’API REST : Divi/Elementor/Avada en dépendent, et WordPress 6.9.4 s’appuie fortement sur l’API REST.

Référence Apache officielle (directives) : Apache 2.4 – .htaccess (httpd.apache.org).


Étape 4 : Dépanner les erreurs courantes (403/404/500, boucles, admin cassée)

Tableau de diagnostic rapide

Symptôme Cause probable Vérification Solution
Permaliens en 404, page d’accueil OK mod_rewrite absent ou AllowOverride désactivé apachectl -M | grep rewrite (si possible) / logs Apache Activer mod_rewrite + AllowOverride All sur le vhost, puis wp rewrite flush --hard
Erreur 500 après modification Directive invalide/interdite, ou syntaxe cassée Logs : error.log Apache Restaurer backup, puis réintroduire les règles une par une
Boucle de redirection Règles HTTPS/canonical + proxy/CDN mal gérés curl -I et vérifier Location: en chaîne Utiliser X-Forwarded-Proto ou configurer le proxy correctement
403 sur wp-admin Règle de sécurité trop agressive, WAF, permissions Logs Apache + désactivation temporaire règles custom Retirer la règle, vérifier permissions, whitelister endpoints
CSS/JS ne chargent plus Mauvais cache-control, mauvaise redirection, ou règle qui bloque wp-content DevTools / curl -I sur un fichier CSS Corriger règles, purger cache plugin/CDN, vérifier MIME types

Erreur 500 : méthode “chirurgicale”

Quand vous prenez une 500, évitez de “deviner”. Faites ceci :

  • restaurez le backup .htaccess pour remettre le site en ligne,
  • lisez le log d’erreur Apache pour connaître la directive fautive,
  • réintroduisez les règles par blocs.

Avec SSH, repérez le log (selon distro/hébergeur) :

# Debian/Ubuntu (souvent)
sudo tail -n 200 /var/log/apache2/error.log

# RHEL/CentOS/Alma/Rocky (souvent)
sudo tail -n 200 /var/log/httpd/error_log

Vous cherchez typiquement :

  • Invalid command 'Header'mod_headers non chargé
  • RewriteEngine not allowed hereAllowOverride ne permet pas FileInfo
  • Options FollowSymLinks not allowed here → directive interdite en .htaccess

Permaliens 404 : vérifier mod_rewrite et AllowOverride

Si vous administrez le serveur (VPS), testez les modules :

# Lister les modules Apache chargés
apachectl -M | sed -n '1,200p'

# Vérifier rewrite
apachectl -M | grep -i rewrite

Sur Debian/Ubuntu, activation :

# Activer mod_rewrite
sudo a2enmod rewrite

# (Optionnel) headers/expires si vous utilisez les directives correspondantes
sudo a2enmod headers
sudo a2enmod expires

# Tester la config
sudo apachectl -t

# Redémarrer proprement
sudo systemctl reload apache2

Ensuite, dans votre vhost Apache, vous devez autoriser les overrides. Exemple (à adapter) :

<Directory /var/www/votre-site>
  AllowOverride All
  Require all granted
</Directory>

Sans ça, WordPress 6.9.4 peut avoir un .htaccess parfait… et Apache l’ignorera.

Admin cassée après migration : vérifier home/siteurl

Un .htaccess “correct” n’empêche pas une boucle si WordPress croit être sur un autre domaine. Vérifiez via WP-CLI :

# Lire les URLs configurées
wp option get home
wp option get siteurl

Si c’est mauvais :

# Remplacer proprement (attention : utilisez la bonne URL)
wp option update home "https://votre-domaine.tld"
wp option update siteurl "https://votre-domaine.tld"

Source officielle (options) : get_option (developer.wordpress.org).


Fichiers de configuration complets

Vous trouverez ci-dessous des fichiers “prêts à copier-coller”. Adaptez les chemins et domaines. Et gardez en tête : si vous êtes sur Nginx, le .htaccess ne s’applique pas.

.htaccess complet (Apache) : WordPress + optimisations raisonnables

Collez ce fichier à la racine WordPress. Si un plugin de cache (LiteSpeed Cache, WP Rocket, etc.) écrit ses propres blocs, gardez-les, mais évitez les doublons de redirection.

# =====================================================================
# .htaccess (Apache) - WordPress 6.9.4+ (avril 2026)
# Objectif : permaliens + quelques optimisations sûres
# Note : si votre hébergeur interdit certaines directives, vous aurez une 500.
# =====================================================================

# --- Sécurité minimale : empêcher l’indexation de répertoires (si autorisé) ---
Options -Indexes

# --- Redirection HTTP -> HTTPS (cas simple, sans reverse proxy) ---
# Si vous êtes derrière Cloudflare/reverse proxy, commentez ce bloc
# et utilisez le bloc X-Forwarded-Proto plus bas.
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

# --- Variante reverse proxy (décommentez si nécessaire) ---
#RewriteEngine On
#RewriteCond %{HTTP:X-Forwarded-Proto} !https
#RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

# --- Compression (si mod_deflate est dispo) ---
<IfModule mod_deflate.c>
  AddOutputFilterByType DEFLATE text/html text/plain text/css
  AddOutputFilterByType DEFLATE application/javascript application/json
  AddOutputFilterByType DEFLATE image/svg+xml

  BrowserMatch ^Mozilla/4 gzip-only-text/html
  BrowserMatch ^Mozilla/4.0[678] no-gzip
  BrowserMatch bMSIE !no-gzip !gzip-only-text/html

  <IfModule mod_headers.c>
    Header append Vary User-Agent
  </IfModule>
</IfModule>

# --- Cache navigateur pour assets (si mod_expires dispo) ---
<IfModule mod_expires.c>
  ExpiresActive On
  ExpiresByType image/jpeg "access plus 30 days"
  ExpiresByType image/png "access plus 30 days"
  ExpiresByType image/webp "access plus 30 days"
  ExpiresByType image/svg+xml "access plus 30 days"
  ExpiresByType image/gif "access plus 30 days"
  ExpiresByType text/css "access plus 7 days"
  ExpiresByType application/javascript "access plus 7 days"
  ExpiresByType font/woff2 "access plus 30 days"
</IfModule>

# --- WordPress : ne modifiez pas ce bloc à la main ---
# Si vous devez le reconstruire : Réglages > Permaliens ou wp rewrite flush --hard
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress

nginx.conf (server block) équivalent minimal pour WordPress

Si vous êtes sur Nginx, voici une base. Elle gère les permaliens WordPress sans .htaccess. Sur un mutualisé Nginx, vous n’aurez pas toujours accès à cette config.

# =====================================================================
# Nginx - configuration minimale WordPress (permalinks)
# À placer dans le server{} de votre vhost
# =====================================================================

server {
  listen 80;
  server_name votre-domaine.tld www.votre-domaine.tld;

  # Redirection HTTP -> HTTPS (si vous avez un vhost SSL séparé)
  return 301 https://votre-domaine.tld$request_uri;
}

server {
  listen 443 ssl http2;
  server_name votre-domaine.tld;

  root /var/www/votre-site;
  index index.php index.html;

  # Empêcher l’accès à certains fichiers sensibles
  location ~* /(wp-config.php|readme.html|license.txt) {
    deny all;
  }

  # Permaliens WordPress
  location / {
    try_files $uri $uri/ /index.php?$args;
  }

  # PHP-FPM (exemple)
  location ~ .php$ {
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_pass unix:/run/php/php8.2-fpm.sock; # Adaptez la version/chemin
  }

  # Cache statique (simple)
  location ~* .(css|js|jpg|jpeg|png|webp|gif|svg|woff2)$ {
    expires 7d;
    add_header Cache-Control "public, max-age=604800";
    try_files $uri =404;
  }
}

wp-config.php : réglages utiles en dépannage (sans casser la prod)

Vous n’allez pas “optimiser” Apache via wp-config.php, mais vous pouvez activer des logs pour diagnostiquer un effet de bord après une 500/white screen.

Ajoutez temporairement (puis retirez) :

<?php
// wp-config.php (extraits) - WordPress 6.9.4+ / PHP 8.1+
// Objectif : activer un logging propre en dépannage (à désactiver après)

define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );      // Écrit dans wp-content/debug.log
define( 'WP_DEBUG_DISPLAY', false ); // Évite d’afficher des infos sensibles aux visiteurs

// Optionnel : augmenter la mémoire si vous avez des erreurs liées à Elementor/Divi/Avada
define( 'WP_MEMORY_LIMIT', '256M' );

Source officielle : Debug WordPress (developer.wordpress.org).

php.ini (ou conf PHP) : paramètres qui évitent des faux diagnostics

Un .htaccess “parfait” n’empêche pas un upload qui échoue ou un builder qui time-out. Voici une base raisonnable pour un blog avec page builder (à adapter à votre hébergeur).

; php.ini (extraits) - PHP 8.1+
memory_limit = 256M
max_execution_time = 120
max_input_time = 120
post_max_size = 64M
upload_max_filesize = 64M
max_input_vars = 5000

; Logging (en prod, évitez display_errors)
display_errors = Off
log_errors = On

Référence PHP : PHP directives (php.net).


Vérification

Après modification de .htaccess (ou conf Nginx), vérifiez avec des tests qui ne dépendent pas de votre navigateur (cache, extensions, etc.).

1) Tester la syntaxe serveur

Sur Apache (si vous avez la main) :

# Vérifier la configuration Apache (inclut parfois les .htaccess selon setup)
sudo apachectl -t

Sur Nginx :

# Tester la configuration Nginx
sudo nginx -t

2) Tester les redirections

Le but : vérifier qu’on a bien une 301 vers HTTPS, sans boucle.

curl -I http://votre-domaine.tld/ | sed -n '1,20p'

3) Tester un permalien et une ressource statique

# Un article (doit répondre 200, pas 404)
curl -I "https://votre-domaine.tld/mon-article/" | sed -n '1,20p'

# Un fichier CSS (doit répondre 200 et idéalement Cache-Control/Expires)
curl -I "https://votre-domaine.tld/wp-content/themes/votre-theme/style.css" | sed -n '1,30p'

4) Vérifier WordPress côté CLI

Le but : s’assurer que WordPress est cohérent (URL, règles, santé).

wp core version
wp option get home
wp option get siteurl
wp rewrite list --format=table | sed -n '1,40p'

Si vous utilisez un cache serveur (LiteSpeed/Varnish/NGINX cache), purgez-le après modification. Sinon vous testez l’ancienne version et vous perdez du temps.


Si ça ne marche pas

Quand un site ne répond plus après modification, votre priorité est de rétablir l’accès, puis de diagnostiquer.

Étape A : remettre un .htaccess minimal pour récupérer le site

Renommez le fichier actuel (pour le garder), puis créez un .htaccess minimal avec uniquement le bloc WordPress.

cd /chemin/vers/votre/site
mv .htaccess .htaccess.ko

# Créer un .htaccess minimal
cat > .htaccess <<'EOF'
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
EOF

Ensuite, régénérez :

wp rewrite flush --hard

Étape B : lire les logs au bon endroit

Les erreurs utiles ne sont pas dans WordPress, mais dans le serveur web.

  • Apache : /var/log/apache2/error.log ou /var/log/httpd/error_log
  • Nginx : /var/log/nginx/error.log
  • PHP-FPM : selon la version et la distro (ex: /var/log/php8.2-fpm.log)
# Apache
sudo tail -n 200 /var/log/apache2/error.log

# Nginx
sudo tail -n 200 /var/log/nginx/error.log

Étape C : vérifier que .htaccess est bien pris en compte

Symptôme typique : vous modifiez .htaccess, aucun effet. Deux causes dominent :

  • Vous n’êtes pas sur Apache/LiteSpeed.
  • AllowOverride est à None.

Si vous administrez Apache, cherchez le vhost, puis :

# Chercher AllowOverride dans les fichiers de conf (chemins variables)
sudo grep -R "AllowOverride" -n /etc/apache2/sites-enabled /etc/apache2/apache2.conf 2>/dev/null | sed -n '1,120p'

Étape D : isoler un conflit de cache/plugin

J’ai souvent croisé des conflits entre règles .htaccess et plugins de cache/sécurité qui injectent leurs propres directives. Pour isoler :

  • désactivez temporairement le plugin de cache via WP-CLI,
  • purgez le cache CDN si vous en avez un,
  • retirez les blocs non-WordPress du .htaccess et réintroduisez-les ensuite.
# Désactiver un plugin de cache (exemples, adaptez le slug)
wp plugin deactivate litespeed-cache
wp plugin deactivate wp-rocket

Source WP-CLI (plugins) : wp plugin deactivate (developer.wordpress.org).


Pièges et erreurs courantes

Erreur Cause Solution
Copier le code au mauvais endroit Vous avez collé des règles dans wp-admin/.htaccess ou dans un sous-dossier Le .htaccess principal doit être à la racine web (à côté de wp-config.php)
Erreur 500 après un copier-coller Directive Apache interdite (ex: Options) ou module manquant (ex: mod_headers) Lire error.log, entourer avec <IfModule>, ou déplacer la directive au vhost
Permaliens non régénérés Vous avez changé la structure mais pas flushé les règles Réglages → Permaliens → Enregistrer, ou wp rewrite flush --hard
Boucle de redirection après passage en HTTPS Proxy/CDN termine le SSL, Apache croit être en HTTP Utiliser X-Forwarded-Proto ou configurer le proxy ; vérifier avec curl -I
CSS/JS “cassés” après optimisation Cache navigateur trop agressif + vous n’avez pas purgé le cache du builder Purger cache Divi/Elementor/Avada + cache plugin/CDN ; vérifier headers sur un fichier
Snippet d’un ancien tutoriel incompatible Règles obsolètes (ex: directives Apache 2.2, vieux hacks) Repartir d’un .htaccess minimal WP 6.9.4, puis ajouter des blocs modernes et testés
Tester sur production sans sauvegarde Un simple caractère invalide rend le site KO Sauvegarde + rollback rapide (renommer/restaurer) + test via apachectl -t

Sécurité serveur

.htaccess peut renforcer la sécurité, mais il peut aussi vous tirer une balle dans le pied (blocage de l’API REST, de admin-ajax.php, du builder). Restez sur des règles simples et vérifiables.

Bloquer l’accès à des fichiers sensibles

Ajoutez (Apache) :

# Bloquer des fichiers qui n’ont rien à faire en public
<FilesMatch "^(wp-config.php|readme.html|license.txt)$">
  Require all denied
</FilesMatch>

Empêcher l’exécution de PHP dans uploads (réduit l’impact d’un upload malveillant)

Créez un .htaccess dans wp-content/uploads/ (pas à la racine) :

# wp-content/uploads/.htaccess
# Objectif : empêcher l’exécution de scripts PHP dans le dossier d’uploads
<FilesMatch ".php$">
  Require all denied
</FilesMatch>

Risque : si un plugin stocke volontairement des fichiers PHP dans uploads (mauvaise pratique, mais ça existe), ça cassera ce plugin. Testez d’abord sur staging.

Permissions : rester strict

  • Ne mettez jamais wp-config.php en écriture globale.
  • Évitez les permissions “ouvertes” (777).
  • Si vous avez un doute, vérifiez propriétaire/groupe et alignez avec l’utilisateur du serveur web.

Référence WordPress (hardening) : Hardening WordPress (wordpress.org).


Ressources


FAQ

Où se trouve le fichier .htaccess de WordPress ?

À la racine du site WordPress, au même niveau que wp-config.php et wp-content. Il peut être caché (fichier commençant par un point). Sur certains hébergements, il n’existe pas tant que vous n’avez pas activé les permaliens.

Je n’ai pas de .htaccess, c’est grave ?

Non. Si vous êtes sur Nginx, c’est normal. Si vous êtes sur Apache et que vous utilisez des permaliens “jolis”, WordPress peut en créer un quand vous sauvegardez Réglages → Permaliens.

Pourquoi mes permaliens font des 404 alors que la page d’accueil marche ?

Le cas classique : mod_rewrite non activé ou AllowOverride désactivé. WordPress génère des URLs, mais Apache ne réécrit pas vers index.php.

Est-ce que je peux “accélérer WordPress” juste avec .htaccess ?

Vous pouvez améliorer la compression et le cache des fichiers statiques. Pour le cache HTML (pages), c’est plutôt un cache serveur (Nginx microcache, Varnish, LiteSpeed) ou un plugin de cache. .htaccess seul ne remplace pas un vrai cache de page.

Est-ce compatible avec Divi 5, Elementor et Avada ?

Oui, si vous évitez de bloquer l’API REST et admin-ajax.php, et si vous ne mettez pas des règles anti-hotlinking agressives sur wp-content. Après changement de cache headers, purgez les caches du builder et du CDN.

J’ai une erreur 500 dès que j’ajoute un bloc “Header set …”

Très souvent, mod_headers n’est pas chargé. Vérifiez le log Apache : vous verrez Invalid command 'Header'. Solution : activer headers (VPS) ou retirer ce bloc (mutualisé).

Pourquoi WordPress réécrit mon .htaccess et supprime mes règles ?

WordPress ne touche normalement qu’au bloc entre # BEGIN WordPress et # END WordPress. Si vous aviez mis vos règles dedans, elles peuvent être écrasées lors d’un flush des permaliens.

Je peux mettre des règles de sécurité très strictes dans .htaccess ?

Vous pouvez, mais testez sur un staging. J’ai vu des règles “anti-API” bloquer Gutenberg, l’éditeur de site, Elementor, et même des paiements WooCommerce. Préférez des règles ciblées (fichiers sensibles, PHP dans uploads).

Comment revenir en arrière si je n’ai plus accès à l’admin ?

Restaurez le backup .htaccess via FTP/SFTP, ou renommez le fichier et remettez un .htaccess minimal. Ensuite, régénérez avec wp rewrite flush --hard si vous avez WP-CLI.

Est-ce que .htaccess est lu à chaque requête ?

Oui, sur Apache, c’est un coût réel. C’est une raison pour laquelle les optimisations lourdes et le cache avancé sont souvent mieux au niveau du vhost Apache ou directement sur Nginx.