# Robots d'IA avec Apache 2.4 - robots.txt, .htaccess, Require not env et plages IP

> Refuser les robots d'entraînement avec Apache 2.4 via .htaccess, mod_setenvif ou mod_rewrite, et n'accepter les robots de recherche que depuis leurs plages IP.

Source : https://iabig.com/fr/plateformes/robots-ia-apache/ — Guides CC BY 4.0, extraits de code MIT

Apache HTTP Server offre plusieurs façons de traiter les robots d'IA, selon l'accès dont vous disposez : un simple fichier `.htaccess` sur un hébergement mutualisé, ou la configuration complète de l'hôte virtuel sur votre propre serveur. Ce guide couvre les deux, avec la même politique que nos autres guides : refuser l'entraînement, laisser passer les robots de recherche de ChatGPT, Claude et Perplexity, et, quand c'est possible, refuser ceux qui empruntent leur nom sans venir des adresses de leur éditeur. Toutes les configurations ci-dessous ont été validées avec `httpd -t` puis par des requêtes réelles sur Apache 2.4.69 (compilation Windows d'Apache Lounge) ; la syntaxe est celle d'Apache 2.4, et une section dédiée résume ce qui change par rapport à la 2.2.

## robots.txt reste la base

Le fichier se place à la racine du site (le `DocumentRoot`). C'est lui qui exprime vos choix auprès des robots qui les respectent, et le seul moyen de refuser l'entraînement à Google (`Google-Extended`) ou à Apple (`Applebot-Extended`) : ces jetons ne correspondent à aucun robot distinct, donc aucune règle serveur ne peut les viser. Un robots.txt refusé en 403 empêche le robot d'y lire votre refus, et la RFC 9309 assimile une erreur 5xx sur ce fichier à une interdiction totale : chaque configuration ci-dessous exclut donc `/robots.txt` du blocage.

## Version .htaccess avec mod_setenvif

C'est la méthode recommandée en 2.4 : `SetEnvIfNoCase` pose une variable d'environnement quand le User-Agent correspond, puis `Require not env` refuse les requêtes qui la portent.

```apache
# .htaccess à la racine du site - Apache 2.4
# Nécessite : AllowOverride FileInfo (SetEnvIf) et AuthConfig (Require, AuthMerging)

# 1. Robots refusés (ici : entraînement ; à adapter). Recherche insensible à la casse.
SetEnvIfNoCase User-Agent "GPTBot"             refus_ia
SetEnvIfNoCase User-Agent "ClaudeBot"          refus_ia
SetEnvIfNoCase User-Agent "CCBot"              refus_ia
SetEnvIfNoCase User-Agent "Bytespider"         refus_ia
SetEnvIfNoCase User-Agent "meta-externalagent" refus_ia

# 2. robots.txt reste lisible par tous : on retire la variable
SetEnvIf Request_URI "^/robots\.txt$" !refus_ia

# 3. Combiner avec les règles d'accès déjà définies au-dessus (ET logique)
AuthMerging And

# 4. Tout le monde, sauf les requêtes marquées
<RequireAll>
    Require all granted
    Require not env refus_ia
</RequireAll>
```

Trois détails comptent. Un `Require not` ne peut jamais autoriser seul une requête : la documentation d'Apache impose de l'associer à une condition positive, ici `Require all granted`, dans un bloc `<RequireAll>`. Ensuite, sans `AuthMerging And`, les règles d'accès d'un `.htaccess` remplacent celles des sections parentes : un `Require all granted` posé à la racine pourrait rouvrir un site que la configuration du serveur limitait, par exemple à certaines adresses. Enfin, les directives d'un `.htaccess` ne sont lues que si `AllowOverride` le permet ; depuis Apache 2.4, sa valeur par défaut est `None`.

## Version .htaccess avec mod_rewrite

Si `mod_rewrite` est déjà utilisé sur le site, ou si l'hébergeur n'autorise pas `AuthConfig`, la même règle s'écrit ainsi :

