IABIG

Guides par plateforme · Mis à jour le 2026-10-25 · Version Markdown

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.

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.

# .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 :

# .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.

# 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.

#!/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 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

<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

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

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

À lire aussi