Zeltro › Rode vários projetos localmente sem conflito de portas

Rodando uma dúzia de projetos localmente sem conflito de portas

Todo projeto quer a porta 3000, todo arquivo compose quer a 3306, e nada consegue falar com nada. Aqui está o arranjo que elimina o problema em vez de administrá-lo: serviços compartilhados e um endereço atribuído a cada projeto, para você nunca precisar escolher um.

O problema chega lá pelo quinto projeto. Todo framework quer a porta 3000 ou a 8000. Todo docker-compose.yaml que você clona quer ocupar a 3306 ou a 5432. Você começa a anotar qual projeto está em qual porta, e aí precisa que dois projetos conversem e descobre o host.docker.internal.

Dá para administrar tudo isso. Também dá para evitar, e não decorando um conjunto melhor de portas, mas nunca escolhendo nenhuma.

O app Zeltro: uma barra lateral de projetos, cada um com indicador de execução, seus endereços local e de rede local, e botões para iniciar, parar, editar e abrir
Todos os projetos em uma lista, cada um com um endereço local e um de rede local atribuídos pelo Zeltro. Nada para escolher.

O arranjo#

Cada projeto ganha o próprio endereço em uma rede Docker privada, atribuído quando o projeto é criado. Você nunca escolhe, e dois projetos não têm como colidir:

LOCAL  http://10.247.177.168        # from this machine
LAN    http://192.168.1.6:168       # from anything else on the network

O zeltro status mostra os dois para cada projeto. O endereço local é o IP do próprio contêiner, então não tem porta nenhuma; o endereço de rede local é o IP deste computador mais a porta publicada do projeto, para acessar pelo celular ou por outro notebook.

Por baixo, todos os projetos do computador compartilham um único conjunto de serviços:

Serviço Contêiner Acessível a partir de um projeto como
MariaDB zeltro-mariadb zeltro-mariadb:3306
Postgres zeltro-postgres zeltro-postgres:5432
Redis zeltro-redis zeltro-redis:6379
MongoDB zeltro-mongo zeltro-mongo:27017
Memcached zeltro-memcached zeltro-memcached:11211

Dez projetos, um de cada. Sete contêineres de Postgres duplicados consumindo cerca de 700 MB viram um só consumindo uns 100.

~700 MBpara sete contêineres de Postgres duplicados
~100 MBpara o único zeltro-postgres compartilhado
0portas para escolher, reservar ou lembrar

O que isso resolve#

A roleta das portasNada para lembrar, nada para reservar, nenhuma colisão quando dois projetos usam a 3000 por padrão. A distribuição é problema do Zeltro, não seu.

Trabalho entre projetosTodos os projetos ficam na mesma rede Docker e são acessíveis nela pelo nome, então um fetch('http://client-api/') de dentro de outro projeto funciona sem nenhuma configuração de rede. Um app em Laravel lendo o banco de dados de um projeto em Django é uma string de conexão, não um exercício.

Repositórios clonados que brigam com vocêUm arquivo compose original que ocupa 5432:5432 ou 80:80 é religado aos serviços compartilhados na configuração, e o original fica guardado como docker-compose.upstream.yaml.

A carga no computadorUm processo de banco de dados por motor, em vez de um por projeto. É a diferença entre um notebook que aguenta todo o seu trabalho e um que não aguenta.

Configurações do Zeltro, aba Serviços compartilhados: zeltro-mariadb, zeltro-redis, zeltro-memcached e phpMyAdmin rodando, cada um com seu endereço
Os serviços compartilhados que todos os projetos usam, uma instância de cada.

Na prática#

zeltro new laravel barber-shop      # scaffold, wire up, start
zeltro setup existing-project       # adapt a project you already have
zeltro up barber-shop               # start it
zeltro status                       # what is running, and its two addresses

Os endereços são atribuídos e mostrados para você. Nada é gravado no /etc/hosts, e o Zeltro nunca pede sudo para gerenciar um projeto.

Serviços compartilhados significam versões compartilhadas: uma única versão principal do Postgres para tudo. A maioria dos projetos nem percebe. Se dois realmente precisam de versões principais diferentes, esse é o único caso em que ferramentas por projeto, como o DDEV ou o Lando, ainda levam vantagem, e é a troca que este desenho faz de propósito.

Por que isso importa mais com um agente de IA#

Um agente trabalhando em uma pasta não faz ideia do que mais existe no computador. Sozinho, ele vai escolher uma porta, adicionar um contêiner de banco de dados ao arquivo compose e colidir em silêncio com algo que você tinha rodando. Um ambiente fixo, com endereços atribuídos, serviços conhecidos e um AGENTS.md escrito, é o que impede isso, e é boa parte do motivo de o Zeltro ser organizado assim.

Como os projetos compartilham uma rede, os agentes deles também podem se coordenar. Quando um projeto muda a API, o agente dele pode avisar os agentes dos projetos que dependem dela.

O app Zeltro mostrando uma mensagem do agente de um projeto chegando na sessão de outro projeto, avisando que a API dele mudou de lugar
O agente de um projeto avisa outro que a API dele mudou de lugar.

Perguntas

Preciso escolher porta para alguma coisa?

Não. Cada projeto recebe um IP de contêiner e uma porta publicada quando é criado. O zeltro status mostra o endereço local e o endereço de rede local de cada um.

Qual a diferença entre os dois endereços?

O local é o IP do próprio contêiner na rede Docker: sem porta, porque não há mais nada nesse endereço. O de rede local é o IP do seu computador mais a porta publicada do projeto, que é por onde outro aparelho precisa passar.

No macOS e no Windows, o Docker mantém os contêineres dentro de uma máquina virtual, e o IP do contêiner não é acessível a partir do host, então o endereço local passa a ser http://localhost:<port>. O Zeltro detecta isso e mostra o endereço que funciona de verdade.

Os projetos conseguem se acessar pelo nome?

Sim, de dentro dos contêineres. Todos os projetos entram na mesma rede Docker, e o DNS embutido do Docker resolve os nomes dos projetos e dos serviços nela. É isso que torna simples as chamadas entre projetos e os bancos de dados compartilhados.

O seu navegador não está nessa rede, e é por isso que ele usa o endereço acima em vez de um nome.

E se dois projetos precisarem de versões diferentes do Postgres?

Não dá: uma única instância compartilhada é a troca. Se isso for um requisito obrigatório, use ferramentas por projeto para esses projetos, ou deixe o diferente em uma stack própria.

Isso funciona com um projeto que tem o próprio docker-compose.yaml?

Sim. Os serviços de banco de dados embutidos são removidos e o app é apontado para os compartilhados, com as credenciais gravadas no .env. O arquivo original fica guardado como docker-compose.upstream.yaml.

E os bancos de dados em si: um projeto vê os dados do outro?

Eles compartilham o servidor, não o banco de dados. Cada projeto ganha o próprio banco de dados e as próprias credenciais. O acesso entre projetos é possível de propósito, o que facilita uma arquitetura no estilo de microsserviços, mas nada é compartilhado por acidente.

Experimente o Zeltro no seu próprio computador

Grátis para uso pessoal, sem conta. Crie com a IA que você já paga e fique com o app, os dados e o código no seu próprio computador.

Instalar o Zeltro Por que trazer sua própria chave

Prefere não configurar você mesmo? Eu faço para você.

Verificado em 2026-08-22. Os outros produtos mudam com frequência: se algo aqui estiver desatualizado, avise a gente e a gente corrige.