```apache
# .htaccess - variante mod_rewrite (AllowOverride FileInfo suffit)
RewriteEngine On
# Ne jamais bloquer robots.txt
RewriteCond %{REQUEST_URI} !^/robots\.txt$
# [NC] : comparaison insensible à la casse
RewriteCond %{HTTP_USER_AGENT} (GPTBot|ClaudeBot|CCBot|Bytespider|meta-externalagent) [NC]
# [F] : réponse 403 Forbidden, fin du traitement des règles
RewriteRule ^ - [F]
```

Lors de nos essais, les deux variantes donnaient le même résultat : 403 pour `gptbot` et `CCBot`, 200 pour `GPTBot` sur `/robots.txt`, 200 pour `OAI-SearchBot` et pour un navigateur.

## Configuration serveur avec vérification des plages IP

Sur votre propre serveur, on peut aller plus loin : n'accepter un robot de recherche que s'il vient des plages publiées par son éditeur. Les listes d'adresses vivent dans des fichiers séparés, générés par un script, et sont incluses dans l'hôte virtuel.

```apache
# Dans <VirtualHost *:443> - Apache 2.4.16 ou plus récent
# Modules : setenvif, authz_core, authz_host, log_config

# 1. Éditeur revendiqué par le User-Agent
SetEnvIfNoCase User-Agent "GPTBot|OAI-SearchBot|ChatGPT-User"       editeur_ia=openai
SetEnvIfNoCase User-Agent "ClaudeBot|Claude-SearchBot|Claude-User" editeur_ia=anthropic
SetEnvIfNoCase User-Agent "PerplexityBot|Perplexity-User"          editeur_ia=perplexity

# 2. Robots refusés par principe (entraînement), sauf sur robots.txt
SetEnvIfNoCase User-Agent "GPTBot|ClaudeBot|CCBot|Bytespider|meta-externalagent" refus_ia
SetEnvIf Request_URI "^/robots\.txt$" !refus_ia

# 3. Journal dédié : uniquement les requêtes d'un robot d'IA annoncé
LogFormat "%h %t \"%r\" %>s robot=%{editeur_ia}e refus=%{refus_ia}e \"%{User-Agent}i\"" robots_ia
CustomLog ${APACHE_LOG_DIR}/robots-ia.log robots_ia env=editeur_ia

<Location "/">
    # Ne remplace pas les règles des <Directory> : s'y ajoute
    AuthMerging And
    <RequireAll>
        Require not env refus_ia
        <RequireAny>
            # Aucun robot d'IA annoncé : rien à vérifier
            Require expr "-z %{ENV:editeur_ia}"
            # robots.txt toujours accessible
            Require expr "%{REQUEST_URI} == '/robots.txt'"
            # Robot annoncé : il doit venir des plages de son éditeur
            <RequireAll>
                Require expr "%{ENV:editeur_ia} == 'openai'"
                Include /etc/apache2/robots-ia/openai.conf
            </RequireAll>
            <RequireAll>
                Require expr "%{ENV:editeur_ia} == 'anthropic'"
                Include /etc/apache2/robots-ia/anthropic.conf
            </RequireAll>
            <RequireAll>
                Require expr "%{ENV:editeur_ia} == 'perplexity'"
                Include /etc/apache2/robots-ia/perplexity.conf
            </RequireAll>
        </RequireAny>
    </RequireAll>
</Location>
```

Chaque fichier inclus contient un bloc `<RequireAny>` de lignes `Require ip`. Ce bloc est indispensable : plusieurs `Require ip` placés directement dans un `<RequireAll>` devraient tous réussir à la fois, ce qui est impossible. `Require ip` accepte la notation CIDR, en IPv4 comme en IPv6. Le script suivant, exécuté contre les fichiers officiels le 25 octobre 2026, produit ces fichiers et ne recharge Apache que si la configuration reste valide.

