Fail2ban s’installe en premier, et l’on s’arrête généralement là : le paquet est en place, le service tourne, sshd est apparemment protégé. Six mois plus tard, on découvre que la prison lit un fichier qui n’existe pas sur ce système, et que tout le reste — la messagerie, le panneau d’administration, le formulaire de connexion du site — n’a jamais été protégé.
Voyons ce qu’il faut réellement activer sur un VPS ordinaire hébergeant un site, quels nombres y mettre et comment s’assurer qu’une prison fonctionne au lieu de simplement figurer dans la configuration.
Vérifiez d’abord que sshd attrape quelque chose
Une seule commande :
sudo fail2ban-client status sshd
La sortie contient les lignes Currently failed, Total failed et Total banned. Si Total failed vaut zéro sur un serveur exposé depuis au moins un jour, la prison ne fonctionne pas. Comparez avec la réalité :
sudo lastb | wc -l
Des milliers d’échecs dans lastb face à des zéros dans Fail2ban ne signifient qu’une chose : le filtre ne regarde pas au bon endroit.
La cause la plus fréquente est Debian 12. Il n’installe plus rsyslog par défaut, le fichier /var/log/auth.log n’existe tout simplement pas, et la prison sshd livrée est réglée sur ce fichier. Aucun message d’erreur n’apparaît : le service démarre, le statut s’affiche, les compteurs restent à zéro. La solution est de basculer sur le journal systemd :
[sshd]
enabled = true
backend = systemd
L’autre possibilité est de réinstaller rsyslog, si un auth.log textuel vous importe pour d’autres outils. Ubuntu 24.04 se comporte de la même façon.
Où écrire les réglages
On ne touche pas à /etc/fail2ban/jail.conf : il est écrasé lors d’une mise à jour du paquet, et toute modification qui s’y trouve disparaîtra un jour en silence. Vos réglages vont dans /etc/fail2ban/jail.local ; ce fichier est lu en dernier et prend le pas sur le fichier commun.
[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 203.0.113.25
bantime = 1h
findtime = 10m
maxretry = 5
backend = systemd
ignoreip avec votre propre adresse n’est pas un luxe mais une assurance : se bannir soi-même d’une faute de frappe arrive plus vite qu’on ne croit. Sans adresse fixe, gardez une entrée de secours en plus de SSH — la console ou VNC chez l’hébergeur.
La prison qui change la donne : recidive
Une prison ordinaire a la mémoire courte : cinq tentatives en dix minutes, une heure de bannissement, et une heure plus tard tout recommence. Un robot s’en accommode très bien et reviendra demain et après-demain. recidive comble exactement cet écart : elle ne lit pas le journal du système mais celui de Fail2ban — elle bannit donc ceux que Fail2ban a déjà bannis.
[recidive]
enabled = true
bantime = 1w
findtime = 1d
maxretry = 5
Cela se lit ainsi : « banni cinq fois en une journée, parti pour une semaine ». La prison a besoin du fichier /var/log/fail2ban.log ; si vous avez basculé la journalisation de Fail2ban vers syslog, recidive aura elle aussi besoin de backend = systemd.
L’effet pratique de cette seule prison est généralement plus net que le réglage fin de toutes les autres : les habitués disparaissent, et il ne reste dans les journaux qu’un bruit de fond frais.
Quoi d’autre lorsque le serveur héberge un site
Par utilité décroissante :
nginx-http-authouapache-auth— force brute contre l’authentification basique. Nécessaire si une zone d’administration ou un site de préproduction est protégé par un mot de passe du serveur web ;nginx-botsearch— le balayage de chemins connus :/wp-login.php,/phpmyadmin,/.env. Ce n’est pas une intrusion mais une reconnaissance, et c’est précisément elle qui précède tout le reste ;nginx-limit-req— ne fonctionne que silimit_req_zoneest défini dans Nginx même ; sans cela la prison est activée et inutile ;postfix-sasletdovecot— indispensables si vous gérez votre propre messagerie. La recherche de mots de passe de boîtes aux lettres est continue et n’est habituellement surveillée par personne.
[nginx-botsearch]
enabled = true
logpath = /var/log/nginx/access.log
Le formulaire de connexion du site lui-même est une histoire à part. L’application n’a pas de journal propre des échecs, et dans access.log une tentative ratée ressemble à un POST ordinaire avec un code 200 ou 302 — impossible à distinguer d’une réussite par un filtre générique. Deux voies : amener l’application à écrire les échecs dans syslog (la plupart des systèmes de gestion de contenu ont une extension pour cela), ou limiter la fréquence des requêtes vers la page de connexion. La seconde est un limiteur, pas un détecteur, et mieux vaut le savoir d’avance.
Les nombres
bantime = 10m est le réglage par défaut à cause duquel on juge souvent Fail2ban inutile : dix minutes suffisent à un robot pour revenir. Une heure pour le premier bannissement plus recidive pour une semaine fonctionne bien mieux que des bannissements définitifs, qui se transforment avec le temps en une liste de règles interminable.
maxretry = 3 pour SSH est un moyen sûr de se bannir soi-même. Cinq tentatives en dix minutes coupent la force brute tout aussi bien.
Une recherche lente — une tentative toutes les cinq minutes — ne tombera jamais dans la fenêtre findtime. Ce n’est pas une raison pour étirer la fenêtre à une journée : vous obtiendriez des faux positifs contre vos propres collaborateurs. Contre la recherche lente, ce n’est pas un seuil qui agit, mais l’authentification par mot de passe désactivée.
Assurez-vous que le bannissement atteint les paquets
Fail2ban ne fait qu’appeler une commande externe. Si banaction ne correspond pas à ce qui filtre réellement le trafic, le journal se remplira de joyeuses lignes Ban 198.51.100.7 tandis que les paquets continueront d’arriver. Debian 12 utilise nftables par défaut, et avec UFW actif le bon choix est banaction = ufw. Pour vérifier :
sudo nft list ruleset | grep -c f2b
sudo iptables -S | grep f2b
Au moins l’une des deux doit montrer des règles. Quant au filtre lui-même, vous pouvez le tester sans attendre une attaque :
sudo fail2ban-regex systemd-journal /etc/fail2ban/filter.d/sshd.conf
Le bas de la sortie indique combien de lignes ont correspondu. Zéro signifie que le filtre et le journal ne se rencontrent pas, et il est inutile de configurer plus loin.
Ce que Fail2ban ne fait pas
Il ne protège pas de la force brute distribuée : mille adresses avec une tentative chacune n’atteindront aucun seuil, quels que soient les réglages. Il ne corrige pas la cause — une adresse bannie n’améliore pas un mot de passe faible. Et il ignore la réputation : une adresse qui attaquait hier les serveurs d’autrui est propre à ses yeux jusqu’à ce qu’elle s’en prenne au vôtre. D’où la combinaison pratique : des clés au lieu de mots de passe, Fail2ban comme limiteur de bruit et une liste de blocage partagée (CrowdSec) comme savoir tiré de l’expérience des autres.
Un problème distinct est qu’il faut bien regarder tout cela de temps en temps. Personne ne tape fail2ban-client status prison par prison pendant des semaines, et une hausse du nombre de bannissements se remarque quand quelque chose est déjà cassé. Sur les pages de démonstration ci-dessous, les mêmes données tiennent sur une seule page : la liste des prisons, qui est banni à l’instant et d’où viennent les tentatives.