Como acessar o host a partir de um contêiner Docker: guia completo do host.docker.internal

Era sexta-feira, três da tarde, e eu estava olhando para a mensagem de erro no terminal: Connection refused.
Para ser sincero, naquele momento eu já estava bem frustrado. O MySQL local funcionava normalmente, o Navicat conseguia se conectar e o terminal também. Mas a aplicação dentro do contêiner simplesmente não conectava. Revisei a string de conexão três vezes: localhost:3306. Parecia certa. O usuário e a senha também estavam corretos. Então, onde estava o problema?
No fim, descobri que o culpado era justamente localhost.
Se você já passou por algo parecido — tentar acessar um serviço do host com localhost ou 127.0.0.1 dentro de um contêiner Docker e receber erro — este artigo é para você. Vou explicar da forma mais direta possível por que o localhost do contêiner não é o localhost que você imagina e como usar o domínio especial host.docker.internal para resolver o problema de forma elegante.
Neste artigo, você vai aprender:
- Como funciona, de verdade, o isolamento de rede dos contêineres, sem excesso de jargão
- A configuração correta no macOS, Windows e Linux
- Um checklist prático de diagnóstico para consultar quando o problema aparecer novamente
Por que localhost não funciona?
Resposta curta: o contêiner tem seu próprio ambiente de rede.
Parece abstrato? Pense no contêiner como uma casa independente, com seu próprio endereço, sua própria caixa de correio e tudo mais. Quando você chama localhost ou digita 127.0.0.1 dentro do contêiner, está procurando essa própria casa, não a máquina que está do lado de fora.
Na prática:
- No host,
localhostaponta para o próprio host - No contêiner,
localhostaponta para o próprio contêiner - São dois
localhostcompletamente diferentes
Também fiquei surpreso quando entendi isso pela primeira vez. O MySQL estava funcionando perfeitamente no meu computador; por que o contêiner não conseguia encontrá-lo? Porque ele procurava o MySQL dentro do próprio ambiente, onde o serviço não existia.
Como funciona o isolamento de rede do contêiner
O Docker cria um “namespace de rede” separado para cada contêiner. Não se assuste com o termo. Na prática, significa que cada contêiner tem sua própria interface de rede, seu próprio endereço IP e sua própria tabela de roteamento. É como sua casa e a casa do vizinho: mesmo no mesmo prédio, cada uma tem sua própria senha de Wi-Fi.
O contêiner e o host são conectados por uma ponte virtual chamada docker0. Em geral, o IP do contêiner se parece com 172.17.0.x, e o IP do host visto pelo contêiner costuma ser 172.17.0.1, o endereço do gateway da ponte.
Quando você acessa localhost dentro do contêiner, está acessando o 127.0.0.1 do contêiner, não o 127.0.0.1 do host. Por isso a conexão com o MySQL do host falha.
Veja mensagens de erro típicas:
Error: connect ECONNREFUSED 127.0.0.1:3306
Ou:
Can't connect to MySQL server on 'localhost' (111)
Esses erros são clássicos quando se tenta acessar um serviço do host usando localhost dentro do contêiner.
O que é host.docker.internal?
Se localhost não funciona, como o contêiner pode acessar o host?
O Docker oferece uma solução bastante prática: host.docker.internal. Esse domínio especial é resolvido para o endereço IP do host. Você pode entendê-lo como um “apelido” do host: não importa qual seja o IP real, esse nome leva até ele.
Por exemplo, se o MySQL estiver escutando na porta 3306 do host, use esta conexão dentro do contêiner:
mysql://user:[email protected]:3306/dbname
Você não precisa saber se o IP do host é 192.168.1.100 ou 10.0.0.5, nem se preocupar quando ele mudar após uma troca de rede. host.docker.internal apontará para o endereço correto.
Prático, não é?
Versões e plataformas compatíveis
Aqui existe uma diferença importante entre plataformas.
Usuários de macOS e Windows com Docker Desktop
Se você usa o Docker Desktop, a versão com interface gráfica, host.docker.internal tem suporte nativo desde a versão 18.03, lançada em março de 2018. Funciona imediatamente, sem configuração adicional.
Basta usar host.docker.internal no código:
const mysql = require('mysql2');
const connection = mysql.createConnection({
host: 'host.docker.internal', // Simples assim
port: 3306,
user: 'root',
password: 'your_password'
});
Usuários de Linux com Docker Engine
No Linux, a situação exige um passo extra. O Docker é executado diretamente no sistema, sem a máquina virtual intermediária usada no macOS e no Windows, por isso host.docker.internal não existe por padrão.
A boa notícia é que, desde o Docker Engine 20.10, lançado em dezembro de 2020, você pode ativá-lo manualmente. A próxima seção mostra como fazer isso.
Se sua versão do Docker for mais antiga, ainda há algumas alternativas:
- Usar
172.17.0.1, o IP do gateway da ponte padrão do Docker - Usar o IP real do host na rede Docker
- Usar
docker.for.mac.host.internal, somente em versões antigas do Docker para macOS
Como configurar nas três principais plataformas
Esta é a parte prática, com configurações prontas para copiar.
Configuração no macOS e Windows com Docker Desktop
Este é o cenário mais simples.
Método 1: usar diretamente no código
Não é necessária nenhuma configuração adicional. Basta usar host.docker.internal:
# docker-compose.yml
version: '3'
services:
app:
image: myapp:latest
environment:
- DB_HOST=host.docker.internal # Uso direto
- DB_PORT=3306
Método 2: declarar explicitamente, se quiser
Embora não seja obrigatório, você também pode adicionar extra_hosts para tornar a configuração explícita:
version: '3'
services:
app:
image: myapp:latest
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
- DB_HOST=host.docker.internal
host-gateway é uma sintaxe disponível no Docker 20.10+ e representa o endereço do gateway do host.
Se você inicia o contêiner com docker run:
docker run -d \
--add-host=host.docker.internal:host-gateway \
-e DB_HOST=host.docker.internal \
myapp:latest
Configuração no Linux com Docker Engine
No Linux, é necessário configurar o mapeamento manualmente.
Método 1: opção recomendada com host-gateway
Este é o método mais genérico e funciona em todas as plataformas com Docker 20.10+:
# docker-compose.yml
version: '3'
services:
app:
image: myapp:latest
extra_hosts:
- "host.docker.internal:host-gateway" # Configuração essencial
environment:
- DB_HOST=host.docker.internal
- DB_PORT=3306
Com docker run:
docker run -d \
--add-host=host.docker.internal:host-gateway \
-e DB_HOST=host.docker.internal \
myapp:latest
A principal vantagem é a compatibilidade entre plataformas: a mesma configuração funciona no macOS, Windows e Linux, sem ajustes específicos para cada sistema.
Método 2: usar o IP da ponte Docker como alternativa
Se host-gateway não estiver disponível por causa de uma versão antiga do Docker, use o endereço do gateway da ponte padrão:
version: '3'
services:
app:
image: myapp:latest
extra_hosts:
- "host.docker.internal:172.17.0.1" # Gateway padrão do Docker
environment:
- DB_HOST=host.docker.internal
172.17.0.1 é o gateway padrão da rede bridge do Docker. Na maioria dos casos esse IP está correto, a menos que você tenha alterado a configuração padrão de rede.
Método 3: última alternativa com o modo de rede host
Se nenhum dos métodos anteriores funcionar, existe uma opção mais radical:
docker run -d \
--network=host \
-e DB_HOST=localhost \ # Agora localhost pode ser usado
myapp:latest
Ou no Docker Compose:
version: '3'
services:
app:
image: myapp:latest
network_mode: "host" # Usa a rede do host
environment:
- DB_HOST=localhost # Agora localhost funciona diretamente
Vantagem desse método: é simples e direto. O contêiner usa a pilha de rede do host, então localhost é realmente o localhost do host.
Desvantagens desse método:
- Remove o isolamento de rede do contêiner
- O contêiner e o host compartilham portas, o que pode causar conflitos, por exemplo se ambos precisarem da porta 8080
- Funciona apenas no Linux; macOS e Windows não oferecem o mesmo suporte
- Não é recomendado em produção; use apenas para desenvolvimento e depuração local
Configuração multiplataforma recomendada
Se parte da equipe usa macOS e outra parte usa Linux, ou se o código precisa funcionar em ambientes diferentes, adote esta configuração:
# docker-compose.yml
version: '3'
services:
app:
image: myapp:latest
extra_hosts:
- "host.docker.internal:host-gateway" # Funciona em todas as plataformas
environment:
- DB_HOST=host.docker.internal
- DB_PORT=3306
- DB_USER=root
- DB_PASSWORD=your_password
Essa configuração funciona em todas as plataformas com Docker 20.10+, lançado no fim de 2020. Se você ainda usa uma versão anterior a 2020, sinceramente, já está na hora de atualizar.
Pontos importantes na configuração dos serviços do host
Configurar o contêiner é apenas metade do trabalho.
O serviço no host também precisa estar configurado corretamente. Caso contrário, a conexão continuará falhando. Esse detalhe costuma passar despercebido, por isso merece uma seção própria.
O serviço precisa escutar no endereço correto
Este é o problema mais comum.
Muitos serviços escutam apenas em 127.0.0.1 por padrão, aceitando conexões somente da própria máquina. Mas o contêiner Docker não é considerado parte desse localhost: a solicitação chega pela ponte de rede do Docker e acaba recusada.
Você precisa configurar o serviço para escutar em 0.0.0.0, ou seja, aceitar conexões em todas as interfaces de rede.
Configuração do MySQL
Localize o arquivo de configuração do MySQL. Normalmente ele fica em:
- Linux:
/etc/mysql/mysql.conf.d/mysqld.cnf - macOS com Homebrew:
/usr/local/etc/my.cnf - Windows:
C:\ProgramData\MySQL\MySQL Server 8.0\my.ini
Altere bind-address:
[mysqld]
# Antes, talvez estivesse assim
# bind-address = 127.0.0.1
# Altere para
bind-address = 0.0.0.0
Reinicie o MySQL:
# Linux
sudo systemctl restart mysql
# macOS
brew services restart mysql
# Windows
# Reinicie o serviço MySQL no Gerenciador de Serviços
Configuração do Redis
Edite redis.conf, normalmente localizado em /etc/redis/redis.conf ou /usr/local/etc/redis.conf:
# Localize esta linha
bind 127.0.0.1 -::1
# Altere para
bind 0.0.0.0
Reinicie o Redis:
# Linux
sudo systemctl restart redis
# macOS
brew services restart redis
Configuração do PostgreSQL
Edite postgresql.conf:
listen_addresses = '*' # Escuta em todos os endereços
Você também precisa editar pg_hba.conf para permitir o acesso da rede Docker:
# Adicione esta linha para permitir acesso da rede 172.17.0.0/16
host all all 172.17.0.0/16 md5
Configure as permissões do usuário no MySQL
Mesmo que o MySQL escute em 0.0.0.0, ainda existe a camada de permissões.
O MySQL administra permissões com base na combinação “usuário@host de origem”. Por exemplo, root@localhost e root@% são usuários diferentes.
Se o usuário do MySQL só puder acessar a partir de localhost, o contêiner continuará sem conexão. Conceda permissão para o usuário acessar a partir da rede Docker:
-- Opção 1: permitir acesso de qualquer host, simples, mas menos seguro
GRANT ALL PRIVILEGES ON *.* TO 'your_user'@'%' IDENTIFIED BY 'your_password';
-- Opção 2: permitir apenas a rede Docker, mais seguro
GRANT ALL PRIVILEGES ON *.* TO 'your_user'@'172.17.0.%' IDENTIFIED BY 'your_password';
-- Atualizar as permissões
FLUSH PRIVILEGES;
No MySQL 8.0+, a sintaxe é um pouco diferente:
-- Primeiro, crie o usuário
CREATE USER 'your_user'@'%' IDENTIFIED BY 'your_password';
-- Depois, conceda as permissões
GRANT ALL PRIVILEGES ON *.* TO 'your_user'@'%';
FLUSH PRIVILEGES;
Configure o firewall
Em alguns sistemas, o firewall pode bloquear o acesso do contêiner Docker aos serviços do host.
Verifique o estado do firewall:
# Linux (ufw)
sudo ufw status
# Linux (firewalld)
sudo firewall-cmd --state
Permita o acesso da rede Docker, usando a porta 3306 do MySQL como exemplo:
# 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
Recomendações de segurança
Escutar em 0.0.0.0 tem riscos: o serviço fica exposto a outras máquinas da rede.
Em produção:
-
Escute apenas em uma interface específica: se você souber qual interface o Docker usa, limite o serviço a ela.
bind-address = 172.17.0.1 -
Combine com regras de firewall: permita somente a rede Docker e bloqueie as demais origens.
-
Use um contêiner dedicado para o banco de dados: em vez de executar o banco no host, inicie-o com o Docker Compose. Assim, a aplicação e o banco ficam na mesma rede, com mais isolamento.
No ambiente local de desenvolvimento:
Na prática, escutar em 0.0.0.0 costuma ser aceitável no desenvolvimento local. Seu computador não é um servidor e normalmente não está acessível pela internet. Não é preciso entrar em pânico, mas continue atento à rede em que você está conectado.
Checklist de diagnóstico para problemas comuns
A conexão falhou? Não se preocupe. Siga este checklist passo a passo.
Problema 1: Connection refused, ou conexão recusada
Este é o erro mais comum. A mensagem se parece com:
Error: connect ECONNREFUSED host.docker.internal:3306
Ou:
Can't connect to MySQL server on 'host.docker.internal' (111)
Possíveis causas e diagnóstico:
Etapa 1: confirme que o serviço está em execução no host
Execute no host:
# Verificar o MySQL
sudo systemctl status mysql # Linux
brew services list # macOS
# Verificar se a porta está sendo escutada
netstat -an | grep 3306
# Ou
lsof -i :3306
Se o serviço estiver parado, inicie-o primeiro.
Etapa 2: verifique o endereço de escuta do serviço
No host:
# Ver em qual endereço o MySQL está escutando
sudo netstat -tlnp | grep 3306
A saída deve se parecer com:
tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN 1234/mysqld
Observe a terceira coluna. Se ela mostrar 0.0.0.0:3306, o serviço está escutando em todos os endereços. Se mostrar 127.0.0.1:3306, você encontrou o problema: o serviço aceita apenas conexões locais e o contêiner não consegue acessá-lo.
Para corrigir, siga a seção anterior e altere bind-address para 0.0.0.0.
Etapa 3: verifique o firewall
Desative o firewall temporariamente para testar:
# Linux (ufw)
sudo ufw disable
# Linux (firewalld)
sudo systemctl stop firewalld
# macOS
# Ajustes do Sistema -> Privacidade e Segurança -> Firewall -> Desativar
Se a conexão funcionar com o firewall desativado, o problema está nas regras. Configure as permissões mostradas anteriormente e reative o firewall.
Problema 2: Connection timeout, ou tempo limite de conexão
Mensagem de erro:
Error: connect ETIMEDOUT host.docker.internal:3306
Um timeout costuma ser mais difícil de diagnosticar do que uma recusa: o pacote foi enviado, mas não recebeu resposta.
Possíveis causas e diagnóstico:
Etapa 1: verifique se host.docker.internal pode ser resolvido
Execute dentro do contêiner:
# Entrar no contêiner
docker exec -it your_container sh
# Testar com ping
ping host.docker.internal
Se o ping falhar ou retornar “unknown host”, host.docker.internal não foi configurado corretamente.
Atenção, usuários de Linux: confirme que o docker-compose.yml ou o comando docker run contém --add-host=host.docker.internal:host-gateway.
Etapa 2: confirme o número da porta
Tem certeza de que a porta é 3306? O MySQL pode ter sido configurado para outra porta.
Confirme no host:
# Verificar a porta real do MySQL
sudo netstat -tlnp | grep mysqld
Etapa 3: teste a conectividade entre o contêiner e o host
Execute no contêiner:
# Testar se a porta está acessível
telnet host.docker.internal 3306
# Se o contêiner não tiver telnet, use nc
nc -zv host.docker.internal 3306
Se a porta não estiver acessível, verifique novamente o firewall e a configuração do serviço.
Problema 3: Unknown host, ou falha ao resolver host.docker.internal
Mensagem de erro:
getaddrinfo ENOTFOUND host.docker.internal
Esse erro indica falha de resolução DNS: o contêiner não reconhece o domínio host.docker.internal.
Solução:
Adicione extra_hosts à configuração do contêiner:
services:
app:
extra_hosts:
- "host.docker.internal:host-gateway"
Ou adicione a opção ao executar docker run:
docker run --add-host=host.docker.internal:host-gateway ...
Problema 4: falha de autenticação, ou Access denied
Mensagem de erro:
Access denied for user 'root'@'172.17.0.2' (using password: YES)
Isso significa que o contêiner alcançou o MySQL, mas as permissões do usuário estão incorretas.
Solução:
Conceda acesso ao usuário do MySQL:
-- Verificar as permissões atuais do usuário
SELECT user, host FROM mysql.user WHERE user='root';
-- Se existir apenas root@localhost, crie root@% ou [email protected].%
CREATE USER 'root'@'%' IDENTIFIED BY 'your_password';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%';
FLUSH PRIVILEGES;
Problema 5: configuração diferente entre plataformas
A equipe usa o mesmo docker-compose.yml, mas ele funciona no macOS e falha no Linux.
Solução:
Padronize a opção host-gateway, que funciona em todas as plataformas:
services:
app:
extra_hosts:
- "host.docker.internal:host-gateway"
Confirme que todos usam Docker 20.10 ou posterior. Se alguém ainda usa uma versão antiga, peça para atualizar.
Sequência rápida de diagnóstico
Quando houver um problema de conexão, verifique nesta ordem:
- O serviço está em execução? →
systemctl status/brew services list - Está escutando no endereço correto? → use
netstat -tlnpe veja se aparece0.0.0.0ou127.0.0.1 - O contêiner está configurado? → verifique
extra_hostsou--add-host - O DNS funciona? → execute
ping host.docker.internalno contêiner - A porta está acessível? → teste com
telnetouncno contêiner - O firewall está bloqueando? → desative-o temporariamente para testar
- O usuário tem permissão? → no MySQL, verifique se ele é
@localhostou@%
Na maioria dos casos, o problema estará em uma das três primeiras etapas.
Exemplos práticos
Agora que a teoria está clara, veja alguns casos reais.
Caso 1: aplicação Spring Boot conectando ao MySQL do host
Cenário: você tem um projeto Spring Boot, quer executá-lo com Docker e conectar ao banco de dados MySQL local.
Etapa 1: configure o Spring Boot
Em application.yml:
spring:
datasource:
# Use host.docker.internal para conectar ao MySQL do host
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
Etapa 2: configure o Docker Compose
Em docker-compose.yml:
version: '3.8'
services:
app:
build: .
ports:
- "8080:8080"
extra_hosts:
- "host.docker.internal:host-gateway" # Configuração essencial
environment:
# Também é possível substituir os valores por variáveis de ambiente
SPRING_DATASOURCE_URL: jdbc:mysql://host.docker.internal:3306/mydb
SPRING_DATASOURCE_USERNAME: root
SPRING_DATASOURCE_PASSWORD: your_password
Etapa 3: configure o MySQL no host
Edite /etc/mysql/mysql.conf.d/mysqld.cnf:
[mysqld]
bind-address = 0.0.0.0
Reinicie o MySQL:
sudo systemctl restart mysql
Conceda permissão ao usuário:
CREATE USER 'root'@'%' IDENTIFIED BY 'your_password';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%';
FLUSH PRIVILEGES;
Etapa 4: inicie e teste
docker-compose up --build
Se aparecer uma mensagem como HikariPool-1 - Start completed, a conexão com o banco de dados foi bem-sucedida.
Registro do diagnóstico:
Na primeira vez que fiz essa configuração, recebi Connection refused. O processo foi este:
- Verifiquei se o MySQL estava em execução com
systemctl status mysql→ estava - Verifiquei o endereço de escuta com
netstat -tlnp | grep 3306→ encontrei127.0.0.1:3306 - Alterei
bind-addresspara0.0.0.0no arquivo de configuração e reiniciei o MySQL - Executei novamente e a conexão funcionou
Caso 2: aplicação Node.js conectando ao Redis do host
Cenário: um projeto Node.js usa Redis como cache e, no desenvolvimento local, o Redis é executado no host.
Etapa 1: código 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,
// Se o Redis tiver senha configurada
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;
Etapa 2: configuração do Docker Compose
Em 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
Etapa 3: configure o Redis no host
Edite /etc/redis/redis.conf ou /usr/local/etc/redis.conf:
# Localize a linha bind
bind 127.0.0.1 ::1
# Altere para
bind 0.0.0.0
Se o Redis tiver protected-mode yes, altere também:
protected-mode no # Aceitável no desenvolvimento local; não faça isso em produção
Reinicie o Redis:
# Linux
sudo systemctl restart redis
# macOS
brew services restart redis
Etapa 4: valide
Inicie a aplicação:
docker-compose up
Ao ver Redis connected successfully, a conexão está funcionando.
Tratamento multiplataforma:
Se a equipe usa macOS e Linux, padronize com uma variável de ambiente:
const REDIS_HOST = process.env.REDIS_HOST || (
process.platform === 'linux' ? 'host.docker.internal' : 'host.docker.internal'
);
Pensando bem, hoje todas as plataformas podem usar host.docker.internal, sem diferenciação. Basta adicionar extra_hosts: ["host.docker.internal:host-gateway"] ao Docker Compose para que macOS e Linux compartilhem a mesma configuração.
Caso 3: configuração completa do ambiente de desenvolvimento
Este é um modelo prático em que o contêiner da aplicação se conecta ao MySQL e ao Redis do host:
# docker-compose.yml
version: '3.8'
services:
app:
build: .
ports:
- "8080:8080"
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
# Configuração do banco de dados
DB_HOST: host.docker.internal
DB_PORT: 3306
DB_NAME: myapp
DB_USER: root
DB_PASSWORD: your_password
# Configuração do Redis
REDIS_HOST: host.docker.internal
REDIS_PORT: 6379
# Configuração da aplicação
NODE_ENV: development
PORT: 8080
volumes:
- .:/app
- /app/node_modules # Não montar node_modules a partir do host
command: npm run dev # Hot reload no modo de desenvolvimento
Checklist correspondente para o host:
# MySQL
# Edite /etc/mysql/mysql.conf.d/mysqld.cnf
bind-address = 0.0.0.0
# Reinicie: sudo systemctl restart mysql
# Redis
# Edite /etc/redis/redis.conf
bind 0.0.0.0
protected-mode no
# Reinicie: sudo systemctl restart redis
# Firewall, se necessário
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
Essa configuração funciona no macOS e no Linux e pode ser reutilizada como ponto de partida.
Resumo
Depois de tudo isso, os três pontos essenciais são:
1. Entenda o princípio
O contêiner tem seu próprio ambiente de rede. Dentro dele, localhost aponta para o próprio contêiner, não para o host. Isso faz parte do isolamento por namespace de rede do Docker; não é um bug.
2. Escolha o método adequado
Use a opção apropriada para seu ambiente:
| Ambiente | Opção recomendada | Configuração |
|---|---|---|
| macOS/Windows com Docker Desktop | Usar host.docker.internal diretamente | Nenhuma configuração adicional |
| Linux com Docker Engine 20.10+ | extra_hosts: host-gateway | Docker Compose ou —add-host |
| Equipe multiplataforma | extra_hosts: host-gateway | Uma configuração para todas as plataformas |
| Versão antiga do Docker no Linux | Usar 172.17.0.1 | Definir o IP em extra_hosts |
| Se nada mais funcionar | --network=host | Apenas para desenvolvimento local; remove o isolamento |
3. Configure também o serviço
Configurar o contêiner não basta. O serviço no host também precisa estar preparado:
- Altere o endereço de escuta para
0.0.0.0 - Conceda ao usuário do MySQL acesso a partir da rede Docker
- Permita o acesso da rede Docker no firewall
Árvore rápida de decisão
Quando a conexão falhar:
Não consegue acessar o serviço do host?
↓
Você usa macOS/Windows ou Linux?
↓
macOS/Windows:
→ Use host.docker.internal diretamente
→ Se ainda falhar, verifique a configuração do serviço no host
Linux:
→ A versão do Docker é ≥20.10?
Sim → Use extra_hosts: host-gateway
Não → Use extra_hosts: 172.17.0.1
→ Verifique a configuração do serviço no host
→ Verifique o firewall
Ainda não funciona?
→ Siga cada item do checklist de diagnóstico
→ Última alternativa: --network=host, somente para desenvolvimento local
Para finalizar
Desenvolver com contêineres é muito prático, mas a parte de rede tem algumas armadilhas. Depois que você entende host.docker.internal e host-gateway, porém, consegue resolver a maioria desses problemas.
Salve este artigo para consultar quando uma conexão falhar novamente. Se alguém da sua equipe estiver enfrentando a mesma dificuldade, compartilhe este guia.
E se você já encontrou algum problema estranho de rede no Docker ou conhece uma solução melhor, conte nos comentários. Sua experiência pode ajudar outras pessoas.
Processo completo para acessar o host a partir de um contêiner Docker
Use host.docker.internal para acessar serviços do host a partir de contêineres no macOS, Windows e Linux.
⏱️ Estimated time: 15 min
- 1
Step 1: Entenda a origem do problema e a solução
Origem do problema: usar localhost ou 127.0.0.1 dentro do contêiner para conectar a um serviço do host sempre falha, porque localhost aponta para o próprio contêiner. É preciso uma configuração específica para acessar os serviços do host.
Solução: use o domínio especial host.docker.internal, que é resolvido automaticamente para o endereço IP do host.
Suporte por plataforma:
• macOS/Windows: suporte nativo no Docker Desktop, sem configuração adicional
• Linux: requer Docker 20.10+ e o parâmetro --add-host ou uma configuração no Docker Compose - 2
Step 2: Configure no macOS e no Windows
Etapas no macOS e no Windows:
1. Use host.docker.internal diretamente:
docker run -e DATABASE_URL=host.docker.internal:3306 my-app
2. Substitua localhost na configuração da aplicação:
• String de conexão: host.docker.internal:3306
• Variável de ambiente: DATABASE_HOST=host.docker.internal
3. Valide a conexão:
• Teste dentro do contêiner: docker exec -it container-name ping host.docker.internal
• Teste a conexão da aplicação diretamente
Observação: macOS e Windows não exigem configuração adicional; o Docker Desktop cuida disso automaticamente. - 3
Step 3: Configure e diagnostique no Linux
Métodos de configuração no Linux:
1. Docker versão ≥20.10 (recomendado):
docker run --add-host=host.docker.internal:host-gateway my-app
Ou, no docker-compose.yml:
extra_hosts:
- "host.docker.internal:host-gateway"
2. Docker versão <20.10:
docker run --add-host=host.docker.internal:172.17.0.1 my-app
3. Checklist completo de diagnóstico:
• Confirme que o serviço está em execução no host (netstat -tuln | grep 3306)
• Verifique se a porta está aberta (telnet host.docker.internal 3306)
• Use host.docker.internal no lugar de localhost
• No Linux, adicione o parâmetro --add-host
• Verifique as regras do firewall (iptables -L)
• Confirme que o serviço escuta em 0.0.0.0, e não em 127.0.0.1
FAQ
Por que localhost não conecta o contêiner a um serviço do host?
É como duas casas independentes: embora estejam na mesma máquina física, cada uma tem seu próprio endereço de rede. Ao acessar localhost, o contêiner procura dentro da própria rede, não na rede do host.
A solução é usar o domínio especial host.docker.internal, que é resolvido automaticamente para o endereço IP do host e permite que o contêiner acesse os serviços executados nele.
host.docker.internal funciona em todas as plataformas?
• macOS/Windows (Docker Desktop): suporte nativo, sem configuração
• Linux (Docker 20.10+): requer configuração manual com --add-host
• Linux (Docker <20.10): requer o IP 172.17.0.1 como endereço do host
Para equipes multiplataforma, recomenda-se padronizar extra_hosts no Docker Compose, para que a mesma configuração funcione em todos os sistemas.
O que fazer se host.docker.internal estiver configurado, mas a conexão ainda falhar?
1. Verifique se o serviço está em execução no host:
netstat -tuln | grep número_da_porta
2. Confirme o endereço em que o serviço está escutando:
O serviço precisa escutar em 0.0.0.0, não apenas em 127.0.0.1
3. Teste a conectividade da rede:
docker exec -it container-name ping host.docker.internal
docker exec -it container-name telnet host.docker.internal número_da_porta
4. Verifique as regras do firewall:
iptables -L (Linux)
Configurações do Firewall do Windows
5. Última alternativa, somente para desenvolvimento:
--network=host (remove o isolamento de rede do contêiner)
Devo usar host.docker.internal em produção?
• Nomes de serviço na rede do Docker Compose ou nomes de contêiner
• Endereços IP explícitos
• Mecanismos de descoberta de serviços, como Consul ou etcd
host.docker.internal é indicado principalmente para:
• Ambientes locais de desenvolvimento
• Depuração e testes
• Acesso a ferramentas de desenvolvimento executadas no host, como bancos de dados e Redis
Usar host.docker.internal em produção pode:
• Criar dependência da configuração de rede do host
• Reduzir as vantagens da conteinerização
• Aumentar a complexidade operacional
17 min de leitura · Publicado em: 17 dez 2025 · Atualizado em: 4 set 2026
Guia prático Docker
Se você chegou pela busca, o caminho mais rápido é ir para o post anterior ou próximo desta série.
Anterior
Mapeamento de portas no Docker: não deixe a mensagem port is already allocated acabar com sua sexta-feira à noite
Do diagnóstico de portas ocupadas à otimização de desempenho, resolva de forma sistemática os principais problemas de mapeamento de portas no Docker e livre-se do erro port already allocated
Parte 20 de 34
Próximo
Guia de mirrors do Docker na China em 2026: resolva o timeout no pull em 5 minutos
Como avaliar os mirrors do Docker disponíveis na China em 2026: configure o daemon.json, teste a velocidade, trate proxies corporativos e pull-through cache e diferencie o limite do Docker Hub (429) de uma falha no mirror para diagnosticar um timeout no docker pull em 5 minutos.
Parte 22 de 34



Comentários
Entre com GitHub para comentar