```bash
#!/usr/bin/env bash
# /usr/local/sbin/maj-robots-ia-apache.sh - dépend de curl et jq
set -euo pipefail
dossier=/etc/apache2/robots-ia

genere() {  # $1 = éditeur, puis les URL des fichiers JSON officiels
  local editeur=$1; shift
  local tmp; tmp=$(mktemp)
  for url in "$@"; do
    # -L : perplexity.com redirige vers perplexity.ai
    curl -fsSL --max-time 30 "$url" \
      | jq -er '.prefixes[] | (.ipv4Prefix // .ipv6Prefix) | select(. != null)' >> "$tmp"
  done
  [ -s "$tmp" ] || { echo "liste vide pour $editeur, abandon" >&2; rm -f "$tmp"; exit 1; }
  { echo "<RequireAny>"
    sort -u "$tmp" | sed 's/^/    Require ip /'
    echo "</RequireAny>"; } > "$dossier/$editeur.conf.new"
  rm -f "$tmp"
}

genere openai     https://openai.com/gptbot.json https://openai.com/searchbot.json https://openai.com/chatgpt-user.json
genere anthropic  https://claude.com/crawling/bots.json
genere perplexity https://www.perplexity.com/perplexitybot.json https://www.perplexity.com/perplexity-user.json

for e in openai anthropic perplexity; do
  cp -p "$dossier/$e.conf" "$dossier/$e.conf.bak" 2>/dev/null || true
  mv "$dossier/$e.conf.new" "$dossier/$e.conf"
done

if ! apachectl configtest; then
  for e in openai anthropic perplexity; do
    [ -f "$dossier/$e.conf.bak" ] && mv "$dossier/$e.conf.bak" "$dossier/$e.conf"
  done
  echo "configuration refusée, anciennes listes restaurées" >&2
  exit 1
fi
apachectl graceful
```

