Pare-feu : UFW et Docker
Sur une machine qui utilise Docker et UFW, un port publié par un conteneur reste joignable depuis Internet même si UFW l’interdit. Les exemples utilisent des noms génériques (web, port 8080).
Le problème
Section intitulée « Le problème »sudo ufw default deny incomingdocker run -d --name web -p 8080:80 nginx:alpineLe port 8080 n’est pas autorisé dans UFW, mais curl http://serveur.exemple.com:8080/ depuis une autre machine répond.
Docker écrit ses propres règles iptables (chaînes DOCKER et DOCKER-USER) pour la traduction d’adresses et le transfert vers le conteneur. Le trafic publié passe par la chaîne FORWARD, avant les règles d’UFW qui filtrent le trafic destiné à la machine elle-même. Docker Compose se comporte de la même façon.
Solution 1 : publier sur 127.0.0.1 (recommandée)
Section intitulée « Solution 1 : publier sur 127.0.0.1 (recommandée) »docker run -d --name web -p 127.0.0.1:8080:80 nginx:alpineDans compose.yaml :
services: web: image: nginx:alpine ports: - '127.0.0.1:8080:80'Un reverse proxy installé sur l’hôte (Caddy, Nginx) écoute sur 80 et 443, que UFW gère normalement, et transmet vers 127.0.0.1:8080 (voir Exemple : VPS avec Caddy).
Solution 2 : ne pas publier de port
Section intitulée « Solution 2 : ne pas publier de port »Les conteneurs d’un même réseau Docker se joignent par leur nom. Seul le service public publie un port :
services: app: image: monapp:1.0 # pas de « ports: » proxy: image: caddy:2 ports: - '80:80' - '443:443'Solution 3 : la chaîne DOCKER-USER
Section intitulée « Solution 3 : la chaîne DOCKER-USER »Docker évalue la chaîne DOCKER-USER avant ses propres règles et ne l’écrase pas : c’est l’endroit prévu pour filtrer le trafic transféré vers les conteneurs.
sudo iptables -I DOCKER-USER -i eth0 -p tcp --dport 8080 ! -s 198.51.100.7 -j DROPsudo iptables -S DOCKER-USERCette règle refuse le port 8080 depuis l’interface publique eth0, sauf pour une adresse. Elle ne survit pas au redémarrage : la rendre persistante (par exemple dans /etc/ufw/after.rules ou avec iptables-persistent). Une règle trop large coupe aussi l’accès des conteneurs à Internet.
Solution 4 : l’outil ufw-docker
Section intitulée « Solution 4 : l’outil ufw-docker »Le projet tiers ufw-docker ajoute à /etc/ufw/after.rules un bloc qui filtre le trafic vers Docker et permet d’écrire des règles par conteneur (ufw-docker allow web 80/tcp). Lire son script avant de l’installer.
À éviter
Section intitulée « À éviter »{ "iptables": false } dans /etc/docker/daemon.json empêche Docker de modifier le pare-feu, mais supprime aussi le NAT et la publication de ports : déconseillé.
Vérifier
Section intitulée « Vérifier »Toujours depuis une autre machine :
nc -vz -w 3 serveur.exemple.com 8080nmap -Pn -p 8080,3306,5432,6379,27017 serveur.exemple.comSur le serveur :
docker ps --format 'table {{.Names}}\t{{.Ports}}'sudo ss -tlnp | grep docker-proxyColonne PORTS |
Accessible depuis |
|---|---|
127.0.0.1:8080->80/tcp |
La machine elle-même |
0.0.0.0:8080->80/tcp |
Toutes les interfaces, donc Internet |
[::]:8080->80/tcp |
Idem en IPv6 |
Bases de données dans Docker
Section intitulée « Bases de données dans Docker »docker run -p 5432:5432 postgres ou -p 6379:6379 redis ouvre la base à Internet. Publier sur 127.0.0.1 (-p 127.0.0.1:5432:5432) ou ne pas publier, et activer l’authentification.
Dépannage
Section intitulée « Dépannage »| Symptôme | Piste |
|---|---|
| Un port « interdit » répond | Port publié par Docker : docker ps, publier sur 127.0.0.1 |
Conteneurs sans Internet après une règle DOCKER-USER |
Règle trop large : sudo iptables -D DOCKER-USER … |
Règles DOCKER-USER perdues au redémarrage |
Les rendre persistantes |
Ubuntu 24.04 et 26.04 : différences à connaître
Section intitulée « Ubuntu 24.04 et 26.04 : différences à connaître »Même comportement sur les deux versions (UFW 0.36.2, iptables-nft). Voir aussi Docker : réseau.
Pour aller plus loin
Section intitulée « Pour aller plus loin »- Documentation Docker : Packet filtering and firewalls
- Suite : Fail2ban : installation