Resposta curta: não é possível. O Docker não tem uma maneira suportada de adicionar uma porta publicada a um contêiner já em execução. Os mapeamentos de porta são fixados na criação do contêiner, e nem docker run nem docker container update podem alterá-los depois. A flag --publish-add existe apenas para serviços Swarm, não para contêineres independentes.
Se você não puder reiniciar o contêiner, estas são as opções que realmente funcionam:
| Abordagem | Adiciona um mapeamento de porta real do Docker? | Funciona no Docker Desktop (macOS/Windows)? | Sobrevive à reinicialização? |
|---|---|---|---|
Contêiner sidecar socat |
Não (encaminhamento TCP) | Sim | Sim, se o sidecar reiniciar |
| Proxy reverso (Nginx/Traefik/HAProxy) | Não (proxied) | Sim | Sim |
DNAT com iptables no host |
Não (regra NAT do host) | Não, apenas Linux nativo | Não, a menos que persistido |
Recriar o contêiner com -p |
Sim | Sim | Sim |
A única abordagem que produz uma porta publicada genuinamente gerenciada pelo Docker — que aparece em docker ps e docker port — é recriar o contêiner. Todo o resto encaminha o tráfego em uma camada acima ou abaixo da contabilidade de portas do Docker. Escolha com base se você pode tolerar uma reinicialização e leia as ressalvas abaixo antes de executar qualquer coisa em produção.
Este artigo explica cada método, os comandos exatos e onde cada um falha.
Contexto: como funciona o mapeamento de portas no Docker
Princípios fundamentais do mapeamento de portas de contêiner
No Docker, a conexão entre a porta interna de um contêiner e a porta da máquina host é facilitada através do mapeamento de portas. Normalmente, especificamos os mapeamentos de porta usando os parâmetros -p ou --publish ao iniciar um contêiner, conforme ilustrado abaixo:
docker run -d -p 8080:80 nginx
O comando acima mapeia a porta 8080 na máquina host para a porta 80 dentro do contêiner. Como resultado, usuários externos podem acessar o serviço web em execução no contêiner através da porta 8080 do host.
Por que o Docker não permite isso
Uma vez que um contêiner foi iniciado, o Docker geralmente não suporta adicionar novos mapeamentos de porta dinamicamente. Em outras palavras, os mapeamentos de porta iniciais permanecem fixos durante todo o ciclo de vida do contêiner. Se você precisar adicionar mais mapeamentos de porta, a abordagem tradicional envolve parar e reiniciar o contêiner, o que pode interromper os serviços e é inaceitável em ambientes de produção.
As quatro soluções alternativas
Para adicionar dinamicamente mapeamentos de porta a um contêiner em execução, vários métodos podem ser empregados:
2.1 Contêiner sidecar que encaminha a porta (recomendado)
Um contêiner separado publica a nova porta do host e encaminha o tráfego para o contêiner original através de uma rede Docker compartilhada. Esta é a opção mais segura porque o contêiner original nunca é tocado.
Uma correção importante primeiro: você não pode combinar --network container:<name> com -p. A documentação de rede do Docker afirma que --publish, --publish-all e --expose não são suportados para contêineres usando o modo de rede container:, porque tal contêiner não tem seu próprio namespace de rede para mapear portas. Qualquer guia que diga para executar docker run -p 8081:81 --net container:your-container ... está errada, e o Docker a rejeitará.
O padrão funcional usa uma rede definida pelo usuário para que o sidecar possa alcançar o destino pelo nome do contêiner:
# 1. Crie uma rede e anexe o contêiner em execução a ela (sem necessidade de reinicialização)
docker network create app-net
docker network connect app-net your-container
# 2. Inicie um sidecar socat que publica 8081 e encaminha para a porta 81 do destino
docker run -d --name port-sidecar \
--network app-net \
--restart unless-stopped \
-p 8081:81 \
alpine/socat \
TCP-LISTEN:81,fork,reuseaddr TCP:your-container:81
Observe que docker network connect funciona em um contêiner em execução, então o passo 1 não causa tempo de inatividade. O sidecar escuta na porta 81 dentro de seu próprio namespace, e -p 8081:81 publica isso para o host.
Ressalvas:
- Isso é um encaminhamento TCP, não um mapeamento de porta Docker. Não aparecerá em
docker port your-container. alpine/socatencaminha apenas TCP. Para UDP, useUDP-LISTEN/UDP, e para HTTP com roteamento baseado em host, prefira Nginx, Traefik, Caddy ou HAProxy.- Adicione
--restart unless-stopped(como acima) ou o encaminhamento desaparecerá na reinicialização. - O salto extra custa uma pequena quantidade de latência e adiciona mais um processo para monitorar.
2.2 Regra DNAT com iptables no host (apenas Linux nativo)
Em um host Linux nativo, você pode adicionar uma regra DNAT que encaminha uma porta do host para o IP interno do contêiner:
# Obter o IP do contêiner
CONTAINER_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' your-container)
# Encaminhar a porta do host 8081 para a porta 81 do contêiner
sudo iptables -t nat -A DOCKER -p tcp --dport 8081 \
-j DNAT --to-destination "${CONTAINER_IP}:81"
Isso oferece controle refinado, mas carrega o maior risco operacional de qualquer método aqui:
- Docker Desktop no macOS e Windows não funcionará dessa forma. Os contêineres são executados dentro de uma VM Linux, então regras
iptablesna sua máquina não tocam no caminho de rede do Docker. Este método é apenas para Linux nativo. - As regras não persistem. Elas são perdidas na reinicialização, recarga do firewall ou transição nftables/iptables. Use o mecanismo de persistência de firewall da sua distribuição se precisar que elas sobrevivam.
- O Docker é dono da cadeia
DOCKER. O Docker cria e gerencia essas regras a partir da configuração de porta dos contêineres em execução, e sua documentação diz que você não deve modificar as regras que o Docker cria. Para filtragem personalizada, o Docker designaDOCKER-USERcomo o espaço reservado para regras definidas pelo usuário, porque regras anexadas aFORWARDsão processadas após as próprias do Docker. - Os IPs dos contêineres não são estáveis. O endereço muda sempre que o contêiner é recriado, deixando uma regra obsoleta que encaminha silenciosamente para lugar nenhum.
- Ignora a contabilidade do Docker. A porta não aparecerá em
docker psoudocker port.
2.3 Executando socat diretamente no host
Você também pode executar socat como um processo host simples, em vez de dentro de um contêiner:
socat TCP-LISTEN:8081,fork,reuseaddr TCP:<container_ip>:81
Isso funciona no Linux nativo, onde o IP do contêiner é roteável a partir do host. No Docker Desktop para macOS e Windows, o IP do contêiner não é acessível a partir da sua máquina, então use o sidecar na seção 2.1. De qualquer forma, você precisa de um supervisor de processo (systemd, ou --restart no sidecar) para sobreviver a reinicializações, já que um processo socat simples morre com seu shell.
2.4 Recriar o serviço com Docker Compose
Este é o único método que produz uma porta publicada real e gerenciada pelo Docker. Adicione o mapeamento ao compose.yaml:
services:
app:
image: your-image:tag
ports:
- "8081:81"
Em seguida, recrie apenas esse serviço:
docker compose up -d app
O Compose recria o contêiner, então há uma breve interrupção — isso não é uma alteração ao vivo. Observe que o Docker moderno usa docker compose (um subcomando), não o binário docker-compose mais antigo e independente. Mantenha o estado em volumes nomeados ou bind mounts para que sobreviva à recriação.
2.5 Editando os arquivos de configuração internos do Docker (não recomendado)
Você encontrará conselhos para editar manualmente /var/lib/docker/containers/<id>/config.v2.json e hostconfig.json para adicionar uma entrada PortBindings e depois reiniciar o daemon. Às vezes funciona, mas trate isso como último recurso:
- Estes são arquivos de implementação internos sem garantias de estabilidade, não uma API suportada. O formato pode mudar entre versões do Docker.
- O daemon mantém o estado do contêiner na memória. Editar arquivos sob um daemon em execução corre o risco de suas alterações serem sobrescritas, e edições parciais podem deixar o estado de rede do contêiner inconsistente com seus metadados.
- Você deve parar o daemon antes de editar, o que afeta todos os contêineres no host.
- Se
live-restoreestiver habilitado, os contêineres continuam em execução durante uma reinicialização do daemon — mas isso não aplica um mapeamento de porta editado. Live-restore não altera a regra de que uma nova porta publicada requer a recriação do contêiner.
Se você chegou ao ponto de editar o estado do daemon manualmente, recriar o contêiner com a flag -p correta é mais rápido e seguro.
Conclusão
O Docker não suporta adicionar uma porta publicada a um contêiner em execução, e nenhuma solução alternativa muda isso. O que os métodos acima fornecem é uma maneira de rotear novo tráfego para um contêiner que você não pode reiniciar.
Escolha nesta ordem:
- Você pode tolerar uma reinicialização curta? Recrie o contêiner com a flag
-pcorreta, ou adicioneports:aocompose.yamle executedocker compose up -d. Este é o único método que produz um mapeamento de porta real do Docker. - Não pode reiniciar? Use o sidecar
socatna seção 2.1, ou um proxy reverso se precisar de roteamento HTTP, TLS ou verificações de saúde. - Linux nativo e precisa de um encaminhamento temporário rápido? Uma regra DNAT com
iptablesfunciona, mas persista-a deliberadamente e espere que o Docker interfira com suas próprias cadeias. - Evite editar manualmente os arquivos de configuração do daemon.
Se os mapeamentos de porta mudam com frequência, isso geralmente é um sinal de design: coloque um proxy reverso na frente do serviço desde o início e deixe que ele possua as portas voltadas para o host, para que o ciclo de vida do contêiner e o roteamento permaneçam independentes.
Fontes: Docker: Publicando portas, Docker: Modos de rede de contêiner, Docker: Filtragem de pacotes e firewalls, Docker e iptables, docker container port.
Você pode visitar Novita AI para instâncias de GPU e APIs de modelo.
