<!--
  canonical-url: https://www.avonture.be/fr/blog/apache-htaccess
  published:     2023-11-03
  This is a static plain-Markdown mirror generated at build time.
  Visit the canonical URL above for the fully rendered page, with images and interactive components.
-->

# Le fichier .htaccess d'Apache

> Maîtrisez votre fichier .htaccess Apache avec des astuces essentielles pour la sécurité, les redirections, le contrôle d'accès aux fichiers, la Content Security Policy (CSP), le forçage du HTTPS et l'optimisation des performances.

---
![Le fichier .htaccess d'Apache](/img/v2/htaccess.webp)

**TL;DR**

Voici une large référence de snippets `.htaccess` prêts à l'emploi : en-têtes Content Security Policy, blocage de fichiers par nom / extension / préfixe point (fichiers cachés), affichage inline forcé ou téléchargement forcé, forçage du HTTPS+www avec preload HSTS, mode maintenance, compression gzip et en-têtes expires, contrôle d'accès par IP, protection contre le clickjacking et le MIME-sniffing, désactivation de l'exécution de scripts ou du listing de répertoires, protection par mot de passe de fichiers/dossiers, différents schémas de redirection, et blocage de l'indexation d'un dossier par les moteurs de recherche.

Quelques trucs et astuces pour votre fichier .htaccess (Apache).

*Ces directives fonctionnent sur n'importe quel serveur Apache, y compris celui, jetable, que vous pouvez démarrer localement en quelques secondes avec [Running an HTML site in seconds using Docker](/blog/docker-html-site) — une manière pratique de tester une règle de redirection avant de la pousser en production.*

## CSP - Content Security Policy {#csp---content-security-policy}

Utilisez les lignes suivantes comme source d'inspiration :

**.htaccess**

```
<IfModule mod_headers.c>

   # Add CSP (Content Security Policy)
   Header set Protected-by "What-you-want-or-just-drop-this-line"

   # Replace XXXXXXXXXXXXXX by your site name like www.yoursite.com
   Header always set Feature-Policy "camera 'none'; fullscreen 'self'; microphone 'none'; payment 'none'; sync-xhr 'self' XXXXXXXXXXXXXX"

   # Blocks a request if the requested type is
   #    "style" and the MIME type is not "text/css", or
   #    "script" and the MIME type is not a JavaScript MIME type.
   Header set X-Content-Type-Options "nosniff"

   # Prevent from Clickjacking by allowing frame to be displayed only
   # on the same origin as the page itself.
   Header always set X-Frame-Options SAMEORIGIN

   # Force HTTPS (don't use this if you're still on http)
   # env=HTTPS didn't work... but while "expr=%{HTTPS} == 'on'" is well working
   # see https://stackoverflow.com/questions/24144552/how-to-set-hsts-header-from-htaccess-only-on-https#comment81632711_24145033
   Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" "expr=%{HTTPS} == 'on'"

   # Enables XSS filtering. Rather than sanitizing the page, the browser
   # will prevent rendering of the page if an attack is detected.
   Header always set X-XSS-Protection "1; mode=block"

   # The Referrer header will be omitted entirely. No referrer information is
   # sent along with requests.
   Header always set Referrer-Policy "no-referrer"

   # CSP : define / whitelist domains where files can be loaded
   # (f.i. fonts.googleapis.com, ...)
   # This should be done for scripts, images, styles, frame, ...
   # Replace XXXXXXXXXXXXXX by your site name like https://www.yoursite.com
   # ----------------------------------------------------------------------
   # UNCOMMENT THE FOLLOWING LINE ONLY IF YOU KNOW WHAT YOU'RE DOING.
   # THIS LINE CAN BREAK YOUR SITE SO, ENABLE IT AND TEST YOUR SITE A LOT,
   # ALL PAGES IF POSSIBLE.
   # ----------------------------------------------------------------------
   #Header set Content-Security-Policy: "default-src 'self'; base-uri 'self'; form-action 'none'; script-src 'self' 'unsafe-eval' 'unsafe-inline' https://ajax.googleapis.com https://www.google.com https://www.google-analytics.com https://code.jquery.com https://www.gstatic.com https://maxcdn.bootstrapcdn.com https://cdnjs.cloudflare.com https://stackpath.bootstrapcdn.com https://unpkg.com; font-src 'self' data: https://fonts.googleapis.com https://fonts.gstatic.com https://maxcdn.bootstrapcdn.com; style-src 'self' 'unsafe-inline' https://maxcdn.bootstrapcdn.com https://fonts.googleapis.com https://cdnjs.cloudflare.com https://stackpath.bootstrapcdn.com; img-src 'self' data: https://www.paypal.com https://raw.githubusercontent.com; frame-src XXXXXXXXXXXXXX https://www.google.com https://www.youtube.com; frame-ancestors 'none'"
</IfModule>
```

## Fichiers {#files}

### Bloquer l'accès à certains fichiers selon leur nom {#block-access-to-some-files-based-on-their-names}

Bloquer les requêtes vers ces fichiers :

**.htaccess**

```
<FilesMatch "(file_1\.gif|file_2\.png)">
    Order Allow,Deny
    Deny from all
</FilesMatch>
```

### Bloquer l'accès à certains fichiers selon leur extension {#block-access-to-some-files-based-on-their-extensions}

Bloquer l'accès à tous les fichiers sauf ceux dont l'extension est mentionnée dans la liste ci-dessous :

Première option :

**.htaccess**

```
RewriteCond %{REQUEST_FILENAME} !(.*)\.(bmp|css|eot|html?|icon?|jpe?g|js|gif|pdf|png|svg|te?xt|ttf|webp|woff2?|xml|zip)$
RewriteRule . - [F]
```

Deuxième option :

**.htaccess**

```
RewriteCond %{REQUEST_FILENAME} !\.(ico?n|img|gif|jpe?g|png|css|map)$ [NC]
RewriteCond %{REQUEST_FILENAME} !\.js(\?.*)?$ [NC]
RewriteCond %{REQUEST_FILENAME} !\.(eot|svg|ttf|woff2?)(\?.*)?$ [NC]
# Comment this line if you wish to make possible to access the /libraries folder by url.
RewriteRule . - [F]
```

### Bloquer l'accès aux fichiers et dossiers cachés {#block-access-to-hidden-files--directories}

Bloquer l'accès à un fichier ou un dossier dont le nom commence par un point (autrement dit, un fichier ou un dossier caché) :

**.htaccess**

```
<IfModule mod_rewrite.c>
    RewriteCond %{SCRIPT_FILENAME} -d [OR]
    RewriteCond %{SCRIPT_FILENAME} -f
    RewriteRule "(^|/)\." - [F]
</IfModule>
```

## Forcer {#force}

### Forcer l'affichage {#force-display}

Ne laissez pas le navigateur télécharger ces fichiers, mais dites-lui comment les afficher (du texte dans l'exemple) :

**.htaccess**

```
<FilesMatch "\.(tex|log|aux)$">
    Header set Content-Type text/plain
</FilesMatch>
```

#### Empêcher le téléchargement {#prevent-downloading}

Par exemple, forcer le téléchargement des fichiers PDF :

**.htaccess**

```
<FilesMatch "\.(pdf)$">
    ForceType application/octet-stream
    Header set Content-Disposition attachment
</FilesMatch>
```

#### Forcer https et www, compatible hstspreload {#force-https-and-www-compatible-hstspreload}

> Une fois implémenté dans votre .htaccess, un accès à `yoursite.com` ou `http://yoursite.com` doit rediriger vers `https://www.yoursite.com`.

Testez aussi votre site avec <https://hstspreload.org/> pour vérifier que votre preloading est correct (vert).

**.htaccess**

```
<IfModule mod_rewrite.c>

 # Rewrite the URL to force https and www.
 RewriteEngine On

 # Compliant with hstspreload.org : first redirect to https if needed
 RewriteCond %{HTTPS} !=on
 RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

 #   then redirect to www. when the prefix wasn't mentioned
 # hstspreload.org seems to not really like to make the two at once
 RewriteCond %{HTTP_HOST} !^www\.
 RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

</IfModule>
```

## Divers {#misc}

### Désactiver l'affichage des erreurs {#disable-error-reporting}

Ne pas afficher les erreurs (exactement comme le fait `error_reporting(0)`)

**.htaccess**

```
<IfModule mod_php5.c>
    php_flag display_errors off
    php_flag log_errors on
    php_flag track_errors on
    php_value error_log error.log
</IfModule>
```

#### Activer l'affichage des erreurs {#enable-error-reporting}

Afficher les erreurs (exactement comme le fait `error_reporting = E_ALL`).

À n'utiliser que sur un serveur de développement, sinon vous exposez des informations sensibles à vos visiteurs.

**.htaccess**

```
<IfModule mod_php5.c>
    php_flag display_errors on
    php_flag log_errors on
    php_flag track_errors on
    php_value error_log error.log
</IfModule>
```

#### Activer un mode maintenance {#enable-a-maintenance-mode}

Rediriger toutes les requêtes faites vers votre site vers une page spécifique (appelée `maintenance.php` ci-dessous). N'oubliez pas de remplacer le code `ADD_YOUR_IP_HERE` par votre adresse IP actuelle.

**.htaccess**

```
<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REMOTE_ADDR} !127.0.0.1 [NC]
    RewriteCond %{REMOTE_ADDR} !localhost [NC]
    RewriteCond %{REMOTE_ADDR} !ADD_YOUR_IP_HERE [NC]
    RewriteCond %{REQUEST_FILENAME} !maintenance.php(.*)$ [NC]
    RewriteRule .* /maintenance.php [L,NC,QSA]
</IfModule>
```

## Optimisation {#optimization}

### Compresser les fichiers selon leur type ou leur extension {#compress-files-based-on-their-type-or-extensions}

**.htaccess**

```
<IfModule mod_deflate.c>
    SetOutputFilter DEFLATE
    <IfModule mod_filter.c>
        AddOutputFilterByType DEFLATE application/font-otf application/font-ttf application/font-woff application/javascript application/json application/manifest+json application/rss+xml application/vnd.ms-fontobject application/xhtml+xml application/xml application/x-javascript image/svg+xml text/css text/csv text/html text/javascript text/plain text/xml
    </IfModule>
</IfModule>

# On some hosting companies, mod_deflate isn't installed but well mod_gzip.
<IfModule mod_gzip.c>
    mod_gzip_on Yes
    mod_gzip_dechunk Yes
    mod_gzip_item_include file      \.(html?|txt|css|js|php|pl)$
    mod_gzip_item_include handler   ^cgi-script$
    mod_gzip_item_include mime      ^text/.*
    mod_gzip_item_include mime      ^application/font-otf
    mod_gzip_item_include mime      ^application/font-ttf
    mod_gzip_item_include mime      ^application/font-woff
    mod_gzip_item_include mime      ^application/vnd.ms-fontobject
    mod_gzip_item_include mime      ^application/x-javascript.*
    mod_gzip_item_exclude mime      ^image/.*
    mod_gzip_item_include mime      ^image/svg+xml*
    mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*
</IfModule>
```

### Ajouter une expiration (en-têtes expires) {#add-expiration-expires-headers}

Activer les ETags

**.htaccess**

```
<IfModule mod_headers.c>
    # Keep the connection alive (not really related to expirations but really increase download speed
    Header set Connection keep-alive
</IfModule>

<IfModule mod_expires.c>

    ExpiresActive On

    # Default expiration: 1 hour after request
    ExpiresDefault "access plus 1 month"

    # CSS and JS expiration
    ExpiresByType text/css "access 1 month"
    ExpiresByType text/javascript "access 1 month"
    ExpiresByType application/javascript "access 1 month"
    ExpiresByType application/x-javascript "access 1 month"

    # webfonts
    ExpiresByType application/vnd.ms-fontobject "access plus 1 month"
    ExpiresByType application/x-font-woff "access 1 year"
    ExpiresByType application/x-font-woff2 "access 1 year"
    ExpiresByType font/eot "access plus 1 month"
    ExpiresByType font/truetype "access 1 year"
    ExpiresByType font/opentype "access 1 year"
    ExpiresByType font/woff "access 1 year"
    ExpiresByType image/svg+xml "access 1 year"
    ExpiresByType application/vnd.ms-fontobject "access 1 year"
    ExpiresByType application/font-otf "access 1 year"
    ExpiresByType application/font-ttf "access 1 year"
    ExpiresByType application/font-woff "access 1 year"
    ExpiresByType application/x-font-ttf "access 1 year"

    # Media
    AddType image/vnd.microsoft.icon .cur
    ExpiresByType application/ico "access 1 year"
    ExpiresByType audio/ogg "access plus 1 month"
    ExpiresByType image/bmp "access plus 1 month"
    ExpiresByType image/gif "access 1 month"
    ExpiresByType image/ico "access 1 year"
    ExpiresByType image/icon "access 1 year"
    ExpiresByType image/jpg "access 1 month"
    ExpiresByType image/jpeg "access 1 month"
    ExpiresByType image/png "access 1 month"
    ExpiresByType image/svg+xml "access 1 month"
    ExpiresByType image/vnd.microsoft.icon "access 1 year"
    ExpiresByType image/webp "access 1 month"
    ExpiresByType image/x-icon "access 1 year"
    ExpiresByType text/ico "access 1 year"
    ExpiresByType video/mp4 "access plus 1 month"
    ExpiresByType video/ogg "access plus 1 month"
    ExpiresByType video/webm "access plus 1 month"

    # Flash
    ExpiresByType application/x-shockwave-flash "access plus 2 months"
    ExpiresByType image/swf "access plus 2592000 seconds"

    # Files
    ExpiresByType application/pdf "access 1 week"
    ExpiresByType application/x-gzip "access 1 month"
    ExpiresByType text/x-component "access 1 month"

    # Data
    ExpiresByType application/atom+xml "access plus 1 hour"
    ExpiresByType application/rdf+xml "access plus 1 hour"
    ExpiresByType application/rss+xml "access plus 1 hour"
    ExpiresByType text/html "access plus 0 seconds"
    ExpiresByType application/json "access plus 0 seconds"
    ExpiresByType application/ld+json  "access plus 0 seconds"
    ExpiresByType application/schema+json "access plus 0 seconds"
    ExpiresByType application/vnd.geo+json "access plus 0 seconds"
    ExpiresByType application/xml "access plus 0 seconds"
    ExpiresByType text/xml "access plus 0 seconds"
</IfModule>

# Perhaps the MIME type of SWF is incorrect, in this case, the FileMatch will do the job
<IfModule mod_headers.c>
    <FilesMatch "\.(swf)$">
        Header set Expires "access plus 2592000 seconds"
    </FilesMatch>
</IfModule>
```

## Protection {#protection}

*Durcir votre `.htaccess` vous protège pour l'avenir ; si vous suspectez que le site a **déjà** été compromis, commencez par [aeSecure - QuickScan - Free viruses scanner](/blog/aesecure-quickscan).*

### Refuser tout accès {#deny-all-access}

**.htaccess**

```
## Apache 2.2
Deny from all

## Apache 2.4
# Require all denied
```

### Refuser tout accès sauf le vôtre {#deny-all-access-except-you}

Remplacez simplement `xxx.xxx.xxx.xxx` par votre adresse IP.

**.htaccess**

```
## Apache 2.2
Order deny,allow
Deny from all
Allow from xxx.xxx.xxx.xxx

## Apache 2.4
# Require all denied
# Require ip xxx.xxx.xxx.xxx
```

### Empêcher le navigateur de faire du MIME-sniffing {#stops-a-browser-from-trying-to-mime-sniff}

**.htaccess**

```
<IfModule mod_headers.c>
    Header always set X-Content-Type-Options "nosniff"
</IfModule>
```

### Éviter le clickjacking et activer la protection XSS des navigateurs {#avoid-clickjacking-and-enable-xss-protection-for-browsers}

**.htaccess**

```
<FilesMatch "\.(pl|php|cgi|spl)$">
    <IfModule mod_headers.c>
        # security
        Header set X-Frame-Options "DENY"
        Header set X-XSS-Protection "1; mode=block"
    </IfModule>
</FilesMatch>
```

### Désactiver l'exécution des scripts {#disable-script-execution}

Placez ces lignes dans, par exemple, `/tmp/.htaccess` pour empêcher l'exécution de scripts dans le dossier `/tmp`.

**/tmp/.htaccess**

```
# secure directory by disabling script execution
AddHandler cgi-script .php .pl .py .jsp .asp .sh .cgi
Options -ExecCGI

##Deny access to all CGI, Perl, PHP and Python
<FilesMatch "\.(asp?x|cgi|php|pl|py)$">
    Deny from all
</FilesMatch>
```

### Interdire le listing des répertoires {#disallow-listing-for-directories}

Ne laissez pas le serveur web fournir la liste des fichiers / dossiers comme le fait une commande `dir`.

**.htaccess**

```
<IfModule mod_autoindex.c>
    Options -Indexes
</IfModule>
```

### htpasswd {#htpasswd}

* Générateur de `.htpasswd` : <http://aspirine.org/htpasswd.html>

#### Mot de passe sur un fichier {#file-password}

**.htaccess**

```
AuthName "File access restriction"
AuthType Basic
AuthUserFile /home/your_account/.htpasswd

<Files "confidential.md">
Require valid-user
</Files>
```

#### Mot de passe sur un dossier {#folder-password}

Placez ces lignes dans un fichier nommé `.htaccess` dans le dossier à protéger (par ex. `folder_name`) :

**folder\_name/.htaccess**

```
AuthType Basic
AuthName "This folder is protected"
AuthUserFile /home/your_account/folder_name/.htpasswd
Require valid-user
```

### Whitelist - Interdire l'accès à tous les fichiers sauf ceux mentionnés {#whitelist---disallow-access-to-all-files-except-the-ones-mentioned}

**.htaccess**

```
# prevent accessing to all files excepted those mentioned (case sensitive!)

<FilesMatch "(?<!\.png|\.jpe?g|\.gif|\.svg|\.icon?)$">
# Apache 2.2
#    deny from all
# Apache 2.4
#    Require all denied
</FilesMatch>
```

## Redirection {#redirect}

### Rediriger un site entier {#redirect-an-entire-site}

**.htaccess**

```
Redirect 301 / https://www.newsite.com/
```

### Redirection permanente {#permanent-redirection}

**.htaccess**

```
RedirectPermanent /old.php http://www.yoursite.com/new.php
```

### Redirection temporaire {#temporary-redirection}

**.htaccess**

```
Redirect 301 /old.php http://www.yoursite.com/new.php
```

### Rediriger un sous-dossier {#redirect-a-subfolder}

Par exemple, rediriger `/category/apple.php` vers `apple.php`

**.htaccess**

```
RedirectMatch 301 ^/category/(.*)$ /$1
```

ou régler des problèmes d'orthographe en redirigeant par exemple toutes les requêtes vers le dossier `fruit` vers sa forme au pluriel.

**.htaccess**

```
RedirectMatch 301 ^/fruit/(.*)$ /fruits/$1
```

Autre exemple : rediriger les URL de `/archive/2020/...` vers `/2020/...`.

**.htaccess**

```
RewriteRule ^archive/2020/(.*)$ /2020/$1 [R=301,NC,L]
```

## Moteurs de recherche {#search-engine}

### Interdire l'indexation {#disallow-indexing}

Placez ces lignes dans, par exemple, `yoursite/administrator` pour informer les moteurs de recherche que vous ne les autorisez pas à indexer les fichiers de ce dossier (et de ses sous-dossiers).

**administrator/.htaccess**

```
# Be sure that pages under this folder won't be indexed

<IfModule mod_headers.c>
    Header set X-Robots-Tag "noindex, nofollow"
</IfModule>
```
