Fail2ban surveille les journaux d’un serveur Linux et bannit automatiquement, via le pare-feu, les adresses IP qui multiplient les échecs de connexion. Sur Debian et Ubuntu récents, le paquet configure déjà la protection SSH — mais rien ne vous dit dans quel état est votre machine. Ce guide commence donc par la vérifier, montre comment personnaliser sans casser ces réglages, et corrige un piège que même la documentation officielle laisse de côté : la protection d’un service qui tourne dans un conteneur Docker.
L'essentiel
Vérifier d'abord : sudo fail2ban-client -d | grep "'sshd'"
Ne jamais faire : sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
À faire : un jail.local minimal, limité aux options que vous changez
Prérequis : accès root ou sudo, un service exposé (SSH au minimum)
Vérifié le : 8 septembre 2026 · commandes et sorties capturées sur
fail2ban 1.0.2-3ubuntu0.1 (Ubuntu 24.04), pare-feu iptables et nftables
Commencez par vérifier ce que votre système fait déjà
Ne partez jamais du principe que fail2ban est inactif, ni qu’il est correctement réglé. Une seule commande donne l’état réel, sans rien modifier :
sudo fail2ban-client -d | grep "'sshd'"
Sortie capturée le 8 septembre 2026 sur une Ubuntu 24.04 avec le paquet d’origine :
['set', 'sshd', 'addjournalmatch', '_SYSTEMD_UNIT=sshd.service', '+', '_COMM=sshd']
['set', 'sshd', 'addaction', 'nftables']
Deux informations décisives. La jail SSH lit le journal systemd, et elle bannit via nftables. Si votre machine renvoie autre chose — une ligne addlogpath vers /var/log/auth.log, ou addaction avec iptables-multiport — un fichier de configuration local a écrasé les réglages du paquet, et c’est la première piste à suivre.
Ces réglages viennent d’un fichier déposé par le paquet, que vous pouvez lire directement :
cat /etc/fail2ban/jail.d/defaults-debian.conf
[DEFAULT]
banaction = nftables
banaction_allports = nftables[type=allports]
backend = systemd
[sshd]
enabled = true
Sur la génération suivante du paquet — la 1.1.0-9 d’Ubuntu 26.04, même série que celle de Debian 13 — le contenu diffère légèrement, avec un réglage supplémentaire qui a son importance :
[DEFAULT]
banaction = nftables
banaction_allports = nftables[type=allports]
[sshd]
backend = systemd
journalmatch = _SYSTEMD_UNIT=ssh.service + _COMM=sshd
enabled = true
Trois conséquences. La jail SSH est déjà activée : inutile d’écrire enabled = true quelque part. Le backend est systemd, ce qui est nécessaire puisque « rsyslog is no longer installed by default » depuis Debian 12 (Debian, notes de version Bookworm, §5.1.7) et que /var/log/auth.log n’existe donc plus. Et l’action de bannissement est nftables en natif : les tutoriels qui recommandent de forcer iptables-multiport font régresser cette configuration.
| Distribution | Version en dépôt | Backend SSH | Action de bannissement |
|---|---|---|---|
| Debian 13 | 1.1.0-8 | systemd |
nftables |
| Ubuntu 26.04 LTS | 1.1.0-9 | systemd |
nftables |
| Ubuntu 24.04 LTS | 1.0.2-3ubuntu0.1 | systemd |
nftables |
| Ubuntu 22.04 LTS | 0.11.2-6 | auto |
iptables-multiport |
| Arch Linux | 1.1.1-1 | systemd (via paths-arch.conf) |
à définir vous-même, voir ci-dessous |
| Fedora 44 | 1.1.0-16.fc44 | systemd (via paths-fedora.conf) |
firewallcmd-ipset |
Ubuntu 22.04 est la seule cible de ce guide privée de ces réglages : son paquet 0.11.2-6 ne contient que [sshd] enabled = true. La section sur les jails silencieuses explique quoi faire.
Le cas d’Arch Linux mérite une vigilance particulière. À partir de fail2ban 1.1.1 — la version en dépôt Arch — la ligne banaction n’est plus active dans jail.conf amont, où elle figure en commentaire, et paths-arch.conf ne la définit pas non plus. Or action_ y fait référence sous la forme %(banaction)s. Contrôlez donc ce que votre installation applique réellement avant d’aller plus loin :
sudo fail2ban-client -d | grep addaction
Si la commande ne renvoie rien, définissez explicitement l’action dans votre jail.local, par exemple banaction = nftables.
Comprendre le principe : jails, filtres et actions

