Alcançar uma interface web dentro de um contêiner VPN: escolha o dono da porta
O aplicativo compartilha o espaço de nomes da VPN, então a porta pertence ao contêiner VPN. Vincule o ouvinte corretamente, publique no dono e mantenha o caminho estreito.
Nada está errado com o aplicativo e nada está errado com o túnel, e mesmo assim o painel não carrega. Quando um serviço roda com network_mode: service:vpn, ele compartilha o espaço de nomes de rede do contêiner VPN, o que significa que seu ouvinte e suas portas publicadas pertencem a esse espaço de nomes e não ao serviço. Três decisões decorrem disso: onde o aplicativo se vincula, qual contêiner publica a porta e quão estreito é o caminho de gestão. Coloque-as na ordem errada e cada configuração isolada parecerá correta, enquanto a combinação não pode funcionar.
Quem possui o espaço de nomes da porta
Em um espaço de nomes compartilhado, adicionar uma entrada ports: ao serviço dependente não faz nada útil, e várias opções de rede não são suportadas para ele por projeto. Publique, em vez disso, no contêiner que possui o espaço de nomes. Esse contêiner é também aquele cujo endereço aparece no host, então o mapeamento é lido como uma entrada e não uma por serviço.
services:
vpn:
image: vpn-client-image
cap_add: [NET_ADMIN]
ports:
- "127.0.0.1:8080:8080"
app:
network_mode: "service:vpn"
Observe o endereço à esquerda do mapeamento. Vincular a 127.0.0.1 mantém a porta publicada no loopback do host, que costuma ser o que uma interface de gestão quer. Vincular a 0.0.0.0 a expõe em todas as interfaces do host, e isso é uma decisão de segurança diferente, não uma conveniência.
Faça o aplicativo escutar onde o espaço de nomes espera
Um ouvinte vinculado a 127.0.0.1 dentro do espaço de nomes só é acessível de dentro desse espaço. As portas publicadas do host chegam de fora, então o aplicativo precisa vincular um endereço mais amplo para que o mapeamento funcione. Isso é uma mudança de uma linha na maioria dos servidores, e é exatamente o passo que as pessoas pulam depois de copiar um guia de endurecimento escrito para uma implantação sem contêineres.
docker compose exec app ss -lntp
docker port vpn
curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080/
A lista de ouvintes dentro do aplicativo diz a verdade sobre o endereço de vínculo, e docker port diz o que o dono realmente publicou. Se o primeiro mostra 127.0.0.1 e o segundo mostra um mapeamento no host, você encontrou a incompatibilidade sem tocar na configuração da VPN.
Escolha como o caminho de gestão entra
Existem três arranjos razoáveis. Publique no contêiner VPN e alcance-o a partir do host ou da rede local. Coloque um proxy reverso à frente do espaço de nomes e dê ao proxy a única porta exposta. Ou mantenha o painel acessível apenas de dentro do espaço de nomes por meio de uma sessão exec ou de um túnel SSH, que é a menor exposição e o menor conforto.
Qual se encaixa depende de quem precisa da interface e de onde. Um único administrador no mesmo host fica bem servido por um vínculo de loopback. Uma equipe que a alcança pela VPN precisa de um caminho deliberado e de um dono nomeado. Escolher a opção de proxy dá TLS e registros de acesso, ao custo de mais um componente para manter atualizado.
Abra a porta de gestão sem abrir tudo
A própria política de acesso local ou de bloqueio do cliente VPN pode descartar uma solicitação de gestão de entrada mesmo enquanto o túnel de saída funciona perfeitamente. Permita uma exceção documentada para a origem e a porta previstas, e depois confirme que a proteção comum do túnel continua igual. Desativar o kill switch para fazer um painel carregar troca um controle real por uma aba do navegador.
Deixe a autenticação do próprio aplicativo ativada. Estar dentro de uma pilha conectada à VPN não autoriza cada usuário local nem cada dispositivo que consiga alcançar o host, e um painel de administração sem autenticação atrás de um túnel continua sendo um painel sem autenticação.
Verifique a partir do dispositivo de gestão e verifique novamente mais tarde
Teste a partir da máquina que realmente gerenciará o serviço, não do host, e depois verifique separadamente o caminho de internet exigido pelo aplicativo. Um sucesso de gestão prova uma direção e não diz nada sobre a saída.
Teste novamente depois que a pilha for recriada. Um dono de rede substituído muda o espaço de nomes ao qual o aplicativo se conecta, e uma URL que funcionava antes de uma atualização pode não apontar para nada depois. Anote o mapeamento publicado e o endereço de vínculo para que a próxima reconstrução seja uma verificação de dois minutos em vez de uma investigação repetida.