Accéder à l'hôte depuis un conteneur Docker : guide complet de host.docker.internal

Vendredi 15 h, je fixais le message d’erreur dans le terminal — Connection refused.
Franchement, c’était frustrant. MySQL tournait bien en local, Navicat se connectait, la ligne de commande aussi, mais l’application dans le conteneur refusait obstinément de joindre. J’ai vérifié trois fois la chaîne de connexion : localhost:3306, rien à redire. Utilisateur et mot de passe corrects. Alors, où était le problème ?
Finalement, j’ai compris : le coupable, c’étaient ces trois lettres — localhost.
Si vous avez déjà vécu ça — dans un conteneur Docker, localhost ou 127.0.0.1 ne joint jamais les services de l’hôte — cet article est pour vous. Je vais expliquer clairement pourquoi localhost dans un conteneur n’est pas celui que vous croyez, et comment résoudre le problème proprement avec host.docker.internal, ce « domaine magique ».
Dans cet article, vous apprendrez :
- Le vrai principe de l’isolation réseau des conteneurs (sans jargon inutile)
- La bonne configuration sur Mac, Windows et Linux
- Une checklist de dépannage pratique (à consulter la prochaine fois)
Pourquoi localhost ne fonctionne pas ?
Réponse directe : un conteneur a son propre monde réseau.
Un peu abstrait ? Imaginez le conteneur comme une petite maison indépendante, avec sa propre adresse, sa propre boîte aux lettres, tout. Quand vous dites « localhost » ou frappez à « 127.0.0.1 » dans le conteneur, vous cherchez cette petite maison, pas la machine hôte à l’extérieur.
Concrètement :
- Sur l’hôte,
localhostpointe vers l’hôte lui-même - Dans le conteneur,
localhostpointe vers le conteneur lui-même - Deux
localhost, ce n’est pas la même chose
La première fois que j’ai compris ça, j’ai été surpris. MySQL tournait pourtant bien sur mon ordinateur — pourquoi le conteneur ne pouvait-il pas s’y connecter ? Parce que le conteneur cherchait MySQL dans son propre monde, et ne le trouvait évidemment pas.
Mécanisme d’isolation réseau des conteneurs
Docker crée pour chaque conteneur un « espace de noms réseau » indépendant (ne vous laissez pas intimider par le terme). En bref :
Chaque conteneur a sa propre carte réseau, sa propre adresse IP, sa propre table de routage. Comme chez vous et chez le voisin : même immeuble, mais chacun son Wi-Fi, sans interférence.
Conteneur et hôte sont reliés par un pont virtuel appelé docker0. L’IP du conteneur ressemble souvent à 172.17.0.x ; du point de vue du conteneur, l’hôte est à 172.17.0.1 (adresse de la passerelle du pont).
Dans le conteneur, accéder à localhost, c’est accéder au 127.0.0.1 du conteneur, pas au 127.0.0.1 de l’hôte. Impossible de joindre MySQL sur l’hôte.
Voici à quoi ressemble une erreur typique :
Error: connect ECONNREFUSED 127.0.0.1:3306
Ou :
Can't connect to MySQL server on 'localhost' (111)
C’est l’erreur classique quand on utilise localhost dans un conteneur pour joindre un service sur l’hôte.
Qu’est-ce que host.docker.internal ?
Puisque localhost ne convient pas, comment faire accéder le conteneur à l’hôte ?
Docker propose une solution élégante : host.docker.internal. C’est un domaine spécial qui se résout automatiquement vers l’IP de l’hôte. Considérez-le comme le « surnom » de l’hôte — quelle que soit l’IP réelle, ce nom suffit pour le trouver.
Par exemple, si MySQL écoute sur le port 3306 de l’hôte, connectez-vous ainsi dans le conteneur :
mysql://user:[email protected]:3306/dbname
Pas besoin de savoir si l’hôte est en 192.168.1.100 ou 10.0.0.5, ni de craindre un changement de réseau — host.docker.internal pointe toujours vers la bonne adresse.
Pratique, non ?
Versions et support par plateforme
Attention, il y a un piège.
Utilisateurs Mac et Windows (Docker Desktop)
Avec Docker Desktop (l’interface graphique), host.docker.internal est supporté nativement depuis la version 18.03 (mars 2018). Prêt à l’emploi, sans configuration supplémentaire.
Écrivez directement host.docker.internal dans le code :
const mysql = require('mysql2');
const connection = mysql.createConnection({
host: 'host.docker.internal', // aussi simple que ça
port: 3306,
user: 'root',
password: 'your_password'
});
Utilisateurs Linux (Docker Engine)
Linux est moins chanceux. Docker y tourne directement sur le système, sans machine virtuelle intermédiaire comme sur Mac/Windows — host.docker.internal n’existe pas par défaut.
Bonne nouvelle : depuis Docker Engine 20.10 (décembre 2020), on peut l’activer manuellement. Comment ? La section suivante détaille tout.
Pour des versions plus anciennes, quelques alternatives :
- Utiliser
172.17.0.1(IP de la passerelle du pont Docker par défaut) - Utiliser l’IP réelle de l’hôte sur le réseau Docker
- Utiliser
docker.for.mac.host.internal(anciennes versions Mac uniquement)
Configuration sur les trois plateformes
Voici le concret, avec des configurations copiables.
Configuration Mac/Windows (Docker Desktop)
Le cas le plus simple.
Méthode 1 : utilisation directe dans le code
Aucune configuration supplémentaire — écrivez host.docker.internal directement :
# docker-compose.yml
version: '3'
services:
app:
image: myapp:latest
environment:
- DB_HOST=host.docker.internal # directement
- DB_PORT=3306
Méthode 2 : déclaration explicite (optionnelle)
Même si ce n’est pas nécessaire, vous pouvez ajouter extra_hosts :
version: '3'
services:
app:
image: myapp:latest
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
- DB_HOST=host.docker.internal
host-gateway est la syntaxe Docker 20.10+, signifiant « adresse de la passerelle de l’hôte ».
Avec docker run :
docker run -d \
--add-host=host.docker.internal:host-gateway \
-e DB_HOST=host.docker.internal \
myapp:latest
Configuration Linux (Docker Engine)
Sur Linux, c’est un peu plus laborieux — configuration manuelle requise.
Méthode 1 : recommandée — host-gateway
La méthode la plus universelle, pour Docker 20.10+ sur toutes les plateformes :
# docker-compose.yml
version: '3'
services:
app:
image: myapp:latest
extra_hosts:
- "host.docker.internal:host-gateway" # configuration clé
environment:
- DB_HOST=host.docker.internal
- DB_PORT=3306
Avec docker run :
docker run -d \
--add-host=host.docker.internal:host-gateway \
-e DB_HOST=host.docker.internal \
myapp:latest
Avantage : multi-plateforme — la même configuration fonctionne sur Mac, Windows et Linux.
Méthode 2 : alternative — IP du pont Docker
Si host-gateway n’est pas disponible (Docker trop ancien), utilisez l’adresse de la passerelle du pont par défaut :
version: '3'
services:
app:
image: myapp:latest
extra_hosts:
- "host.docker.internal:172.17.0.1" # passerelle Docker par défaut
environment:
- DB_HOST=host.docker.internal
172.17.0.1 est la passerelle par défaut du réseau bridge Docker. Dans la grande majorité des cas, cette IP est correcte, sauf si vous avez modifié la configuration réseau Docker.
Méthode 3 : ultime — mode réseau host
Si rien d’autre ne fonctionne, voici la solution radicale :
docker run -d \
--network=host \
-e DB_HOST=localhost \ # localhost fonctionne ici
myapp:latest
Ou dans docker-compose :
version: '3'
services:
app:
image: myapp:latest
network_mode: "host" # réseau de l'hôte
environment:
- DB_HOST=localhost # localhost utilisable directement
Avantages : simple et direct — le conteneur utilise la pile réseau de l’hôte, localhost est le vrai localhost.
Inconvénients :
- Compromet l’isolation réseau du conteneur
- Conteneur et hôte partagent les ports, risque de conflit (ex. le conteneur veut le 8080 déjà pris sur l’hôte)
- Linux uniquement, Mac/Windows non supportés
- Non recommandé en production, réservé au dev local
Configuration multi-plateforme (fortement recommandée)
Si votre équipe mélange Mac et Linux, ou si votre code tourne dans plusieurs environnements, utilisez :
# docker-compose.yml
version: '3'
services:
app:
image: myapp:latest
extra_hosts:
- "host.docker.internal:host-gateway" # reconnu sur toutes les plateformes
environment:
- DB_HOST=host.docker.internal
- DB_PORT=3306
- DB_USER=root
- DB_PASSWORD=your_password
Cette configuration fonctionne sur toutes les plateformes Docker 20.10+ (fin 2020). Si votre Docker date d’avant 2020… honnêtement, il est temps de mettre à jour.
Points clés pour les services sur l’hôte
Configurer le conteneur ne suffit pas.
Les services sur l’hôte doivent aussi être correctement configurés, sinon la connexion échouera. Beaucoup l’oublient — voici ce qu’il faut savoir.
Le service doit écouter sur la bonne adresse
C’est le piège le plus courant.
Beaucoup de services n’écoutent par défaut que sur 127.0.0.1, donc uniquement les connexions locales. Or un conteneur Docker n’est pas « local » — les requêtes venant du pont Docker seront refusées.
Il faut écouter sur 0.0.0.0, c’est-à-dire accepter les connexions sur toutes les interfaces.
Configuration MySQL
Fichier de configuration, généralement :
- Linux :
/etc/mysql/mysql.conf.d/mysqld.cnf - Mac (Homebrew) :
/usr/local/etc/my.cnf - Windows :
C:\ProgramData\MySQL\MySQL Server 8.0\my.ini
Modifiez bind-address :
[mysqld]
# Avant, souvent :
# bind-address = 127.0.0.1
# Changez en :
bind-address = 0.0.0.0
Puis redémarrez MySQL :
# Linux
sudo systemctl restart mysql
# Mac
brew services restart mysql
# Windows
# Redémarrer le service MySQL dans le gestionnaire de services
Configuration Redis
Éditez redis.conf (souvent /etc/redis/redis.conf ou /usr/local/etc/redis.conf) :
# Trouvez cette ligne
bind 127.0.0.1 -::1
# Changez en
bind 0.0.0.0
Redémarrez Redis :
# Linux
sudo systemctl restart redis
# Mac
brew services restart redis
Configuration PostgreSQL
Éditez postgresql.conf :
listen_addresses = '*' # écouter sur toutes les adresses
Modifiez aussi pg_hba.conf pour autoriser le segment Docker :
# Ajoutez cette ligne pour autoriser 172.17.0.0/16
host all all 172.17.0.0/16 md5
Configuration des droits utilisateur (MySQL)
Même si MySQL écoute sur 0.0.0.0, les droits utilisateur comptent encore.
Les droits MySQL sont gérés par « utilisateur@hôte source ». root@localhost et root@% sont deux utilisateurs distincts.
Si votre utilisateur MySQL n’autorise que localhost, le conteneur ne pourra pas se connecter. Accordez les droits pour le segment Docker :
-- Option 1 : accès depuis n'importe quel hôte (simple mais moins sûr)
GRANT ALL PRIVILEGES ON *.* TO 'your_user'@'%' IDENTIFIED BY 'your_password';
-- Option 2 : segment Docker uniquement (plus sûr)
GRANT ALL PRIVILEGES ON *.* TO 'your_user'@'172.17.0.%' IDENTIFIED BY 'your_password';
-- Recharger les droits
FLUSH PRIVILEGES;
Pour MySQL 8.0+, la syntaxe diffère légèrement :
-- Créer l'utilisateur
CREATE USER 'your_user'@'%' IDENTIFIED BY 'your_password';
-- Accorder les droits
GRANT ALL PRIVILEGES ON *.* TO 'your_user'@'%';
FLUSH PRIVILEGES;
Configuration du pare-feu
Sur certains systèmes, le pare-feu bloque l’accès des conteneurs Docker aux services de l’hôte.
Vérifier l’état du pare-feu :
# Linux (ufw)
sudo ufw status
# Linux (firewalld)
sudo firewall-cmd --state
Autoriser le segment Docker (exemple port MySQL 3306) :
# ufw
sudo ufw allow from 172.17.0.0/16 to any port 3306
# firewalld
sudo firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="172.17.0.0/16" port port="3306" protocol="tcp" accept'
sudo firewall-cmd --reload
Recommandations de sécurité
Écouter sur 0.0.0.0 comporte un risque — votre service devient accessible à d’autres machines du réseau.
En production :
-
Écouter sur une interface spécifique : si vous connaissez l’interface Docker, n’écoutez que celle-ci
bind-address = 172.17.0.1 -
Combiner avec le pare-feu : autoriser uniquement le segment Docker, bloquer le reste
-
Utiliser un conteneur de base de données dédié : ne pas faire tourner la BDD sur l’hôte ; lancez-la via Docker Compose, conteneur app et conteneur BDD sur le même réseau — plus sûr
En développement local :
Honnêtement, écouter sur 0.0.0.0 en local pose peu de problème. Votre machine n’est pas un serveur, l’extérieur n’y accède pas. Pas de stress.
Checklist de dépannage des problèmes courants
Problème de connexion ? Pas de panique — suivez cette checklist.
Problème 1 : Connection refused (connexion refusée)
L’erreur la plus fréquente :
Error: connect ECONNREFUSED host.docker.internal:3306
Ou :
Can't connect to MySQL server on 'host.docker.internal' (111)
Causes possibles et étapes :
Étape 1 : vérifier que le service tourne sur l’hôte
Sur l’hôte :
# MySQL
sudo systemctl status mysql # Linux
brew services list # Mac
# Vérifier que le port est en écoute
netstat -an | grep 3306
# ou
lsof -i :3306
Si le service n’est pas démarré, démarrez-le d’abord.
Étape 2 : vérifier l’adresse d’écoute
Sur l’hôte :
# Voir sur quelle adresse MySQL écoute
sudo netstat -tlnp | grep 3306
La sortie devrait ressembler à :
tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN 1234/mysqld
Regardez la troisième colonne. Si c’est 0.0.0.0:3306, tout va bien. Si c’est 127.0.0.1:3306, le service n’écoute que localement — le conteneur ne pourra pas se connecter.
Solution : modifiez bind-address en 0.0.0.0 comme dans la section « Configuration des services sur l’hôte ».
Étape 3 : vérifier le pare-feu
Désactivez temporairement le pare-feu pour tester :
# Linux (ufw)
sudo ufw disable
# Linux (firewalld)
sudo systemctl stop firewalld
# Mac
# Réglages système -> Sécurité et confidentialité -> Pare-feu -> Désactiver
Si ça fonctionne sans pare-feu, c’était bien lui. Configurez les règles comme indiqué plus haut, puis réactivez le pare-feu.
Problème 2 : Connection timeout (délai dépassé)
Error: connect ETIMEDOUT host.docker.internal:3306
Un timeout est plus délicat qu’un refus — les paquets partent mais ne reviennent pas.
Étapes :
Étape 1 : vérifier la résolution de host.docker.internal
Dans le conteneur :
# Entrer dans le conteneur
docker exec -it your_container sh
# Tester
ping host.docker.internal
Si ping échoue ou « unknown host », host.docker.internal n’est pas configuré.
Utilisateurs Linux : vérifiez que docker-compose.yml ou docker run inclut --add-host=host.docker.internal:host-gateway.
Étape 2 : vérifier le numéro de port
Êtes-vous sûr que c’est 3306 ? MySQL a peut-être un autre port.
Sur l’hôte :
# Port réel de MySQL
sudo netstat -tlnp | grep mysqld
Étape 3 : tester la connectivité conteneur → hôte
Dans le conteneur :
# Tester le port
telnet host.docker.internal 3306
# Sans telnet, utiliser nc
nc -zv host.docker.internal 3306
Si le port ne répond pas, revérifiez pare-feu et configuration du service.
Problème 3 : Unknown host (host.docker.internal introuvable)
getaddrinfo ENOTFOUND host.docker.internal
Échec de résolution DNS — le conteneur ne connaît pas host.docker.internal.
Solution :
Ajoutez extra_hosts à la configuration :
services:
app:
extra_hosts:
- "host.docker.internal:host-gateway"
Ou avec docker run :
docker run --add-host=host.docker.internal:host-gateway ...
Problème 4 : Échec d’authentification (Access denied)
Access denied for user 'root'@'172.17.0.2' (using password: YES)
MySQL est joignable, mais les droits utilisateur sont incorrects.
Solution :
-- Voir les droits actuels
SELECT user, host FROM mysql.user WHERE user='root';
-- S'il n'y a que root@localhost, créer root@% ou [email protected].%
CREATE USER 'root'@'%' IDENTIFIED BY 'your_password';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%';
FLUSH PRIVILEGES;
Problème 5 : Configuration multi-plateforme incohérente
Mac et Linux partagent le même docker-compose.yml — ça marche sur Mac, pas sur Linux.
Solution :
Unifiez avec host-gateway, valable partout :
services:
app:
extra_hosts:
- "host.docker.internal:host-gateway"
Assurez-vous que Docker ≥ 20.10. Si quelqu’un a une version trop ancienne, incitez-le à mettre à jour.
Formule de dépannage rapide
En cas de problème de connexion, dans cet ordre :
- Service démarré ? →
systemctl status/brew services list - Bonne adresse d’écoute ? →
netstat -tlnp,0.0.0.0ou127.0.0.1? - Conteneur configuré ? → vérifier
extra_hostsou--add-host - DNS OK ? →
ping host.docker.internaldans le conteneur - Port accessible ? →
telnetouncdans le conteneur - Pare-feu actif ? → désactiver temporairement pour tester
- Droits accordés ? → utilisateur MySQL
@localhostou@%?
Dans neuf cas sur dix, c’est l’un des trois premiers.
Cas pratiques
Assez de théorie — deux exemples concrets.
Cas 1 : application Spring Boot et MySQL sur l’hôte
Scénario : projet Spring Boot conteneurisé, base MySQL locale sur l’hôte.
Étape 1 : configurer Spring Boot
application.yml :
spring:
datasource:
# host.docker.internal pour joindre MySQL sur l'hôte
url: jdbc:mysql://host.docker.internal:3306/mydb?useSSL=false&serverTimezone=UTC
username: root
password: your_password
driver-class-name: com.mysql.cj.jdbc.Driver
Étape 2 : Docker Compose
docker-compose.yml :
version: '3.8'
services:
app:
build: .
ports:
- "8080:8080"
extra_hosts:
- "host.docker.internal:host-gateway" # configuration clé
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://host.docker.internal:3306/mydb
SPRING_DATASOURCE_USERNAME: root
SPRING_DATASOURCE_PASSWORD: your_password
Étape 3 : MySQL sur l’hôte
Éditez /etc/mysql/mysql.conf.d/mysqld.cnf :
[mysqld]
bind-address = 0.0.0.0
Redémarrez MySQL :
sudo systemctl restart mysql
Accordez les droits :
CREATE USER 'root'@'%' IDENTIFIED BY 'your_password';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%';
FLUSH PRIVILEGES;
Étape 4 : lancer et tester
docker-compose up --build
Si vous voyez HikariPool-1 - Start completed, la connexion à la base est établie.
Retour d’expérience :
Ma première config a donné Connection refused. Dépannage :
- MySQL démarré ?
systemctl status mysql→ oui - Adresse d’écoute ?
netstat -tlnp | grep 3306→127.0.0.1:3306 - Modifié
bind-address = 0.0.0.0, redémarré MySQL - Relancé — connecté
Cas 2 : application Node.js et Redis sur l’hôte
Scénario : projet Node.js avec Redis en cache, Redis sur l’hôte en dev local.
Étape 1 : code Node.js
// redis-client.js
const redis = require('redis');
const client = redis.createClient({
host: process.env.REDIS_HOST || 'host.docker.internal',
port: process.env.REDIS_PORT || 6379,
// Si Redis a un mot de passe
password: process.env.REDIS_PASSWORD
});
client.on('connect', () => {
console.log('Redis connected successfully');
});
client.on('error', (err) => {
console.error('Redis error:', err);
});
module.exports = client;
Étape 2 : Docker Compose
docker-compose.yml :
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
NODE_ENV: development
REDIS_HOST: host.docker.internal
REDIS_PORT: 6379
Étape 3 : Redis sur l’hôte
Éditez /etc/redis/redis.conf ou /usr/local/etc/redis.conf :
# Trouvez bind
bind 127.0.0.1 ::1
# Changez en
bind 0.0.0.0
Si protected-mode yes :
protected-mode no # OK en dev local, pas en production
Redémarrez Redis :
# Linux
sudo systemctl restart redis
# Mac
brew services restart redis
Étape 4 : vérification
docker-compose up
Redis connected successfully — c’est bon.
Multi-plateforme :
Avec variables d’environnement unifiées :
const REDIS_HOST = process.env.REDIS_HOST || (
process.platform === 'linux' ? 'host.docker.internal' : 'host.docker.internal'
);
En fait, tout le monde peut utiliser host.docker.internal maintenant. Avec extra_hosts: ["host.docker.internal:host-gateway"] dans Docker Compose, Mac et Linux partagent la même config.
Cas 3 : environnement de dev complet
Modèle pratique — conteneur app, MySQL et Redis sur l’hôte :
# docker-compose.yml
version: '3.8'
services:
app:
build: .
ports:
- "8080:8080"
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
# Base de données
DB_HOST: host.docker.internal
DB_PORT: 3306
DB_NAME: myapp
DB_USER: root
DB_PASSWORD: your_password
# Redis
REDIS_HOST: host.docker.internal
REDIS_PORT: 6379
# Application
NODE_ENV: development
PORT: 8080
volumes:
- .:/app
- /app/node_modules # ne pas monter node_modules
command: npm run dev # hot reload en dev
Checklist de configuration sur l’hôte :
# MySQL
# Éditer /etc/mysql/mysql.conf.d/mysqld.cnf
bind-address = 0.0.0.0
# Redémarrer : sudo systemctl restart mysql
# Redis
# Éditer /etc/redis/redis.conf
bind 0.0.0.0
protected-mode no
# Redémarrer : sudo systemctl restart redis
# Pare-feu (si nécessaire)
sudo ufw allow from 172.17.0.0/16 to any port 3306
sudo ufw allow from 172.17.0.0/16 to any port 6379
Cette config fonctionne sur Mac et Linux — copier-coller et c’est parti.
Résumé
Trois points essentiels :
1. Comprendre le principe
Le conteneur a son propre réseau ; localhost dans le conteneur, c’est le conteneur, pas l’hôte. C’est l’isolation par espace de noms réseau — une conception Docker, pas un bug.
2. Choisir la bonne méthode
Selon votre environnement :
| Environnement | Solution recommandée | Configuration |
|---|---|---|
| Mac/Windows (Docker Desktop) | host.docker.internal directement | Aucune config supplémentaire |
| Linux (Docker Engine 20.10+) | extra_hosts: host-gateway | docker-compose ou —add-host |
| Équipe multi-plateforme | extra_hosts: host-gateway | Config unifiée |
| Ancien Linux | 172.17.0.1 | extra_hosts avec IP |
| Dernier recours | --network=host | Dev local uniquement, compromet l’isolation |
3. Configurer les services
Le conteneur seul ne suffit pas — configurez aussi l’hôte :
- Adresse d’écoute
0.0.0.0 - Droits MySQL pour le segment Docker
- Pare-feu autorisant le segment Docker
Arbre de décision rapide
Problème de connexion :
Impossible de joindre l'hôte ?
↓
Mac/Windows ou Linux ?
↓
Mac/Windows :
→ host.docker.internal directement
→ Sinon, vérifier la config des services sur l'hôte
Linux :
→ Docker ≥ 20.10 ?
Oui → extra_hosts: host-gateway
Non → extra_hosts: 172.17.0.1
→ Vérifier les services sur l'hôte
→ Vérifier le pare-feu
Tout essayé sans succès ?
→ Checklist de dépannage
→ Dernier recours : --network=host (dev local uniquement)
Pour finir
Le développement conteneurisé est pratique, mais le réseau recèle des pièges. Maîtriser host.docker.internal et host-gateway règle la plupart des cas.
Gardez cet article sous la main pour la prochaine panne de connexion. Partagez-le avec vos collègues qui galèrent encore sur ce sujet.
Si vous avez rencontré des problèmes réseau conteneur plus étranges, ou une meilleure solution, dites-le en commentaire — ça peut aider d’autres personnes.
Configuration complète pour accéder à l'hôte depuis un conteneur Docker
Résoudre les problèmes d'accès aux services de l'hôte avec host.docker.internal sur Mac, Windows et Linux
⏱️ Estimated time: 15 min
- 1
Step 1: Comprendre la cause et la solution
Cause : localhost ou 127.0.0.1 dans un conteneur ne joint jamais les services de l'hôte, car localhost pointe vers le conteneur lui-même, pas l'hôte — une configuration spéciale est nécessaire.
Solution : utiliser host.docker.internal, un « domaine magique » qui se résout automatiquement vers l'IP de l'hôte.
Support par plateforme :
• Mac/Windows : support natif Docker Desktop, sans configuration supplémentaire
• Linux : Docker 20.10+ requis, avec --add-host ou extra_hosts dans docker-compose - 2
Step 2: Configuration Mac/Windows
Étapes Mac/Windows :
1. Utiliser directement host.docker.internal :
docker run -e DATABASE_URL=host.docker.internal:3306 my-app
2. Remplacer localhost dans la configuration applicative :
• Chaîne de connexion : host.docker.internal:3306
• Variable d'environnement : DATABASE_HOST=host.docker.internal
3. Vérifier la connexion :
• Test dans le conteneur : docker exec -it container-name ping host.docker.internal
• Test direct de la connexion applicative
Note : Mac/Windows ne nécessitent aucune configuration supplémentaire, Docker Desktop gère tout automatiquement. - 3
Step 3: Configuration et dépannage Linux
Méthodes Linux :
1. Docker ≥ 20.10 (recommandé) :
docker run --add-host=host.docker.internal:host-gateway my-app
Ou dans docker-compose.yml :
extra_hosts:
- "host.docker.internal:host-gateway"
2. Docker < 20.10 :
docker run --add-host=host.docker.internal:172.17.0.1 my-app
3. Checklist de dépannage complète :
• Confirmer que le service tourne sur l'hôte (netstat -tuln | grep 3306)
• Vérifier que le port est ouvert (telnet host.docker.internal 3306)
• Remplacer localhost par host.docker.internal
• Sur Linux, ajouter --add-host
• Vérifier le pare-feu (iptables -L)
• Confirmer que le service écoute sur 0.0.0.0 et non 127.0.0.1
FAQ
Pourquoi localhost dans un conteneur ne joint-il pas les services de l'hôte ?
Comme deux maisons distinctes sur la même machine physique, chacune a sa propre adresse réseau. Quand le conteneur accède à localhost, il accède au réseau interne du conteneur, pas à celui de l'hôte.
Solution : utiliser host.docker.internal, un domaine spécial qui se résout automatiquement vers l'IP de l'hôte, permettant au conteneur d'accéder aux services de l'hôte.
host.docker.internal est-il supporté sur toutes les plateformes ?
• Mac/Windows (Docker Desktop) : support natif, sans configuration
• Linux (Docker 20.10+) : configuration manuelle --add-host requise
• Linux (Docker < 20.10) : utiliser 172.17.0.1 comme IP de l'hôte
Pour les équipes multi-plateformes : unifier avec extra_hosts dans docker-compose pour que toutes les plateformes fonctionnent.
Que faire si host.docker.internal ne fonctionne toujours pas ?
1. Vérifier que le service tourne sur l'hôte :
netstat -tuln | grep numéro_de_port
2. Confirmer l'adresse d'écoute du service :
Le service doit écouter sur 0.0.0.0, pas uniquement 127.0.0.1
3. Tester la connectivité réseau :
docker exec -it container-name ping host.docker.internal
docker exec -it container-name telnet host.docker.internal numéro_de_port
4. Vérifier les règles de pare-feu :
iptables -L (Linux)
Paramètres du pare-feu Windows
5. Dernier recours (environnement de dev uniquement) :
--network=host (compromet l'isolation du conteneur)
Faut-il utiliser host.docker.internal en production ?
• Utiliser les noms de service (réseau Docker Compose) ou les noms de conteneurs
• Utiliser des adresses IP explicites
• Utiliser un mécanisme de découverte de services (Consul, etcd, etc.)
host.docker.internal sert surtout à :
• L'environnement de développement local
• Le débogage et les tests
• Accéder aux outils de dev sur l'hôte (base de données, Redis, etc.)
En production, host.docker.internal entraîne :
• Une dépendance à la configuration réseau de l'hôte
• Une réduction des avantages de la conteneurisation
• Une complexité opérationnelle accrue
14 min de lecture · Publié le: 17 déc. 2025 · Mis à jour le: 27 juil. 2026
Guide pratique Docker
Si vous arrivez depuis la recherche, le plus rapide est de passer à l’article précédent ou suivant de cette série.
Précédent
Mapping de ports Docker : ne laissez pas « port déjà alloué » gâcher votre vendredi soir
Du diagnostic d'occupation de port à l'optimisation des performances : résoudre systématiquement tous les casse-têtes du mapping de ports Docker et dire adieu à l'erreur port already allocated
Partie 20 sur 38
Suivant
Modes réseau Docker en pratique : guide de choix entre bridge, host et overlay
Comparaison approfondie des trois modes réseau Docker : performances, cas d'usage et configuration, avec arbre de décision et données de benchmark. Bridge par défaut en mono-hôte, host pour la performance, overlay obligatoire en multi-hôtes.
Partie 22 sur 38



Commentaires
Connectez-vous avec GitHub pour laisser un commentaire