Fail2ban repose sur trois briques. Une jail associe un service à surveiller à un filtre et à une action, avec ses propres seuils. Un filtre est une expression régulière qui repère, dans un journal, une ligne signalant un échec de connexion. Une action pose la règle de pare-feu qui rejette le trafic de l’adresse fautive.
Le projet le résume dans son dépôt officiel : fail2ban lit les journaux et bannit les adresses qui accumulent trop d’échecs d’authentification, en mettant à jour les règles du pare-feu (GitHub, fail2ban/fail2ban). Il y ajoute une limite explicite : l’outil réduit le rythme des tentatives, il n’élimine pas le risque d’une authentification faible. Un mot de passe SSH faible reste un mot de passe faible — fail2ban ralentit l’attaquant, il ne remplace pas une authentification par clé SSH.
Installer fail2ban
# Debian / Ubuntu
sudo apt update && sudo apt install fail2ban
# Fedora (paquet méta, il installe aussi l'intégration firewalld)
sudo dnf install fail2ban
# Arch Linux
sudo pacman -S fail2ban
# openSUSE
sudo zypper install fail2ban
Sur Debian et Ubuntu, python3-systemd est une dépendance obligatoire, installée automatiquement : c’est elle qui permet la lecture du journal systemd. Le pare-feu, lui, n’est qu’une recommandation (nftables | iptables) — une installation faite avec --no-install-recommends peut se retrouver sans pare-feu, et fail2ban n’aura alors aucune règle à poser.
Personnaliser sans casser la configuration existante

