This article in French is also available in English here.
Introduction
Dans un précédent article, j’expliquais mes motivations et choix pour protéger Mastodon (et les autres applications du fédiverse) contre les bots IA. Ce nouvel article, à destination des administrateurs, détaille les étapes techniques afin d’arriver au résultat ; il est également disponible en anglais ici.
Pour mémoire, voici les objectifs visés :
- Protéger nos utilisateurs du moissonnage massif et systématique de leur contenu ;
- Protéger nos serveurs des attaques en masse de ces bots IA ;
- Laisser nos sites internet visibles publiquement, car c’est pour moi une des vocations des réseaux sociaux, le choix étant laissé à l’utilisateur de sélectionner la visibilité de ses publications ;
- Ne pas utiliser un service en ligne dédié de type CloudFlare, car une de mes valeurs est de protéger la vie privée de nos utilisateurs, et dépendre d’une solution externe qui a toute visibilité sur le trafic, les identifiants en clair et le contenu des consultations n’est pas acceptable ;
- Aller au-delà du filtrage “standard”, et ainsi adresser la problématique des bots IA quelles que soient leurs adresses IP et qui s’identifient comme des utilisateurs humains (font semblant d’utiliser un navigateur).
Ainsi, j’ai choisi d’installer Anubis, un programme en source ouverte (disponible ici sous licence MIT) que j’auto-héberge afin d’être autonome et de garantir la sécurité et la confidentialité de la navigation.
Les défis posés
Le site présentant Anubis est très bien fait, et détaille comment installer l’application et protéger un site internet standard. Néanmoins, pour Mastodon et plus généralement pour les applications du fédiverse, j’ai fait quelques choix et j’ai dû résoudre quelques problématiques particulières, concernant notamment :
- Une instance Anubis commune protégeant toutes les applications installées sur le même serveur ;
- Configuration en sous-requête d’authentification (subrequest authentication);
- Renvoi d’un code
200et d’une fausse page aux robots bloqués (plutôt qu’un code403) ; - Prise en compte de l’API de streaming et du changement légitime possible des adresses IP ;
- Prise en compte de l’authentification applicative avec OAuth ;
- Prise en compte des médias intégrés (embedded) ;
- Fonctionnement en mode failsafe (si Anubis tombe, le service reste fonctionnel) ;
- Des métriques montrant les taux de blocage des clients.
J’aborderai l’ensemble de ces points, en utilisant un serveur linux Ubuntu 24.04LTS avec Nginx et une installation native (sans Docker). Je vous laisse le soin d’adapter ces instructions à votre propre configuration.
Installation d’Anubis
Vous pouvez vous référer à la documentation du site officiel pour cette installation, sachant que nous utiliserons la configuration subrequest authentication.
Dans ce mode, Nginx reste en frontal internet et va interroger Anubis pour autoriser la requête : ce dernier renverra 200 si le client est autorisé ou a déjà son cookie d’autorisation, 403 s’il est interdit et 401 s’il a besoin d’être vérifié ; dans ce dernier cas, la requête est redirigée (307) sur la page Anubis et doit passer le défi pour récupérer un cookie d’autorisation et enfin atteindre la page visée en cas de succès.
Comme le décrit le site officiel, vous devez modifier la politique Anubis afin que DENY renvoie un code 403 au lieu de 200 par défaut, pour que Nginx l’interprète correctement :
status_codes:
CHALLENGE: 200
DENY: 403
Nous allons toutefois améliorer cette situation, car certains bots IA retentent leur chance sur un code 403.
Configuration d’Anubis
Concernant la configuration d’Anubis, le premier point concerne les variables d’environnement et le second les politiques.
Variables d’environnement
Voici un extrait des variables d’environnement que j’utilise, je décris ci-dessous les points importants pour notre problématique :
BIND=/run/anubis/anubis.sock
BIND_NETWORK=unix
SOCKET_MODE=0660
COOKIE_EXPIRATION_TIME=168h
JWT_RESTRICTION_HEADER="User-Agent"
METRICS_BIND=:8240
METRICS_BIND_NETWORK=tcp
POLICY_FNAME=/usr/local/etc/botPolicies.yaml
REDIRECT_DOMAINS="example.net,*.example.net"
SERVE_ROBOTS_TXT=false
TARGET=" "
Les trois premières lignes concernent le point d’écoute du serveur Anubis. J’ai choisi d’utiliser un socket unix, vous pouvez rester sur un port tcp, auquel cas vous devrez adapter les configurations de Nginx qui suivent. Assurez-vous que l’utilisateur www-data a bien les droits d’accès pour lire sur le socket (appartient au groupe qui exécute Anubis).
L’expiration du cookie est fixé à une semaine. Vous pouvez réduire cette durée, sachant que chaque expiration casse le flux Mastodon sur le navigateur et nécessite que l’utilisateur rafraîchisse sa page. Il faut donc choisir le bon équilibre entre protection et expérience utilisateur.
Pour la même raison, JWT_RESTRICTION_HEADER est lié au User-Agent de l’utilisateur plutôt qu’à son adresse IP (défaut). Le problème de l’adresse IP est que celle-ci peut changer dynamiquement en navigation mobile ou bien avec certains VPN, et dans ce cas le flux Mastodon est cassé à chaque fois, parfois après quelques minutes, ce qui rend le service quasiment inutilisable. Nous sommes donc obligé d’adapter le niveau de protection en ne tenant pas compte de l’adresse IP.
Les quatre valeurs qui suivent sont classiques et permettent l’observabilité à travers Prometheus (nous en reparlerons plus loin), le fichier des politiques et les domaines de redirection autorisés qu’il est conseillé de configurer (ceux de vos applications à protéger, donc).
Le paramètre SERVE_ROBOTS_TXT ne fait pas sens dans le mode Anubis utilisé, néanmoins nous servirons notre propre fichier robots.txt directement avec Nginx.
Enfin, la valeur de TARGET=" " est essentielle pour que le mode subrequest authentication fonctionne.
Politiques
J’utilise une seule instance Anubis pour protéger toutes mes applications, ainsi les politiques utilisées doivent être adaptées à toutes, ce qui en pratique ne pose aucun problème.
Le point essentiel est celui cité plus haut concernant status_codes. Sinon, les politiques par défaut, éventuellement adaptées à votre sauce, peuvent parfaitement convenir. Notez bien que si aucune politique ne s’applique à la requête, celle-ci sera acceptée par défaut : il n’y a donc aucun problème posé pour par exemple la fédération entre serveurs.
Néanmoins, vous pouvez souhaiter accepter explicitement certains flux comme par exemple la fédération ou les flux RSS :
- name: federation
action: ALLOW
user_agent_regex: >-
^(Mastodon|Pleroma|Akkoma|Misskey|Calckey|Firefish|gotosocial|Friendica|Hubzilla|Lemmy|Kbin|PeerTube|Pixelfed|BookWyrm|WriteFreely|Mobilizon|Funkwhale|Sharkey|Loops|AodeRelay)
expression:
all:
- '"Accept" in headers'
- 'headers["Accept"].matches("^application/(activity\\+json|jrd\\+json|ld\\+json)(\\s*;.*)?$")'
- name: rss-feeds
action: ALLOW
expression:
all:
- '"Accept" in headers'
- 'headers["Accept"].matches("^application/(rss|atom|rdf)\\+xml(\\s*;.*)?$")'
Rappelons enfin que l’objectif d’Anubis n’est pas de bloquer tous les bots mais bien ceux qui se présentent pour collecter en masse vos pages internet. Pour les bots malveillants, je complète avec des outils tels que iptables et ipset pour bloquer les IP toxiques et fail2ban pour les attaques par force brute (mais c’est une autre histoire).
Configuration de Nginx
Maintenant que votre service Anubis est prêt, passons à Nginx qui reste en frontal de l’internet public. Dans le fichier concernant Mastodon (ou toute autre application à protéger), par exemple /etc/nginx/sites-available/mastodon, nous allons rajouter les directives suivantes.
Configuration générale
Adaptant légèrement la documentation officielle, voici les lignes à rajouter :
location ^~ /.within.website/ {
proxy_pass http://unix:/run/anubis/anubis.sock:;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Original-URI $request_uri;
proxy_set_header Accept $http_accept;
proxy_set_header User-Agent $http_user_agent;
add_header Cache-Control "no-store";
proxy_pass_request_body off;
proxy_set_header Content-Length "";
auth_request off;
proxy_cache off;
proxy_connect_timeout 1s;
proxy_read_timeout 1s;
proxy_send_timeout 1s;
}
location @redirectToAnubis {
return 307 /.within.website/?redir=$scheme://$host$request_uri;
auth_request off;
proxy_cache off;
}
Notons en particulier que nous nous assurons de ne pas utiliser le cache en passant la requête à Anubis (ce qui empêcherait le bon fonctionnement de la vérification) et que nous réduisons la durée d’attente (timeout) afin que la configuration failsafe puisse être acceptable du point de vue de l’utilisateur.
Optionnel : servir de fausses pages aux bots IA
Afin de retrouver le même fonctionnement d’Anubis qu’en mode proxy, et donc d’éviter de renvoyer un code 403 aux bots interdits (ceux-ci pouvant alors réitérer sans cesse leurs requêtes), nous avons trois options possibles.
Option basique : page statique
Vous pouvez servir un texte statique tout en renvoyant un code 200 ainsi, en rajoutant les lignes suivantes au même fichier :
location @fake200 {
default_type text/html;
return 200 "<h2>Service not available</h2>\n";
auth_request off;
}
Option élaborée : page dynamique
Il est également possible de servir des pages dynamiquement générées à la volée avec un script lua. Pourquoi faire ? Car cela permet un contenu variable que l’on peut faire passer pour de véritables pages html (contenus multiples mais stables par bot, délai variable par requête, contenu réaliste). L’objectif étant que le bot IA trouve un contenu et en conclut : “rien d’intéressant ici”.
Pour ce faire, nous allons plutôt rajouter les lignes suivantes au même fichier (à la place de l’option basique précédente) :
location @fake200 {
access_by_lua_file /var/www/html/fake_200.lua;
auth_request off;
}
Pour que ceci fonctionne, il faut deux conditions : que le module lua soit installé avec Nginx (ce n’est pas le cas par défaut sur Ubuntu 24.04LTS), et qu’un fichier fake_200.lua soit présent sous /var/www/html/ (ou tout autre répertoire de votre choix). Pour installer le module sous Ubuntu :
$ sudo apt install libnginx-mod-http-lua
Si vous êtes intéressé par le fichier fake_200.lua complet que j’utilise, contactez-moi.
local ngx = ngx
--
-- Logic : cache, fingerprinting, generate random content, noise, padding, jitter
--
ngx.say(body)
return ngx.exit(ngx.HTTP_OK)
Option nucléaire : bombe zip
Il est possible d’aller encore plus loin, et au lieu de servir au bot un contenu trompeur, lui servir un contenu carrément nocif. Pour cela, il existe des techniques simples comme les “bombes zip” qui vont coûter très cher en ressources au robot, voire le faire planter.
Vous pourrez facilement trouver sur internet des exemples et adapter les configurations précédentes en ce sens. Pour ma part, je reste réticent à utiliser cette technique, mais à vous de voir…
Voici toutefois un exemple de mise en œuvre (inspiré par Ibrahim Diallo sur son blog), qui va servir un fichier de 10 Mo qui se décompressera en 10 Go, assez pour faire planter les bots qui n’y prennent garde. Génération du fichier :
$ dd if=/dev/zero bs=1G count=10 | gzip -c > /var/www/html/10GB.gz
Et ensuite, rajouter les lignes suivantes au même fichier de configuration Nginx (à la place des options précédentes) :
location @fake200 {
add_header Content-Encoding gzip;
return 200 /10GB.gz
auth_request off;
}
location = /10GB.gz {
root /var/www/html;
auth_request off;
}
Optionnel : mode failsafe
Avec Anubis devant l’ensemble de mes applications, un dysfonctionnement les rendrait toutes indisponibles à la fois. Même si cela ne s’est jamais produit, je préfère qu’en cas de souci, l’utilisateur puisse continuer à accéder aux applications, le temps de résoudre la panne d’Anubis. Il suffit de rajouter les lignes suivantes au même fichier :
location @allowOnFailure {
try_files $uri @mastodon;
auth_request off;
}
Les lignes hors auth_request off; étant à adapter à ce qui est servi par défaut aux répertoires protégés (la racine / pour Mastodon).
Notez que j’omets add_header Strict-Transport-Security "max-age=63072000; includeSubDomains"; dans chaque directive location contrairement à ce qui est indiqué dans la documentation officielle Mastodon, car je mets cet en-tête au niveau du serveur avec always :
server {
...
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
...
}
Flux OAuth
Le flux d’autorisation OAuth est cassé pour les applications qui n’utilisent pas un navigateur et ne suivent pas une redirection 307 (cas de Tusky par exemple). Pour permettre ce type de flux, il est nécessaire de contourner explicitement Anubis, ainsi il faut rajouter dans le fichier de configuration Nginx pour Mastodon (à adapter pour les autres applications du fédiverse) :
location ^~ /oauth/ {
try_files $uri @mastodon;
auth_request off;
}
location ^~ /api/v1/apps {
try_files $uri @mastodon;
auth_request off;
}
location ^~ /auth/sign_in {
try_files $uri @mastodon;
auth_request off;
}
Il peut semble contre-intuitif de contourner Anubis pour le chemin /auth/sign_in mais encore une fois, Anubis n’est pas une protection contre les attaques par force brute, utilisez fail2ban ou un équivalent pour cela.
Médias intégrés
Les médias intégrés (embedded) posent également souci car les navigateurs récents ne permettent pas aux pages intégrées de type iframe de stocker leurs cookies. Ainsi, si vous souhaitez pouvoir intégrer des publications (par exemple, Mastodon) ou des médias (par exemple, PeerTube), il est nécessaire là aussi de contourner Anubis. Voici les lignes à rajouter dans Nginx pour Mastodon :
location ~ ^/@[^/]+/\d+/embed$ {
try_files $uri @mastodon;
auth_request off;
}
location ~ ^/api/v1/statuses/\d+$ {
try_files $uri @mastodon;
auth_request off;
}
location = /embed.js {
try_files $uri @mastodon;
auth_request off;
}
Cette fonction étant moins utilisée sur Mastodon, vous pouvez choisir de faire sans, mais elle reste indispensable pour PeerTube. Sans cela, l’intégration affichera la fenêtre “non autorisé” d’Anubis.
Partie principale
Sur chaque chemin à protéger, on peut maintenant rajouter les lignes suivantes dans Nginx. Pour Mastodon, cela se limite à la racine / :
location / {
auth_request /.within.website/x/cmd/anubis/api/check;
auth_request_set $anubis_status $upstream_status;
error_page 401 = @redirectToAnubis;
error_page 403 = @fake200;
error_page 500 502 503 504 = @allowOnFailure;
try_files $uri @mastodon;
}
Notez la ligne auth_request_set qui nous sert pour l’observabilité et pour associer dans les logs Nginx le statut renvoyé par Anubis, on y reviendra plus loin. Si cela ne vous intéresse pas, vous pouvez omettre cette ligne.
Dans toutes les autres directives location, on rajoute auth_request off; pour contourner la vérification. Cela concernera en général les fichiers statiques et les autres pages qui ne nécessitent pas ou qui ne devraient pas être protégées (proxy interne, streaming…).
Le fichier robots.txt
Enfin, pour rester cohérent et même si beaucoup de bots IA l’ignorent, on peut choisir de servir son propre fichier robots.txt en lieu et place de celui servi par Mastodon (ou une autre application du fédiverse) qui est minimaliste. Voici un exemple de lignes à rajouter dans Nginx :
location = /robots.txt {
auth_request off;
root /var/www/html;
default_type text/plain;
access_log off;
log_not_found off;
}
Mon fichier robots.txt a été mis en cohérence avec les politiques Anubis. Je peux vous le fournir sur demande.
Et en avant !
Tout est maintenant prêt. Bien entendu, si vous utilisez un stockage objet S3 avec un proxy inversé Nginx, vous ne toucherez pas à cette dernière configuration, il n’est pas souhaitable d’y utiliser Anubis.
Si vous ne l’avez déjà fait, après avoir modifié les configurations :
$ sudo systemctl restart anubis
$ sudo systemctl reload nginx
Désormais, vous aurez la fenêtre de vérification Anubis la première fois que vous visiterez votre site, et ensuite vous serez tranquille pour la durée que vous avez configurée (une semaine si vous avez suivi ce guide à la lettre).
Après expiration du cookie, le flux Mastodon sur un navigateur sera rompu : si vous l’aviez laissé ouvert, vous aurez alors un message d’erreur de Mastodon, vous invitant à tenter de rafraîchir la page, ce qui résout la situation. C’est une gêne mineure que je n’ai pas réussi à éliminer, mais elle me semble acceptable. Bien entendu, elle ne se produit pas sur les applications clientes.
Cette configuration fonctionne parfaitement chez moi après plusieurs mois, sans impact visible sur les performances, Anubis protégeant cinq applications du fédiverse sur chacun de mes deux serveurs principaux. La charge poussée par les bots IA a nettement diminué, et les défis non résolus varient entre 70% et 95% selon les périodes, donnant une idée du taux important de bots IA qui tentent de se faire passer pour des navigateurs légitimes !
Bonus : observabilité
Si vous souhaitez rajouter quelques métriques pour mesurer l’efficacité, vous pouvez utiliser deux sources complémentaires.
Prometheus
Si vous avez configuré Anubis comme indiqué, vous retrouverez sur le port 8240 des métriques Prometheus que vous pourrez utiliser :
curl http://127.0.0.1:8240/metrics
Pour ma part je les exporte avec Alloy vers un serveur Prometheus / Grafana. Contactez-moi si vous voulez en savoir plus.
Nginx
En utilisant la variable $anubis_status configurée ci-dessus, vous pouvez associer le “vrai'“ statut renvoyé par Anubis à chaque requête Nginx dans les journaux (200, 401, 403…) et enrichir ainsi les statistiques (par exemple, par pays).
Pour ma part je remonte les logs filtrés avec Alloy vers le même serveur avec Loki / Grafana. Contactez-moi également pour plus de détails.
Résultat
Pour un exemple de résultat de ce que cela peut donner, vous pouvez alors voir la page de statut de notre serveur Mastodon ici. Les statistiques correspondantes se trouvent sur la dernière section.
Pour les autres applications du fédiverse
La même logique s’applique aux autres applications, mais les configurations et chemins dans Nginx diffèrent et nécessitent de légères adaptations. N’hésitez pas à me contacter si vous souhaitez tous les détails.
Avec Anubis, je protège ainsi avec succès Mastodon, Pixelfed, PeerTube, Lemmy, Friendica, WriteFreely, Loops, Mobilizon, BookWyrm, Funkwhale, ainsi que FreshRSS et les blogs Movim.
J’accueille volontiers vos retours et suggestions. Et sus aux bots IA !
Techno-Fil et faits divers

Le blog d’un informaticien, animateur de multiples réseaux sociaux du fédiverse, administrateur système versé dans la sécurité informatique et la défense de la vie privée.
Je publierai des articles relatifs à l’informatique, la sécurité, la protection des données personnelles, avec le souci de vulgariser au maximum, plutôt en français mais pas exclusivement.
#infosec #security #privacy #dataprivacy #opensource #sysadmin #linux #fediverse #hardware #watercooling