Blog Dev

Desenvolvimento remoto: Code-Server, Coolify e Hetzner - as piores armadilhas de arquitetura

Como programador freelancer e consultor de TI, a flexibilidade é tudo. Quer esteja a trabalhar em backends complexos com Java Spring Boot, a criar frontends em JavaScript ou a renderizar visualizações com Three.js, o ambiente de desenvolvimento tem de ser fluido, reproduzível e acessível a partir de qualquer lugar.

Foi por isso que deixei para trás a abordagem clássica de alojamento e transferi a minha infraestrutura para um servidor Hetzner próprio, totalmente orquestrado pelo Coolify. No centro está uma instância remota do VS Code (Code-Server).

Em teoria, é uma configuração de sonho. Na prática, caí em armadilhas de arquitetura que quase me levaram à loucura. Estes são os maiores obstáculos e como os evitar de forma elegante.

Armadilha 1: a ilusão do proxy de portas (ou o ecrã preto da morte)

O VS Code no navegador oferece uma funcionalidade aparentemente genial: o reencaminhamento de portas integrado. Quando inicia um servidor de testes local, por exemplo na porta 4096, o IDE cria automaticamente um túnel para um URL como https://o-seu-ide.pt/proxy/4096/.

Para desenvolvimento exclusivamente backend, como uma API REST Spring Boot que devolve apenas JSON, isto é fantástico. Não são necessárias regras de firewall e o acesso é direto.

No entanto, assim que inicia um frontend moderno com Vue, React ou Vite, ou uma ferramenta com interface gráfica, depara-se com um ecrã preto e intermináveis erros 404 na consola.

O motivo: Os frameworks modernos compilam com caminhos absolutos, por exemplo <script src="/main.js">. O navegador ignora completamente o subdiretório /proxy/4096/, procura os ficheiros na raiz do servidor e falha.

A solução: Traefik e subdomínios

A única arquitetura limpa consiste em ignorar completamente o túnel integrado do VS Code. Em vez disso, utilizamos o reverse proxy Traefik do Coolify:

  1. Crie no fornecedor do domínio um registo wildcard (*.oseudominio.pt) que aponte para o servidor Hetzner.
  2. No Coolify, adicione aos domínios do contentor um novo subdomínio com a porta interna: https://dev.oseudominio.pt:4096.
  3. O Traefik trata automaticamente do certificado SSL e encaminha o URL público limpo, sem sufixo de porta, diretamente para o contentor. O frontend passa a carregar corretamente.

Armadilha 2: o equívoco do localhost (502 Bad Gateway)

Configurou o subdomínio no Coolify e aguarda com expectativa a pré-visualização, mas recebe um frio 502 Bad Gateway. O Traefik está a funcionar, mas o contentor bloqueia a ligação.

Isto acontece quando o servidor interno, por exemplo o Five Server ou uma ferramenta própria, escuta por predefinição em 127.0.0.1. No mundo do Docker, isso significa que o serviço comunica apenas consigo próprio dentro do contentor. Quando o proxy Traefik bate à porta a partir do exterior, esta permanece fechada.

A correção: Force o servidor de testes a escutar em todas as interfaces de rede. Se o iniciar no terminal, utilize --hostname=0.0.0.0 ou defina a variável de ambiente HOST="0.0.0.0". Se utilizar uma extensão do VS Code como o Five Server, altere o settings.json:

{
  "fiveServer.host": "0.0.0.0",
  "fiveServer.port": 5500
}

Armadilha 3: a amnésia do Docker («Restart» hoje, desaparecido amanhã)

Configura cuidadosamente o seu .bashrc com aliases úteis, gera uma chave SSH para o GitHub, para o contentor através do Coolify e, no dia seguinte, clica em «Deploy». De repente, desapareceu tudo. Os aliases foram eliminados e o Git volta a pedir palavras-passe.

Não é um erro, mas uma funcionalidade. Um contentor parado aparece durante algum tempo com a opção «Restart». Durante a noite, a recolha de lixo do Coolify limpa o servidor e elimina completamente o contentor inativo. Ao clicar em «Deploy», é criado um contentor novo a partir da imagem base, pelo que tudo o que não era persistente se perde.

A estrutura correta

Nunca confie no armazenamento efémero do contentor. Utilize bind mounts ou volumes Docker para tudo o que precisa de permanecer.

volumes:
  - type: bind
    source: /opt/appdata/workspace # O seu código
    target: /workspace
  - type: bind
    source: /opt/appdata/config    # Definições do VS Code, chaves SSH e .bashrc
    target: /config

Armadilha 4: configuração CORS atrás do reverse proxy

A última armadilha surge muitas vezes durante o desenvolvimento full stack. O frontend está em https://dev.oseudominio.pt e envia pedidos para o backend Spring. Por hábito, inclui a porta na sua CorsConfiguration:

// ERRADO quando existe um reverse proxy à frente!
configuration.setAllowedOriginPatterns(
    Arrays.asList("https://dev.oseudominio.pt:5500")
);

O backend volta a bloquear o pedido. Porquê? A porta 5500 é apenas uma instrução de encaminhamento interna do Coolify. Externamente, o navegador comunica de forma transparente com o proxy Traefik através da porta HTTPS padrão 443. Assim, define o cabeçalho Origin simplesmente como https://dev.oseudominio.pt.

Remova a porta da configuração do backend e os erros de CORS desaparecem.


Conclusão: Uma configuração própria com Coolify e Code-Server na Hetzner exige inicialmente alguma paciência e conhecimentos sólidos de Docker. No entanto, quando o encaminhamento está correto, os volumes estão montados e as portas estão certas, dispõe de um IDE privado na cloud de alto desempenho que não fica atrás das soluções SaaS tradicionais.