Le fichier .htaccess est l'un des outils de configuration les plus puissants pour les serveurs web Apache. Il vous permet de contrôler les redirections, forcer le HTTPS, définir des en-têtes de sécurité, gérer le cache et bien plus encore, sans toucher à la configuration principale du serveur. Ce guide complet .htaccess fournit des exemples prêts pour la production que vous pouvez copier et coller directement.
Redirections de base
Les redirections sont l'utilisation la plus courante des fichiers .htaccess. Que vous déplaciez une seule page, restructuriez un répertoire entier ou migriez vers un nouveau domaine, les directives Redirect et RewriteRule d'Apache le rendent simple. Utilisez toujours des redirections 301 (permanentes) pour le SEO afin de transférer la valeur des liens vers la nouvelle URL.
Rediriger une URL unique
# Redirect a single URL (301 permanent)
Redirect 301 /old-page.html https://example.com/new-page.html
# Using RewriteRule for more control
RewriteEngine On
RewriteRule ^old-page\.html$ /new-page.html [R=301,L]
# Redirect with pattern matching (e.g., old product URLs)
RewriteRule ^products/([0-9]+)\.html$ /shop/item/$1 [R=301,L]Rediriger un répertoire entier
# Redirect entire directory to new location
RedirectMatch 301 ^/blog/(.*)$ https://example.com/articles/$1
# Using RewriteRule (preserves subdirectory structure)
RewriteEngine On
RewriteRule ^blog/(.*)$ /articles/$1 [R=301,L]
# Redirect directory but keep filenames
RewriteRule ^old-folder/(.+)$ /new-folder/$1 [R=301,L]Redirection de domaine à domaine
# Redirect entire old domain to new domain
RewriteEngine On
RewriteCond %{HTTP_HOST} ^(www\.)?olddomain\.com$ [NC]
RewriteRule ^(.*)$ https://newdomain.com/$1 [R=301,L]
# Redirect specific domain alias to primary domain
RewriteEngine On
RewriteCond %{HTTP_HOST} ^olddomain\.net$ [NC,OR]
RewriteCond %{HTTP_HOST} ^olddomain\.org$ [NC]
RewriteRule ^(.*)$ https://newdomain.com/$1 [R=301,L]Forçage HTTPS
Forcer le HTTPS est essentiel pour la sécurité et le SEO. Google utilise le HTTPS comme signal de classement, et les navigateurs modernes avertissent les utilisateurs des connexions HTTP non sécurisées. Ces règles utilisent mod_rewrite pour rediriger tout le trafic HTTP vers HTTPS.
HTTP vers HTTPS (sans www)
# Force HTTPS (redirect HTTP to HTTPS, non-www)
RewriteEngine On
# Redirect www to non-www
RewriteCond %{HTTP_HOST} ^www\.example\.com$ [NC]
RewriteRule ^(.*)$ https://example.com/$1 [R=301,L]
# Redirect HTTP to HTTPS
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://example.com/$1 [R=301,L]HTTP vers HTTPS (avec www)
# Force HTTPS with www prefix
RewriteEngine On
# Redirect non-www to www
RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
RewriteRule ^(.*)$ https://www.example.com/$1 [R=301,L]
# Redirect HTTP to HTTPS
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://www.example.com/$1 [R=301,L]Forcer non-www avec HTTPS
# Force non-www + HTTPS in a single pass
# Works on shared hosting and most Apache setups
RewriteEngine On
# Handle both www removal and HTTPS enforcement together
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^(.*)$ https://%1/$1 [R=301,L]
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]
# Alternative: Using environment variables (some hosts)
# RewriteCond %{ENV:HTTPS} !on
# RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]Gestion du slash final
Des slashs finaux incohérents créent des problèmes de contenu dupliqué qui nuisent au SEO. Les moteurs de recherche traitent /about et /about/ comme des URL différentes. Choisissez un style et appliquez-le de manière cohérente sur l'ensemble de votre site.
Ajouter le slash final
# Add trailing slash to all URLs (except files with extensions)
RewriteEngine On
# Only apply to URLs without a file extension
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !\.[a-zA-Z0-9]{1,5}$
RewriteRule ^(.+[^/])$ %{REQUEST_URI}/ [R=301,L]
# Simpler version (may cause issues with some file types)
# RewriteRule ^(.*[^/])$ $1/ [R=301,L]Supprimer le slash final
# Remove trailing slash from all URLs (except directories)
RewriteEngine On
# Do not remove trailing slash from actual directories
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [R=301,L]
# Remove trailing slash except for root URL
# RewriteCond %{REQUEST_URI} !^/$
# RewriteRule ^(.*)/$ /$1 [R=301,L]Gestion des chaînes de requête
La redirection d'URL avec des chaînes de requête nécessite une attention particulière. Par défaut, Apache ajoute la chaîne de requête originale à la cible. Utilisez les drapeaux QSA et ? pour conserver, supprimer ou modifier les paramètres.
Redirection en conservant la chaîne de requête
# Redirect preserving the original query string (default behavior)
# /search?q=test -> /find?q=test
RewriteEngine On
RewriteRule ^search$ /find [R=301,L]
# Redirect and APPEND additional query parameters (QSA flag)
# /page?id=5 -> /new-page?id=5&ref=old
RewriteRule ^page$ /new-page?ref=old [R=301,L,QSA]
# Match specific query string and redirect
RewriteCond %{QUERY_STRING} ^id=([0-9]+)$
RewriteRule ^product\.php$ /products/%1? [R=301,L]Redirection en supprimant la chaîne de requête
# Redirect and DISCARD all query parameters
# /old-page?any=params -> /new-page (clean URL)
RewriteEngine On
RewriteRule ^old-page$ /new-page? [R=301,L]
# The trailing ? strips the query string
# Discard specific query parameters only
# /page?utm_source=x&id=5 -> /page?id=5 (strip tracking params)
RewriteCond %{QUERY_STRING} (^|&)utm_[^&]*
RewriteRule ^(.*)$ /$1? [R=301,L]Redirection en modifiant les paramètres
# Rewrite query parameter to path segment
# /index.php?page=about -> /about
RewriteEngine On
RewriteCond %{QUERY_STRING} ^page=(.+)$
RewriteRule ^index\.php$ /%1? [R=301,L]
# Rewrite path segment to query parameter
# /category/electronics -> /shop.php?cat=electronics
RewriteRule ^category/([a-zA-Z0-9-]+)$ /shop.php?cat=$1 [L]
# Rename a query parameter
# /search?q=test -> /search?query=test
RewriteCond %{QUERY_STRING} ^q=(.+)$
RewriteRule ^search$ /search?query=%1 [R=301,L]Pages d'erreur personnalisées
Les pages d'erreur personnalisées améliorent l'expérience utilisateur en fournissant des informations utiles. La directive ErrorDocument permet de définir des pages personnalisées pour tout code de statut HTTP.
# Custom error pages
# Place error page files in your document root
# 404 Not Found - page does not exist
ErrorDocument 404 /errors/404.html
# 403 Forbidden - access denied
ErrorDocument 403 /errors/403.html
# 500 Internal Server Error
ErrorDocument 500 /errors/500.html
# 401 Unauthorized - authentication required
ErrorDocument 401 /errors/401.html
# 503 Service Unavailable - maintenance mode
ErrorDocument 503 /errors/maintenance.html
# You can also use inline messages (not recommended for production)
# ErrorDocument 404 "Page not found. Please check the URL."
# Or redirect to an external URL
# ErrorDocument 404 https://example.com/not-found
# ── Maintenance mode (redirect all traffic to maintenance page) ──
# Uncomment during maintenance, recomment when done
# RewriteEngine On
# RewriteCond %{REMOTE_ADDR} !^123\.456\.789\.000$ # Allow your IP
# RewriteCond %{REQUEST_URI} !/errors/maintenance.html$ [NC]
# RewriteCond %{REQUEST_URI} !\.(css|js|png|jpg|gif|ico)$ [NC]
# RewriteRule ^(.*)$ /errors/maintenance.html [R=503,L]En-têtes de sécurité via .htaccess
Les en-têtes de sécurité HTTP protègent votre site contre les attaques courantes comme le clickjacking, le XSS et l'injection de contenu. L'ajout via .htaccess nécessite l'activation de mod_headers.
# Security headers via .htaccess
# Requires mod_headers to be enabled: a2enmod headers
<IfModule mod_headers.c>
# X-Frame-Options: Prevent clickjacking by blocking iframes
# Options: DENY | SAMEORIGIN | ALLOW-FROM uri
Header always set X-Frame-Options "SAMEORIGIN"
# X-Content-Type-Options: Prevent MIME-type sniffing
Header always set X-Content-Type-Options "nosniff"
# X-XSS-Protection: Enable browser XSS filter (legacy)
Header always set X-XSS-Protection "1; mode=block"
# Referrer-Policy: Control referrer information
Header always set Referrer-Policy "strict-origin-when-cross-origin"
# Content-Security-Policy: Control resource loading
# Customize the sources based on your site's needs
Header always set Content-Security-Policy "default-src 'self'; \
script-src 'self' 'unsafe-inline' https://cdn.example.com; \
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; \
img-src 'self' data: https:; \
font-src 'self' https://fonts.gstatic.com; \
connect-src 'self' https://api.example.com; \
frame-ancestors 'self';"
# Strict-Transport-Security (HSTS): Force HTTPS for 2 years
# Only add this if your site fully supports HTTPS
Header always set Strict-Transport-Security \
"max-age=63072000; includeSubDomains; preload"
# Permissions-Policy: Disable unused browser features
Header always set Permissions-Policy \
"camera=(), microphone=(), geolocation=(), interest-cohort=()"
# Remove X-Powered-By header (hides PHP/server version)
Header unset X-Powered-By
Header always unset X-Powered-By
</IfModule>
# Hide Apache version in server headers
ServerSignature OffRègles de cache navigateur
Le cache navigateur améliore considérablement les temps de chargement pour les visiteurs réguliers. Le module mod_expires définit automatiquement les en-têtes Cache-Control et Expires.
# Browser caching with mod_expires
# Enable the module: a2enmod expires
<IfModule mod_expires.c>
ExpiresActive On
# Default expiration: 1 month
ExpiresDefault "access plus 1 month"
# HTML files: short cache (content changes frequently)
ExpiresByType text/html "access plus 1 hour"
# CSS and JavaScript: long cache (use fingerprinted filenames)
ExpiresByType text/css "access plus 1 year"
ExpiresByType application/javascript "access plus 1 year"
ExpiresByType text/javascript "access plus 1 year"
# Images: cache for 1 month
ExpiresByType image/jpeg "access plus 1 month"
ExpiresByType image/png "access plus 1 month"
ExpiresByType image/gif "access plus 1 month"
ExpiresByType image/webp "access plus 1 month"
ExpiresByType image/avif "access plus 1 month"
ExpiresByType image/svg+xml "access plus 1 month"
ExpiresByType image/x-icon "access plus 1 year"
# Fonts: cache for 1 year
ExpiresByType font/woff2 "access plus 1 year"
ExpiresByType font/woff "access plus 1 year"
ExpiresByType font/ttf "access plus 1 year"
ExpiresByType application/font-woff2 "access plus 1 year"
ExpiresByType application/font-woff "access plus 1 year"
# JSON/XML data: short cache
ExpiresByType application/json "access plus 1 hour"
ExpiresByType application/xml "access plus 1 hour"
# PDF and documents
ExpiresByType application/pdf "access plus 1 month"
</IfModule>
# Alternative: Cache-Control headers with mod_headers
<IfModule mod_headers.c>
# Immutable cache for fingerprinted assets
<FilesMatch "\.(js|css)$">
Header set Cache-Control "public, max-age=31536000, immutable"
</FilesMatch>
# Short cache for HTML
<FilesMatch "\.html$">
Header set Cache-Control "public, max-age=3600, must-revalidate"
</FilesMatch>
# No cache for dynamic content
<FilesMatch "\.(php|cgi)$">
Header set Cache-Control "no-store, no-cache, must-revalidate"
</FilesMatch>
</IfModule>Compression Gzip / Brotli
La compression réduit la taille des réponses de 60 à 90%, améliorant significativement les temps de chargement. Apache supporte Gzip (via mod_deflate) et Brotli (via mod_brotli, Apache 2.4.26+).
Compression Gzip (mod_deflate)
# Gzip compression using mod_deflate
# Enable the module: a2enmod deflate
<IfModule mod_deflate.c>
# Compress text-based content types
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/javascript
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/atom+xml
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/x-javascript
AddOutputFilterByType DEFLATE application/json
AddOutputFilterByType DEFLATE application/ld+json
AddOutputFilterByType DEFLATE application/vnd.ms-fontobject
AddOutputFilterByType DEFLATE font/opentype
AddOutputFilterByType DEFLATE font/ttf
AddOutputFilterByType DEFLATE font/woff
AddOutputFilterByType DEFLATE font/woff2
AddOutputFilterByType DEFLATE image/svg+xml
AddOutputFilterByType DEFLATE image/x-icon
# Do not compress images (already compressed)
SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png|webp|avif)$ no-gzip
# Handle browser quirks
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4\.0[678] no-gzip
BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
# Add Vary header for proper caching
Header append Vary Accept-Encoding
</IfModule>Compression Brotli (mod_brotli)
# Brotli compression using mod_brotli (Apache 2.4.26+)
# Enable the module: a2enmod brotli
<IfModule mod_brotli.c>
# Compress text-based content types with Brotli
AddOutputFilterByType BROTLI_COMPRESS text/plain
AddOutputFilterByType BROTLI_COMPRESS text/html
AddOutputFilterByType BROTLI_COMPRESS text/xml
AddOutputFilterByType BROTLI_COMPRESS text/css
AddOutputFilterByType BROTLI_COMPRESS text/javascript
AddOutputFilterByType BROTLI_COMPRESS application/xml
AddOutputFilterByType BROTLI_COMPRESS application/xhtml+xml
AddOutputFilterByType BROTLI_COMPRESS application/javascript
AddOutputFilterByType BROTLI_COMPRESS application/json
AddOutputFilterByType BROTLI_COMPRESS application/ld+json
AddOutputFilterByType BROTLI_COMPRESS font/opentype
AddOutputFilterByType BROTLI_COMPRESS font/ttf
AddOutputFilterByType BROTLI_COMPRESS font/woff
AddOutputFilterByType BROTLI_COMPRESS font/woff2
AddOutputFilterByType BROTLI_COMPRESS image/svg+xml
# Brotli compression quality (0-11, default: 11)
# Lower = faster compression, larger files
# Higher = slower compression, smaller files
BrotliCompressionQuality 6
# Brotli window size (10-24, default: 22)
BrotliCompressionWindow 22
</IfModule>
# Fallback: Use Gzip if Brotli is not available
# Both modules can coexist; Apache serves Brotli to
# browsers that support it and Gzip to others.Erreurs courantes et corrections
Le débogage des problèmes .htaccess peut être frustrant. Voici les erreurs les plus courantes et comment les éviter.
Boucles de redirection infinies
L'erreur la plus courante est de créer une boucle où l'URL réécrite correspond à nouveau à la même règle. Utilisez toujours RewriteCond pour vérifier l'état actuel et le drapeau [L] pour arrêter le traitement.
# BAD: Creates an infinite loop
# (The rewritten URL "/new" matches "^(.*)$" again)
RewriteRule ^(.*)$ /new/$1 [R=301]
# GOOD: Use RewriteCond to prevent the loop
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/new/ [NC]
RewriteRule ^(.*)$ /new/$1 [R=301,L]
# GOOD: Another approach - check if already redirected
RewriteEngine On
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^(.*)$ /new/$1 [R=301,L]Mauvais RewriteBase
RewriteBase définit le chemin URL de base pour les réécritures par répertoire. Si votre .htaccess est dans un sous-répertoire, le RewriteBase doit correspondre à ce chemin.
# If .htaccess is in the document root:
RewriteEngine On
RewriteBase /
# If .htaccess is in /blog/ subdirectory:
RewriteEngine On
RewriteBase /blog/
# If .htaccess is in /app/public/ subdirectory:
RewriteEngine On
RewriteBase /app/public/
# Common mistake: Using RewriteBase /blog when file is at root
# This causes all rewritten URLs to be prefixed with /blogL'ordre des règles compte
Apache traite les règles de haut en bas. Si une règle générale précède une règle spécifique, elle correspondra en premier. Placez toujours les règles spécifiques avant les générales et utilisez le drapeau [L].
# BAD: General rule before specific rule
RewriteEngine On
RewriteRule ^(.*)$ /index.php?page=$1 [L] # Catches everything!
RewriteRule ^about$ /about-us.html [R=301,L] # Never reached!
# GOOD: Specific rules first, general rules last
RewriteEngine On
RewriteRule ^about$ /about-us.html [R=301,L] # Specific: runs first
RewriteRule ^contact$ /contact-us.html [R=301,L] # Specific: runs second
RewriteCond %{REQUEST_FILENAME} !-f # Skip existing files
RewriteCond %{REQUEST_FILENAME} !-d # Skip existing dirs
RewriteRule ^(.*)$ /index.php?page=$1 [L] # General: fallback| Erreur | Correction |
|---|---|
| RewriteEngine On manquant | Ajoutez toujours "RewriteEngine On" en haut du bloc de règles |
| Points non échappés dans les motifs | Utilisez \. au lieu de . dans les motifs regex |
| Oubli du drapeau [L] | Ajoutez [L] pour arrêter le traitement après une correspondance |
| Mélange de Redirect et RewriteRule | Utilisez une seule méthode ; le mélange cause un comportement imprévisible |
| Test sans vider le cache du navigateur | Les redirections 301 sont mises en cache ; utilisez 302 pendant les tests |
| Mauvaises permissions sur .htaccess | Définissez les permissions à 644 |
Questions fréquemment posées
Qu'est-ce que .htaccess et où le placer ?
.htaccess est un fichier de configuration distribué pour les serveurs web Apache. Placez-le dans le répertoire racine de votre site (généralement public_html ou www). Il affecte le répertoire et tous ses sous-répertoires. Le fichier doit être nommé exactement ".htaccess" avec le point initial.
Quelle est la différence entre les redirections 301 et 302 ?
Une redirection 301 est permanente : elle indique aux moteurs de recherche de transférer la valeur des liens vers la nouvelle URL. Une 302 est temporaire : les moteurs gardent l'URL originale dans leur index. Utilisez 301 pour les déplacements permanents et 302 pour les situations temporaires. Les navigateurs mettent en cache les 301, utilisez donc 302 pendant les tests.
Pourquoi mes règles .htaccess ne fonctionnent-elles pas ?
Causes les plus courantes : 1) mod_rewrite non activé ; 2) AllowOverride réglé sur None ; 3) Permissions de fichier incorrectes (devrait être 644) ; 4) Erreurs de syntaxe (vérifiez le log d'erreurs Apache) ; 5) Le navigateur a mis en cache une redirection 301 précédente.
.htaccess fonctionne-t-il avec Nginx ?
Non, .htaccess est spécifique à Apache. Nginx ne supporte pas les fichiers .htaccess. Avec Nginx, vous devez ajouter les directives équivalentes directement dans la configuration du bloc server. Des outils en ligne existent pour convertir les règles .htaccess en syntaxe Nginx.
Comment rediriger les anciennes URL après une refonte ?
Créez une correspondance des anciennes vers les nouvelles URL. Pour les changements basés sur des motifs, utilisez RewriteRule avec des groupes de capture : RewriteRule ^blog/(.*)$ /articles/$1 [R=301,L]. Testez toujours avec curl -I pour vérifier le code de statut et la destination.
Comment .htaccess affecte-t-il les performances du site ?
Apache lit les fichiers .htaccess à chaque requête, ce qui ajoute un léger surcoût. Pour les sites à fort trafic, déplacez les règles dans la configuration principale Apache. Pour la plupart des sites, l'impact est négligeable et la commodité de .htaccess l'emporte.
Ce guide .htaccess couvre les modèles de redirection essentiels, les configurations de sécurité et les optimisations de performance. Testez toujours vos modifications avec curl avant le déploiement en production et conservez une sauvegarde de votre fichier .htaccess fonctionnel.