Skip to main content

Gestion du réseau et des ports Docker

Cette page est dédier à la question suivante :

Comment bien configuré ses conteneurs sur le réseau ?

Portée : Docker Compose, hosts Linux avec UFW comme pare-feu, reverse proxy type Traefik/Caddy/nginx.
Objectif : standardiser une architecture réseau 100 % maîtrisée sur toutes les stacks compose.

 

1. Comportement par défaut de Docker

1.1 Réseaux créés automatiquement

Par défaut, docker compose up crée un réseau bridge dédié par projet (nommé <nom_projet>_default), distinct du bridge docker0 historique. 
Tous les services d'un même fichier compose sont attachés à ce réseau et se résolvent entre eux par nom de service (DNS interne Docker), sans avoir besoin de publier le moindre port.

➡️ Conséquence clé : la communication inter-conteneurs ne nécessite jamais ports:. 
ports: ne sert qu'à exposer un service en dehors du host Docker (vers le LAN/WAN).

 
1.2 EXPOSE vs ports:
Directive Effet réel Portée
EXPOSE (Dockerfile) Documentation uniquement, aucun binding réseau réel N/A
expose: (compose) Idem, informatif N/A
ports: (compose) Publie réellement le port sur une interface du host via NAT Host + extérieur
 
1.3 Docker et iptables : le piège UFW

C'est le point le plus critique en environnement Ops/DevSec.

Quand un conteneur publie un port avec ports:, Docker insère automatiquement des règles dans les chaînes DOCKER et DOCKER-USER de la table nat/filter d'iptables — en amont de la chaîne INPUT gérée par UFW.

Conséquence : un port publié via ports: est accessible depuis l'extérieur même si UFW le bloque explicitement. 
UFW ne voit jamais passer ce trafic car Docker route directement via NAT/FORWARD.

Trafic entrant → PREROUTING (Docker DNAT) → FORWARD → DOCKER-USER → DOCKER → conteneur
                                                ↑
                                    UFW (INPUT) n'intercepte PAS ce chemin

 


2. Le comportement de ports: en détail

2.1 Syntaxes

 

ports:
  - "8080:80"            # host:container — bind 0.0.0.0 (TOUTES interfaces) par défautdéfaut, port ouvert sur iptables
  - "127.0.0.1:8080:80"  # bind explicite localhost uniquement
  - "10.10.10.1:8080:80" # bind sur une IP précise (ex: interface WireGuard)
  - "8080:80/udp"        # protocole expliciteexplicite, port ouvert sur iptables
    2.2 Le piège du binding implicite

    "8080:80" publie sur 0.0.0.0:8080, donc sur toutes les interfaces réseau du host (LAN, WAN, VPN...), pas seulement en local.

    C'est la cause n°1 des services/ports exposées par erreur sur Internet.


    3. Bonnes pratiques Ops / DevSec

      Principe de moindre exposition : ne publier (ports:) que ce qui doit être joignable depuis l'extérieur du host. Tout le reste communique via le réseau interne Docker (DNS de service). Un réseau dédié par stack, jamais le réseau default partagé pour plusieurs projets sans raison. Nommer explicitement :

       


      Quelle configuration utiliser ? 

      Avec Docker il existe plusieurs moyens de configurer l'accès aux conteneurs. Chaque solution répond à un besoin bien spécifique. 

      Le cas "Reverse Proxy" : Pour les services derrière le Reverse Proxy (Apache, nginx, traefik, etc..)
      Empêchez Docker d'exposer ces services sur Internet. Liez-les uniquement à l'interface locale (127.0.0.1).
      Les requêtes passeront par le proxy (80/443), et personne ne pourra contourner le proxy en tapant directement le port du service.

      ports:
        - "127.0.0.1:8080:8080" # Invisible de l'extérieur, accessible par le pr