Fail2ban lit ses fichiers dans un ordre précis, et le dernier lu écrase les précédents : jail.conf, puis jail.d/*.conf, puis jail.local, puis jail.d/*.local. Le fichier jail.d/defaults-debian.conf, qui porte les réglages du paquet, est donc lu avant jail.local.
Avertissement — la commande sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local, recommandée par la plupart des tutoriels francophones, produit un jail.local de près de mille lignes qui réinstalle les valeurs génériques et annule les réglages du paquet. Testé le 8 septembre 2026 sur Ubuntu 24.04 : après cette seule commande, fail2ban-client -t répond ERROR Failed during configuration: Have not found any log file for sshd jail puis ERROR: test configuration failed, l’action repasse de nftables à iptables-multiport, et le service refuse de démarrer.
La bonne méthode consiste à n’écrire que ce que vous changez, comme le dit l’en-tête de jail.conf lui-même : « Provide customizations in a jail.local file or a jail.d/customisation.local ».
sudo nano /etc/fail2ban/jail.local
[DEFAULT]
# Durée du bannissement
bantime = 1h
# Fenêtre pendant laquelle les échecs sont comptés
findtime = 10m
# Nombre d'échecs tolérés dans cette fenêtre
maxretry = 5
# Vos propres adresses, jamais bannies
ignoreip = 127.0.0.1/8 ::1 203.0.113.42
Quatre lignes suffisent : jail SSH activée, backend systemd et action nftables continuent de venir du paquet.
Avertissement — sans adresse dans ignoreip, quelques erreurs de mot de passe depuis votre poste suffisent à vous bannir et à vous couper l’accès SSH. Renseignez-y votre adresse IP publique fixe si vous en avez une. En cas de bannissement accidentel, la commande de secours est sudo fail2ban-client unban VOTRE_IP, à lancer depuis la console de votre hébergeur.
Validez avant d’appliquer :
sudo fail2ban-client -t
OK: configuration test is successful
sudo systemctl reload fail2ban
Lire l’état d’une jail
sudo fail2ban-client status sshd
Sortie capturée le 8 septembre 2026 sur une jail en backend systemd, la configuration par défaut de Debian et d’Ubuntu :
Status for the jail: sshd
|- Filter
| |- Currently failed: 0
| |- Total failed: 0
| `- Journal matches: _SYSTEMD_UNIT=sshd.service + _COMM=sshd
`- Actions
|- Currently banned: 0
|- Total banned: 0
`- Banned IP list:
La ligne Journal matches indique le filtre journalctl appliqué. Sur une jail configurée pour lire un fichier, elle est remplacée par File list suivie du chemin surveillé :
| `- File list: /var/log/auth.log
C’est la ligne à lire en priorité : si elle affiche un chemin de fichier sur une Debian 12 ou une Ubuntu 24.04 récente, la jail surveille un fichier qui n’existe plus, et ne bannira jamais rien.
Pourquoi une jail active ne bannit parfois rien
C’est le symptôme le plus signalé sur les forums francophones : la jail répond, mais aucune adresse n’est bannie (forum Ubuntu-fr, fail2ban ne bannit pas les IP ; forum Ubuntu-fr, fail2ban ne bannit pas). Sur une distribution récente, la cause est presque toujours une configuration ajoutée par l’utilisateur. Trois cas couvrent l’essentiel.
Un jail.local copié depuis jail.conf, ou toute configuration qui redéfinit backend ou logpath pour la jail SSH. Le backend repasse à auto, qui n’essaie que pyinotify puis polling — jamais systemd, comme l’indique le commentaire de jail.conf — et fail2ban cherche un /var/log/auth.log inexistant. Le correctif : repartir du jail.local minimal ci-dessus.
Une distribution sans les réglages du paquet, typiquement Ubuntu 22.04. Déclarez le backend explicitement :
[sshd]
backend = systemd
Un journalmatch inadapté. L’unité systemd de SSH ne porte pas le même nom partout : ssh.service sur Debian et Ubuntu, sshd.service sur Arch et Fedora. Une configuration recopiée d’une distribution à l’autre ne détecte plus rien — c’est précisément pour cela que le paquet 1.1.0-9 impose journalmatch = _SYSTEMD_UNIT=ssh.service + _COMM=sshd.
Confirmer le diagnostic avec fail2ban-regex. Cet outil confronte un filtre à une source de journaux sans rien bannir :
# Système lisant le journal systemd
sudo fail2ban-regex systemd-journal sshd
# Système lisant un fichier
sudo fail2ban-regex /var/log/auth.log sshd
La dernière ligne donne le verdict. Testé le 8 septembre 2026 sur un journal contenant trois échecs :
Lines: 3 lines, 0 ignored, 3 matched, 0 missed
Un piège de lecture, testé le même jour : si le fichier indiqué n’existe pas, fail2ban-regex ne renvoie pas d’erreur explicite. Il traite le chemin lui-même comme une unique ligne non reconnue.
Lines: 1 lines, 0 ignored, 0 matched, 1 missed
|- Missed line(s):
| /var/log/auth.log
Une seule ligne traitée signale donc un fichier absent. Si matched reste à 0 alors que le fichier existe et contient des échecs récents, c’est le filtre qui ne reconnaît pas le format.
Reste une cause matérielle : sur certains noyaux ARM personnalisés, Raspberry Pi notamment, le module ip_tables manque et aucune règle ne peut s’appliquer alors que la détection fonctionne (forum Ubuntu-fr, cas résolu sur Raspberry Pi).
Protéger un service Docker : le piège de la chaîne DOCKER-USER

Si vous hébergez Nginx Proxy Manager, Vaultwarden ou tout autre service exposé par Docker, une jail laissée en configuration par défaut ne le protège pas. Docker insère ses propres règles, et le trafic à destination d’un conteneur ne traverse pas la chaîne INPUT où fail2ban place ses bannissements.
Le wiki officiel écarte deux réflexes répandus — multiplier les instances de fail2ban, inutile, et basculer globalement toutes les jails vers DOCKER-USER, ce qui laisserait SSH sans protection — et retient de définir la chaîne jail par jail, avec l’option chain (wiki officiel fail2ban, Fail2Ban and Docker).
Sur Debian et Ubuntu, cette recette demande une adaptation que le wiki ne mentionne pas, parce qu’il raisonne sur une configuration iptables. DOCKER-USER est une chaîne iptables, créée par Docker, alors que l’action par défaut de ces distributions est nftables. Les deux ne se rencontrent jamais.
Voici ce que produit la configuration qui semble logique, avec l’action par défaut. Test réalisé le 8 septembre 2026 sur Ubuntu 24.04, avec une chaîne DOCKER-USER en place comme sur un hôte Docker, puis un bannissement déclenché pour de bon. Fail2ban annonce l’adresse bannie :
|- Total banned: 1
`- Banned IP list: 198.51.100.42
Mais la chaîne de Docker, elle, est restée vide :
# sudo iptables -S DOCKER-USER
-N DOCKER-USER
Le bannissement est en réalité parti ailleurs — dans une chaîne homonyme créée par fail2ban dans sa propre table nftables, accrochée au hook input :
# sudo nft list table inet f2b-table
table inet f2b-table {
set addr-set-npm-docker {
type ipv4_addr
elements = { 198.51.100.42 }
}
chain DOCKER-USER {
type filter hook input priority filter - 1; policy accept;
tcp dport { 80, 443 } ip saddr @addr-set-npm-docker reject with icmp port-unreachable
}
}
Le trafic vers un conteneur passant par le chemin forward et non input, cette chaîne ne voit jamais les paquets visés. Le service démarre, le statut affiche une adresse bannie, et le conteneur reste exposé — sans le moindre message d’erreur.
La jail conteneurisée doit donc forcer l’action iptables en plus de la chaîne :
[nginx-proxy-manager]
enabled = true
port = http,https
logpath = /chemin/vers/npm/data/logs/*.log
banaction = iptables-multiport
chain = DOCKER-USER
Avec ce réglage, le même test donne un résultat radicalement différent. Le saut est bien inséré dans la chaîne de Docker :
# sudo iptables -S DOCKER-USER
-N DOCKER-USER
-A DOCKER-USER -p tcp -m multiport --dports 80,443 -j f2b-nginx-proxy-manager
Et la chaîne dédiée porte la règle de rejet :
# sudo iptables -S f2b-nginx-proxy-manager
-N f2b-nginx-proxy-manager
-A f2b-nginx-proxy-manager -s 198.51.100.42/32 -j REJECT --reject-with icmp-port-unreachable
-A f2b-nginx-proxy-manager -j RETURN
La chaîne INPUT, elle, n’a pas été modifiée : vos jails natives et vos jails conteneurisées restent indépendantes. Lors de ces essais, la chaîne f2b-* n’est apparue qu’après le premier bannissement — ne concluez pas à un échec si elle est absente juste après un rechargement.
Adaptez logpath à l’emplacement réel des journaux montés hors du conteneur, comme décrit dans le guide Nginx Proxy Manager.
Dernier piège, sur les hôtes encore en iptables-legacy — certains NAS et UNRAID : si l’hôte et le conteneur n’utilisent pas la même variante d’iptables, l’action échoue avec iptables: No chain/target/match by that name. Comparez les deux avec iptables --version, puis forcez la variante :
[DEFAULT]
banaction = iptables-multiport[iptables=iptables-legacy]
Le wiki place ce réglage dans fail2ban.local ; c’est une erreur de sa part. Ce fichier ne gère que le démon — niveau de journalisation, socket, base de données — et un banaction qui s’y trouve est ignoré. Il doit figurer dans jail.local.
Vérifier que le bannissement fonctionne
Depuis une autre machine que le serveur — jamais depuis celui-ci — tentez plus de connexions SSH ratées que la valeur de maxretry, puis relevez l’état :
sudo fail2ban-client status sshd
Sortie capturée après quatre échecs avec maxretry = 3 :
|- Filter
| |- Currently failed: 1
| |- Total failed: 4
`- Actions
|- Currently banned: 1
|- Total banned: 1
`- Banned IP list: 198.51.100.42
Contrôlez ensuite la règle côté pare-feu, avec la commande qui correspond à votre action — c’est là qu’une erreur de diagnostic est fréquente, puisque iptables -S ne montre jamais rien quand l’action est nftables :
# Action nftables (défaut Debian / Ubuntu)
sudo nft list table inet f2b-table
# Action iptables (jails Docker, Ubuntu 22.04)
sudo iptables -S | grep f2b
Pour lever le bannissement de test, la première commande ne concerne qu’une jail, la seconde parcourt toutes les jails :
sudo fail2ban-client set sshd unbanip 198.51.100.42
sudo fail2ban-client unban 198.51.100.42
Les deux renvoient le nombre d’adresses débannies. Un 1 signifie que l’opération a réussi, pas qu’une erreur s’est produite.
Punir les récidivistes
Une adresse bannie une heure revient souvent dès la fin du bannissement. L’option bantime.increment allonge la durée à chaque récidive :
[DEFAULT]
bantime = 1h
bantime.increment = true
bantime.maxtime = 1w
Avec le facteur par défaut, la durée double à chaque nouveau bannissement de la même adresse — une heure, deux, quatre, huit — sans dépasser le plafond de bantime.maxtime. Le commentaire de jail.conf détaille la formule et l’option bantime.factor.
Désinstaller fail2ban
# Debian / Ubuntu
sudo systemctl stop fail2ban
sudo apt purge fail2ban
# Fedora
sudo systemctl stop fail2ban
sudo dnf remove fail2ban
# Arch Linux
sudo systemctl stop fail2ban
sudo pacman -Rns fail2ban
L’arrêt du service supprime les chaînes créées. Vérifiez qu’il n’en reste aucune, en interrogeant le pare-feu correspondant à votre action :
sudo nft list table inet f2b-table
sudo iptables -S | grep f2b
La réponse No such file or directory sur la première, et une sortie vide sur la seconde, confirment le retour à l’état initial.
Erreurs courantes
Failed to start fail2ban.service — presque toujours une erreur de syntaxe ou une option en double dans jail.local. sudo fail2ban-client -t indique le fichier et la ligne fautive.
section 'sshd' already exists ou option 'backend' in section 'sshd' already exists — vous avez copié jail.conf dans jail.local puis ajouté une section déjà présente. Repartez d’un jail.local minimal.
Have not found any log file for sshd jail — le backend cherche un fichier absent. Sur Debian et Ubuntu récents, une configuration locale a écrasé le backend = systemd du paquet.
iptables: No chain/target/match by that name — l’action utilise une variante d’iptables différente de celle de l’hôte. Voir le réglage iptables=iptables-legacy de la section Docker.
Error: systemd library not found — le module Python systemd est absent ou compilé pour une autre version de Python que celle qui exécute fail2ban. Sur Debian et Ubuntu, python3-systemd est installé en dépendance du paquet.
Fail2ban ou CrowdSec
Fail2ban fonctionne en autarcie : chaque serveur n’apprend que de ses propres journaux. CrowdSec mutualise les signalements entre serveurs participants, ce qui permet de bloquer une adresse déjà repérée ailleurs avant qu’elle n’atteigne votre machine.
Fail2ban reste plus simple à auditer — tout se lit dans des fichiers locaux, et son comportement se vérifie avec fail2ban-regex et fail2ban-client -d. CrowdSec ajoute une couche d’intelligence collective, au prix d’une dépendance à un service tiers. Pour un serveur personnel ou un homelab, fail2ban suffit et se dépanne de bout en bout ; CrowdSec devient intéressant dès que vous administrez plusieurs machines. Dans les deux cas, une authentification SSH par clé apporte davantage que l’un ou l’autre outil.
FAQ
Qu’est-ce que Fail2ban et à quoi sert-il ? Fail2ban est un logiciel de sécurité open source qui surveille les journaux d’un serveur Linux et bannit automatiquement, via le pare-feu, les adresses IP accumulant des échecs de connexion répétés sur un service comme SSH, un serveur web ou un serveur mail.
Faut-il copier jail.conf vers jail.local ?
Non. Cette manipulation, très répandue dans les tutoriels, écrase les réglages livrés par le paquet Debian ou Ubuntu — notamment backend = systemd et banaction = nftables — et empêche le service de démarrer. Créez un jail.local contenant uniquement les options que vous modifiez.
Comment fonctionne Fail2ban ?
Une jail associe un service à un filtre, qui repère les échecs dans les journaux au moyen d’une expression régulière, et à une action, qui pose une règle de pare-feu. Quand le nombre d’échecs dépasse maxretry dans la fenêtre findtime, l’adresse est bannie pour la durée bantime.
Fail2ban existe-t-il sur Windows ? Non. Fail2ban cible les systèmes POSIX, Linux et BSD, et s’appuie sur leurs mécanismes de pare-feu. Aucune version officielle n’existe pour Windows.
Fail2ban fonctionne-t-il avec nftables ?
Oui, et c’est l’action par défaut sur Debian 13, Ubuntu 24.04 et Ubuntu 26.04, via le fichier jail.d/defaults-debian.conf du paquet. Les règles se consultent alors avec nft list table inet f2b-table, et non avec iptables -S.
Fail2ban peut-il s’intégrer à Home Assistant ?
Oui, avec une restriction importante : l’intégration officielle n’est disponible que sur Home Assistant Container et ne fonctionne pas sur Home Assistant Operating System. Elle lit le fichier /var/log/fail2ban.log, qui doit être monté dans le conteneur, et demande la liste des jails à suivre dans sa configuration (documentation officielle Home Assistant).
Combien de temps une adresse reste-t-elle bannie ?
La durée est fixée par bantime. Avec bantime.increment = true, elle double à chaque récidive de la même adresse, jusqu’au plafond défini par bantime.maxtime.
Ce qu’il faut retenir
Commencez toujours par fail2ban-client -d | grep "'sshd'" : cette commande dit en deux lignes ce que votre machine fait réellement, et évite de corriger un problème qui n’existe pas. Sur Debian 13, Ubuntu 24.04 et 26.04, la réponse attendue est le journal systemd et l’action nftables — le paquet a déjà fait le travail.
La façon la plus courante de casser cette protection est de suivre le conseil le plus répandu, cp jail.conf jail.local, après quoi le service refuse de démarrer. Un jail.local de quatre lignes suffit à personnaliser sans rien détruire.
Le seul cas qui demande vraiment une intervention est le service conteneurisé : il faut y forcer banaction = iptables-multiport en plus de chain = DOCKER-USER, faute de quoi fail2ban crée une chaîne nftables décorative qui ne voit jamais le trafic Docker, tout en affichant des adresses bannies.
Pour compléter cette protection, configurez un pare-feu UFW qui limite les ports exposés, et remplacez l’authentification par mot de passe par des clés SSH : fail2ban ralentit les attaques par force brute, la clé les rend inopérantes.
Sources officielles
- github.com/fail2ban/fail2ban — dépôt officiel du projet
- github.com/fail2ban/fail2ban/wiki/Fail2Ban-and-Docker — wiki officiel, intégration Docker
- manpages.debian.org — fail2ban-client(1)
- mankier.com — fail2ban-regex
- debian.org — notes de version Bookworm, §5.1.7
- packages.ubuntu.com — paquet fail2ban
- tracker.debian.org/pkg/fail2ban
- archlinux.org/packages/extra/any/fail2ban
- fedoraproject.org/wiki/Fail2ban_with_FirewallD
- home-assistant.io/integrations/fail2ban