OpenVPN + SSH Proxy — O Problema e a Solução

OpenVPN + SSH Proxy — O Problema e a Solução

Todo desenvolvedor que trabalha com múltiplos clientes ou em ambientes corporativos conhece bem essa situação: você precisa acessar um banco de dados, um servidor interno, uma API privada — e para isso tem que conectar em uma VPN. Simples assim. O problema começa quando você tem dois clientes ao mesmo tempo, ou quando a VPN do trabalho briga com a VPN do cliente, ou quando o cliente OpenVPN resolve reescrever todas as suas rotas e você perde a internet enquanto está conectado.

Este post é o primeiro de uma série de três partes sobre o projeto openvpn-ssh-proxy. Aqui eu explico o problema e a ideia central da solução. Nas próximas partes entro na implementação e nas decisões de segurança.


O problema real com clientes VPN

Vou ser direto: clientes OpenVPN instalados direto no host são uma bagunça gerenciada.

Primeiro, eles são pesados. Muitos vêm junto com um cliente gráfico cheio de funcionalidades que você nunca vai usar, que inicia junto com o sistema, que fica lá consumindo recursos em background. Segundo, eles mexem na tabela de roteamento do sistema operacional. Quando você conecta, é comum ver o gateway padrão sendo substituído pela interface da VPN — o que significa que todo o seu tráfego passa pelo túnel, incluindo aquele streaming que você estava assistindo em outra janela. Alguns clientes permitem configurar split tunneling para mitigar isso, mas nem sempre funciona direito, e depende da configuração do servidor.

O problema que me incomodava de verdade, porém, era outro: você só consegue conectar em uma VPN por vez. Ou melhor, tecnicamente dá para conectar em mais de uma, mas as rotas entram em conflito e as coisas param de funcionar. Para quem trabalha com mais de um cliente simultâneo, isso significa ficar desconectando e reconectando o dia todo — ou manter duas máquinas separadas só para isso.

Tem ainda o fator portabilidade. Se você tem uma configuração de VPN funcionando no seu Linux, ela não necessariamente vai funcionar igual no Mac do colega ou no Windows da máquina da empresa. E se você precisar reconfigurar o host por qualquer motivo, vai ter que refazer tudo.


A ideia: isolar o problema

A solução que encontrei parte de uma premissa simples: se o problema está no cliente OpenVPN afetando o host, então o cliente OpenVPN não deve rodar no host.

A ideia é colocar o cliente OpenVPN dentro de um container Docker. O container se conecta à VPN, acessa a rede privada normalmente, e expõe para o host apenas um servidor SSH. O host, então, usa esse SSH para criar um proxy SOCKS ou encaminhar portas específicas — acessando os recursos privados sem nunca ter instalado um cliente VPN, sem ter tocado na tabela de roteamento local, e sem saber absolutamente nada sobre a VPN em si.


Como fica a arquitetura

O fluxo completo é assim:

+-------------------+       SSH tunnel       +--------------------------------+
|                   |  <------------------->  |         Docker Container       |
|   Seu Host        |                         |                                |
|   (qualquer OS)   |   porta local (ex 2222) |  [OpenVPN client] [SSH server] |
|                   |                         |         |                      |
+-------------------+                         |         | túnel VPN            |
        |                                     |         v                      |
        | SOCKS proxy / port forward          |  +-------------+               |
        v                                     |  | Rede privada |              |
  banco de dados,                             |  | do cliente   |              |
  APIs internas,                              |  +-------------+               |
  servidores web...                           +--------------------------------+

O host se conecta ao container via SSH na porta que você configurar. A partir daí, você pode:

  • Criar um proxy SOCKS e configurar seu browser ou cliente de banco de dados para rotear através dele
  • Fazer port forwarding de portas específicas — por exemplo, mapear a porta 5432 local para o PostgreSQL interno da rede privada

O container, do ponto de vista do host, é só mais um processo ouvindo em uma porta TCP. A VPN vive e morre dentro do container. O host não sabe, não liga, e não é afetado.


Por que isso resolve os problemas

Múltiplas VPNs simultâneas. Cada VPN vira um container separado, rodando em uma porta SSH diferente. Você pode ter o container da VPN do cliente A na porta 2222 e o container da VPN do cliente B na porta 2223, ambos rodando ao mesmo tempo, sem conflito nenhum. A tabela de roteamento de cada container é isolada do host e de todos os outros containers.

Host limpo. Nenhum cliente VPN instalado. Nenhuma dependência de sistema. Se quiser parar tudo, é um docker compose down e acabou. Se quiser rodar em outra máquina, é um docker compose up e pronto — desde que tenha os arquivos de configuração da VPN.

Funciona em qualquer OS. O Docker abstrai o ambiente. A mesma configuração roda no Linux, no macOS e no Windows com Docker Desktop. Sem diferenças de comportamento, sem scripts específicos de plataforma.

Portável e versionável. A configuração inteira — Dockerfile, docker-compose, certificados (com o cuidado devido) — pode viver num repositório. Você versiona, você compartilha com o time, você replica em minutos.


O que vem a seguir

A ideia é elegante no papel, mas a implementação tem alguns detalhes que valem atenção. O container precisa de permissões específicas para criar interfaces de rede (NET_ADMIN, /dev/net/tun). O servidor SSH dentro do container precisa ser configurado de forma segura — afinal, você está abrindo uma porta de rede, e isso tem implicações. E a questão de como passar as credenciais da VPN para o container de forma que não seja um desastre de segurança merece uma discussão própria.

Tudo isso está na Parte 2 — A Implementação, onde entro no Dockerfile, no docker-compose e nos comandos SSH que você vai usar no dia a dia.

Se você já trabalhou com esse tipo de problema de VPN e encontrou outras soluções, me conta — fico curioso para saber o que mais as pessoas usam por aí.