UFW a été conçu pour qu’un pare-feu se configure en trois commandes, et il y parvient. Le problème est ailleurs : ufw status montre des intentions, pas des résultats. Une règle peut figurer dans la liste et ne rien fermer du tout — pour trois raisons différentes, qui se rencontrent toutes régulièrement sur des serveurs réels.

Un départ qui ne vous enferme pas dehors

L’ordre des commandes compte. D’abord autoriser SSH, ensuite activer :

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw enable

ufw enable avant l’autorisation SSH coupe votre propre session, et il ne reste ensuite que la console de l’hébergeur. Si le serveur est déjà configuré et que vous n’êtes pas sûr, gardez une seconde connexion ouverte : elle survivra à une modification ratée.

Regardez l’état détaillé ; le court masque la politique par défaut :

sudo ufw status verbose

Erreur une : la règle existe et le port est ouvert au monde entier

La ligne la plus fréquente dans les configurations d’autrui :

sudo ufw allow 3306

C’est ainsi qu’on ouvre MySQL « pour pouvoir se connecter de chez soi » — et qu’on l’ouvre à tout l’internet. Il existe deux variantes correctes, toutes deux meilleures :

sudo ufw allow from 203.0.113.25 to any port 3306

ou, plus sûr encore, ne pas laisser le service sortir du tout : bind-address = 127.0.0.1 dans la configuration MySQL, et l’accès externe par un tunnel SSH. Le pare-feu est la seconde ligne ; la première est que le service n’écoute pas sur une adresse publique. Une règle UFW peut être supprimée par erreur, bind-address ne change pas tout seul.

Erreur deux : IPv6

Une règle du type ufw allow from 203.0.113.25 ne concerne qu’IPv4. Si le serveur possède une adresse IPv6 — et la plupart des VPS en ont une, activée —, le service y reste accessible. L’hébergeur a attribué l’adresse, vous ne vous en souvenez pas, le scanner la connaît.

Vérifiez que le filtrage v6 est bien activé (IPV6=yes dans /etc/default/ufw) et que le service n’écoute pas sur :: sans nécessité :

ss -tulpn | grep ':::'

Les règles qui nomment une adresse explicitement doivent être écrites séparément pour chaque version du protocole.

Erreur trois : Docker

La plus rageante. Docker publie les ports en écrivant ses propres règles dans les chaînes iptables avant celles où écrit UFW. De ce fait, un conteneur lancé avec -p 5432:5432 est accessible depuis l’internet, même si UFW affiche Status: active et une politique deny incoming. Le pare-feu n’est pas cassé pour autant — son tour ne vient simplement jamais.

Cela ne se corrige pas dans UFW mais dans la manière dont le port est publié :

ports:
  - "127.0.0.1:5432:5432"

L’attachement à l’adresse locale est la solution la plus simple et la plus fiable. Ne doit regarder vers l’extérieur que ce qui sert réellement les visiteurs : d’ordinaire les ports 80 et 443 d’un proxy inverse.

L’ordre des règles

UFW applique la première règle correspondante et s’arrête là. Un refus ajouté après une autorisation ne fonctionnera donc pas : on ne l’atteint jamais. Regardez la numérotation et insérez au bon endroit :

sudo ufw status numbered
sudo ufw insert 1 deny from 198.51.100.0/24
sudo ufw delete 7

Les règles se suppriment par numéro, mais les numéros se décalent après chaque suppression — supprimez une par une et relisez la liste à chaque fois.

La vérification depuis l’extérieur

Les commandes locales montrent ce qui est configuré. Ce qui en est réellement sorti ne se voit que depuis une autre machine :

nmap -Pn -p- 203.0.113.25
nc -zv 203.0.113.25 3306

N’importe quel autre serveur ou votre ordinateur personnel fera l’affaire. C’est la seule vérification qui ne ment pas, et elle vaut la peine après chaque reconfiguration notable — surtout après l’installation de quelque chose qui « configure le réseau tout seul » : Docker, panneaux de gestion, VPN.

Les journaux

Par défaut, UFW n’écrit presque rien. Cela s’active ainsi :

sudo ufw logging low

Les entrées vont dans /var/log/ufw.log — mais seulement si rsyslog est présent dans le système. Sous Debian 12 et Ubuntu 24.04, il peut manquer, et tout part alors dans le journal systemd :

sudo journalctl -k | grep -i '\[UFW'

Un /var/log/ufw.log vide ne signifie rien en soi — regardez d’abord dans le journal.

Ce qu’il faut attendre d’un pare-feu

UFW ferme ce qui ne doit pas être accessible. Il n’examine pas le contenu des requêtes vers ce qui est ouvert : le port 443 est ouvert à tous, et ce qui arrive sur le site y arrive sans entrave. C’est le travail d’autres outils — un WAF au niveau applicatif, un IDS au niveau du trafic. La tâche du pare-feu est plus modeste et plus importante : que la liste des ports ouverts corresponde à ce que vous croyez d’elle. À quoi ressemble cette liste avec les règles actives sur une page, la démonstration ci-dessous le montre.