Lancez-le une première fois avant d'ajouter le bloc `<Location>`, sinon les `Include` pointent vers des fichiers absents ; puis planifiez-le chaque jour avec cron. Sur Debian et Ubuntu, la commande s'appelle aussi `apache2ctl`. Pour contrôler à la main une adresse trouvée dans le journal, le [vérificateur d'IP de robots IABIG](/fr/outils/verifier-ip-robot/) interroge les mêmes listes.

Si un proxy ou un CDN précède Apache, l'adresse vue par `Require ip` est la sienne : configurez d'abord `mod_remoteip`, sinon tous les vrais robots seront refusés.

## X-Robots-Tag avec mod_headers

```apache
<FilesMatch "\.pdf$">
    Header set X-Robots-Tag "noindex"
</FilesMatch>
```

Google documente cet en-tête ; les pages d'OpenAI, d'Anthropic et de Perplexity consultées pour ce guide ne le mentionnent pas. Pour ces robots, robots.txt reste la consigne documentée.

## Ce qui change par rapport à Apache 2.2

| Apache 2.2 | Apache 2.4 |
|---|---|
| `Order Allow,Deny` puis `Allow from all` | `Require all granted` |
| `Order Deny,Allow` puis `Deny from all` | `Require all denied` |
| `Deny from env=refus_ia` | `Require not env refus_ia` dans un `<RequireAll>` |
| `Allow from 192.0.2.0/24` | `Require ip 192.0.2.0/24` |
| `AllowOverride All` par défaut | `AllowOverride None` par défaut |

Les anciennes directives existent encore en 2.4 grâce à `mod_access_compat`, mais la documentation les déclare obsolètes et déconseille de les mélanger avec `Require` : les deux mécanismes se combinent de façon peu intuitive. Si vous reprenez un vieux `.htaccess`, convertissez-le en entier. Autre différence : avant la version 2.4.16, l'expression de `Require expr` devait être écrite sans guillemets.

Apache n'a pas d'équivalent intégré à la limitation de débit par requêtes de nginx : `mod_ratelimit` limite la bande passante, pas le nombre de requêtes.

## Tester

```bash
apachectl configtest
# Robot d'entraînement : 403 ; même robot sur robots.txt : 200
curl -s -o /dev/null -w '%{http_code}\n' -A "compatible; GPTBot/1.4" https://www.example.com/
curl -s -o /dev/null -w '%{http_code}\n' -A "compatible; GPTBot/1.4" https://www.example.com/robots.txt
# Faux robot de recherche depuis votre poste : 403 avec la vérification IP
curl -s -o /dev/null -w '%{http_code}\n' -A "compatible; OAI-SearchBot/1.4" https://www.example.com/
tail -f /var/log/apache2/robots-ia.log
```

Ces tests sont indicatifs : curl reproduit le User-Agent, pas l'adresse du robot. Lors de nos essais, avec l'adresse locale déclarée comme plage d'OpenAI, `OAI-SearchBot` obtenait 200 et `Claude-SearchBot` 403, comme prévu. Le journal d'erreurs indique la cause de chaque refus (`AH01630: client denied by server configuration`).

## Pièges à éviter

- **Le User-Agent seul ne prouve rien.** Le refus par nom n'arrête que les robots honnêtes ; seule la comparaison avec les plages IP écarte les usurpateurs, et seulement pour les éditeurs qui en publient.
- **Un motif trop large.** `bot` refuserait Googlebot et Bingbot.
- **Bloquer les plages d'un éditeur pour refuser l'entraînement.** Anthropic indique que cette méthode n'est pas fiable, car elle empêche aussi la lecture de robots.txt.
- **Des listes périmées.** Les plages évoluent ; un robot de recherche refusé dans le journal signale souvent une liste trop ancienne.

## Revenir en arrière

Dans un `.htaccess`, supprimez ou commentez le bloc ajouté ; l'effet est immédiat. Dans la configuration serveur, retirez le bloc `<Location>` et les lignes `SetEnvIfNoCase`, puis `apachectl configtest` et `apachectl graceful`, et supprimez la tâche cron.

## Sources officielles

- Apache 2.4, mod_authz_core (Require, RequireAll, AuthMerging) : <https://httpd.apache.org/docs/2.4/mod/mod_authz_core.html>
- Apache 2.4, mod_authz_host (Require ip) : <https://httpd.apache.org/docs/2.4/mod/mod_authz_host.html>
- Apache 2.4, mod_setenvif : <https://httpd.apache.org/docs/2.4/mod/mod_setenvif.html>
- Apache 2.4, mod_rewrite : <https://httpd.apache.org/docs/2.4/mod/mod_rewrite.html>
- Apache 2.4, Access Control : <https://httpd.apache.org/docs/2.4/howto/access.html>
- Apache 2.4, Upgrading to 2.4 from 2.2 : <https://httpd.apache.org/docs/2.4/upgrading.html>
- Apache 2.4, mod_log_config (CustomLog env=) : <https://httpd.apache.org/docs/2.4/mod/mod_log_config.html>
- Apache 2.4, mod_headers : <https://httpd.apache.org/docs/2.4/mod/mod_headers.html>
- Apache 2.4, mod_remoteip : <https://httpd.apache.org/docs/2.4/mod/mod_remoteip.html>
- Apache 2.4, mod_ratelimit : <https://httpd.apache.org/docs/2.4/mod/mod_ratelimit.html>
- RFC 9309, Robots Exclusion Protocol : <https://www.rfc-editor.org/rfc/rfc9309>
- OpenAI, Overview of OpenAI Crawlers : <https://developers.openai.com/api/docs/bots>
- Anthropic, Does Anthropic crawl data from the web : <https://support.claude.com/en/articles/8896518>
- Perplexity, Perplexity Crawlers : <https://docs.perplexity.ai/docs/resources/perplexity-crawlers>
