Le .htaccess est un fichier de configuration Apache que vous placez à la racine de votre site (ou dans un sous-dossier). Il permet de redéfinir le comportement du serveur sans toucher à la configuration globale : redirections, réécritures d'URL, contrôle d'accès, compression, cache navigateur. Sur nos hébergements Plesk avec Apache, c'est l'outil le plus direct pour pas mal de besoins courants.
.htaccess est une fonctionnalité d'Apache. Si votre hébergement tourne sur Nginx pur, le fichier est ignoré. Sur nos Plesk, Apache est servi derrière un Nginx reverse proxy : le .htaccess fonctionne pour tout ce qui concerne PHP, les redirections et la réécriture. Pour les règles statiques (compression, cache), la config Nginx prend parfois le relais automatiquement.
Anatomie d'un .htaccess
Un fichier texte simple, une directive par ligne, des commentaires avec #. Les directives sont regroupées par modules Apache (mod_rewrite, mod_expires, mod_deflate, etc.). On les enveloppe dans un <IfModule> pour éviter une erreur 500 si le module n'est pas chargé.
# Forcer l'UTF-8 par défaut
AddDefaultCharset UTF-8
# Désactiver le listing des dossiers
Options -Indexes
# Page d'erreur personnalisée
ErrorDocument 404 /404.php
Forcer HTTPS
À placer tout en haut de votre .htaccess, avant toute autre règle RewriteRule :
<IfModule mod_rewrite.c>
RewriteEngine On
# Forcer HTTPS
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</IfModule>
Le flag R=301 indique une redirection permanente (les moteurs transfèrent le jus SEO). L signifie « dernière règle » et évite que d'autres RewriteRule s'appliquent après.
Redirections 301
Deux approches, les deux fonctionnent :
Avec Redirect (simple)
# URL exacte vers URL exacte
Redirect 301 /ancienne-page.html https://exemple.fr/nouvelle-page
# Dossier entier
Redirect 301 /blog-old/ https://exemple.fr/blog/
Avec RewriteRule (pattern matching)
<IfModule mod_rewrite.c>
RewriteEngine On
# www vers sans-www (ou l'inverse)
RewriteCond %{HTTP_HOST} ^www\.exemple\.fr [NC]
RewriteRule ^(.*)$ https://exemple.fr/$1 [L,R=301]
# Toute URL /produit/XXX vers /p/XXX
RewriteRule ^produit/(.*)$ /p/$1 [L,R=301]
</IfModule>
R=302 (temporaire), validez, puis passez en R=301.
Bloquer l'accès à des fichiers ou dossiers
Un fichier précis
<Files "wp-config.php">
Require all denied
</Files>
<Files ".env">
Require all denied
</Files>
Tous les fichiers d'un type
<FilesMatch "\.(sql|log|bak|ini|conf)$">
Require all denied
</FilesMatch>
Interdire le listing d'un dossier
# À la racine ou dans le dossier concerné
Options -Indexes
Bloquer l'exécution PHP dans uploads/
Une protection classique pour wp-content/uploads/ (placez ce .htaccess dans le dossier uploads) :
<FilesMatch "\.(php|phtml|phps)$">
Require all denied
</FilesMatch>
Require all denied / Require all granted. L'ancienne (Deny from all, Order deny,allow) fonctionne encore via mod_access_compat, mais est dépréciée. Préférez la nouvelle.
Protéger un dossier par mot de passe
Créez le fichier de mots de passe avec htpasswd (depuis SSH) :
htpasswd -c /home/user/.htpasswd admin
# Entrez le mot de passe deux fois
Puis dans un .htaccess au niveau du dossier à protéger :
AuthType Basic
AuthName "Zone protégée"
AuthUserFile /home/user/.htpasswd
Require valid-user
Plesk propose aussi l'équivalent graphique : Websites & Domains > Password-Protected Directories.
Compression gzip / deflate
Réduit la taille des réponses HTML, CSS, JS, SVG de 60 à 80 % avant envoi au navigateur :
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/json
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE image/svg+xml
AddOutputFilterByType DEFLATE font/ttf
AddOutputFilterByType DEFLATE font/otf
</IfModule>
Ne compressez pas les formats déjà compressés : JPEG, PNG, WebP, MP4, woff2, ZIP. Le gain est nul et la CPU consommée est perdue.
Cache navigateur (mod_expires)
Dit au navigateur combien de temps il peut réutiliser un fichier sans revenir demander au serveur. Énorme gain de performance sur les visites récurrentes :
<IfModule mod_expires.c>
ExpiresActive On
# Par défaut (fallback)
ExpiresDefault "access plus 1 month"
# HTML : court, pour propager les mises à jour
ExpiresByType text/html "access plus 0 seconds"
# CSS / JS : un an (on les cassera via un query string ou un hash de nom)
ExpiresByType text/css "access plus 1 year"
ExpiresByType application/javascript "access plus 1 year"
# Images : un an
ExpiresByType image/jpeg "access plus 1 year"
ExpiresByType image/png "access plus 1 year"
ExpiresByType image/webp "access plus 1 year"
ExpiresByType image/svg+xml "access plus 1 year"
# Fonts : un an
ExpiresByType font/woff2 "access plus 1 year"
ExpiresByType font/woff "access plus 1 year"
</IfModule>
style.css?v=3 ou style-a1b2c3.css). Changez le numéro, le navigateur recharge.
Protection hotlinking
Empêche d'autres sites d'afficher vos images en consommant votre bande passante :
<IfModule mod_rewrite.c>
RewriteEngine On
# Autoriser si pas de referer (accès direct) ou referer interne
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?exemple\.fr [NC]
# Autoriser Google Images, Bing, etc. (optionnel)
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?(google|bing|duckduckgo)\. [NC]
# Bloquer tout le reste sur les images
RewriteRule \.(jpe?g|png|gif|webp|svg)$ - [F,NC,L]
</IfModule>
Le flag F renvoie un 403 Forbidden. Remplacez exemple.fr par votre domaine.
Debug : tester avec curl
Pour vérifier qu'une redirection ou un header fonctionne sans passer par le navigateur (qui cache tout) :
# Voir les headers de réponse (suivre ou pas la redirection)
curl -I https://exemple.fr/ancienne-page
# Suivre toute la chaîne de redirections
curl -IL https://exemple.fr
# Forcer un User-Agent (certaines règles filtrent par UA)
curl -I -A "Mozilla/5.0" https://exemple.fr
# Vérifier que gzip est bien activé
curl -I -H "Accept-Encoding: gzip" https://exemple.fr | grep -i content-encoding
Pièges à connaître
Boucles de redirection
Classique : vous forcez HTTPS, et un autre outil (plugin WordPress, config Plesk) force déjà HTTPS. Résultat : le navigateur boucle et affiche ERR_TOO_MANY_REDIRECTS. Dans ce cas, retirez une des deux règles.
%{HTTPS} peut renvoyer off côté Apache même si l'utilisateur est en HTTPS (Nginx a déjà terminé le TLS). Préférez tester via le header X-Forwarded-Proto :
RewriteCond %{HTTP:X-Forwarded-Proto} !=https
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Ordre des règles
Les règles sont évaluées dans l'ordre du fichier. Une règle [L] qui matche coupe tout ce qui suit. Mettez vos règles les plus générales en bas, les plus spécifiques en haut.
Erreur 500 après modification
Presque toujours une faute de frappe ou un module Apache non chargé. Pour diagnostiquer :
- Commentez (avec
#) la dernière règle ajoutée. Si ça repart, vous tenez le coupable. - Consultez les logs Apache depuis Plesk : Websites & Domains > Logs puis filtre Error Log.
- Vérifiez que chaque bloc
<IfModule>,<Files>,<FilesMatch>est bien fermé.
.htaccess en .htaccess.bak. Une règle mal écrite peut rendre le site inaccessible. Avec la sauvegarde, vous restaurez en deux secondes via SFTP.
Module manquant ?
Sur nos infrastructures, les modules Apache standards sont chargés : mod_rewrite, mod_expires, mod_deflate, mod_headers, mod_mime. Si vous avez besoin d'un module plus exotique (mod_pagespeed, mod_security avec règles custom, etc.), ouvrez un ticket Datacampus pour qu'on valide l'installation côté serveur.