Saltar para o conteúdo principal
50% de desconto todos os planos, tempo limitado. A partir de $2.48/mo
17 min left
Ferramentas de desenvolvimento e DevOps

Como publicar apps localhost sem um VPS

B Por Bill 17 min de leitura
Capa «Publicar localhost sem um VPS»: um app local em um laptop se ramifica por um túnel até um celular, uma janela de navegador e uma rede doméstica

Seu app funciona. Você iniciou o servidor de desenvolvimento, abriu http://localhost:3000, e ele faz o que deveria fazer. Aí alguém pede um link, e você descobre que a URL na sua tela não significa nada para ninguém além de você.

Há três formas de dar uma URL pública a um app localhost sem um VPS, mais uma opção mais rápida quando a outra pessoa está na sua rede local, e escolher entre elas não é uma questão de ferramenta. É uma questão de por quanto tempo a coisa precisa continuar acessível, e de se ela pode rodar em outro lugar que não o seu laptop. Abaixo está cada caminho, o comando que gera uma URL, e exatamente o que fará essa URL parar de funcionar.

TL;DR

  • Alguém no seu Wi-Fi precisa ver: vincule o servidor de desenvolvimento a todas as interfaces de rede e passe o seu IP da LAN. Pronto em segundos, morto no instante em que o visitante sai da sua rede.
  • Você precisa de um link que qualquer pessoa possa abrir, pela próxima hora: rode um túnel (cloudflared, ngrok, localtunnel, localhost.run). URL HTTPS pública em cerca de um minuto, sem mudanças no roteador, e ela morre junto com o processo que a iniciou.
  • Precisa continuar no ar com o laptop fechado: envie o app para um plano de hospedagem gratuito. Isso desacopla o app do seu laptop e introduz novas regras sobre cartões de crédito, uso comercial e se seus dados sobrevivem a um reinício.
  • Seu app não precisa de código de servidor no momento da requisição: faça o build e coloque a saída estática em um host estático. Ele pode ficar online sem o seu laptop e não tem nenhum processo de app para acordar, desde que a conta e os limites de uso do host ainda comportem.
  • Um padrão que vale a pena conhecer: next dev e python -m http.server já escutam em todas as interfaces de rede sem nenhuma flag. Se você achava que seu servidor de desenvolvimento era privado, restrito ao seu laptop, ele não é.

Qual caminho serve para o seu app

Fluxograma de decisão do seu app local até um de quatro caminhos: só LAN, túnel público, host de apps ou build estático, com o tempo de configuração, se o laptop pode ficar desligado e o melhor uso de cada um

Três desses quatro caminhos dão ao seu app uma URL pública na internet; o primeiro alcança só a sua própria rede, o que o torna ao mesmo tempo o mais rápido e o mais limitado. Ordene-os por quanto tempo a URL precisa sobreviver e a escolha praticamente se faz sozinha.

CaminhoTempo até ter uma URLQuanto tempo duraO que a mataPara quem é
Mesma redeSegundosEnquanto vocês dois estiverem na redeSeu visitante muda para outro Wi-FiUm colega na mesa ao lado, ou o seu próprio celular
TúnelCerca de um minutoEnquanto o processo estiver rodandoFechar o laptop, matar o terminal, atingir os limites do planoUma demo, uma apresentação para cliente, um teste de webhook
Plano de hospedagem gratuito10 a 30 minutosIndefinidamente, com condiçõesHibernação, um sistema de arquivos efêmero ou os termos do planoAlgo que precisa responder enquanto você dorme
Build estático10 a 20 minutosIndefinidamentePrecisar de código do lado do servidor no momento da requisiçãoApps que podem ser totalmente gerados no build ou rodar no cliente

Quais linhas estão abertas para você depende de três coisas que dá para conferir dentro do seu próprio projeto:

  • O app precisa que o seu código de servidor rode no momento da requisição? Uma rota Flask ou FastAPI, um endpoint server.js , ou lógica de servidor específica por requisição precisa de um host do lado do servidor. Código de servidor executado no build não descarta automaticamente uma implantação estática: os Server Components do Next.js podem rodar durante o next build, e os GET Route Handlers estáticos podem ser pré-renderizados. Se toda requisição em tempo de execução puder ser servida como assets estáticos ou enviada direto do navegador para uma API externa, o caminho estático continua aberto.
  • Ele lê ou grava um arquivo que precisa manter? Um arquivo de banco de dados (.db, .sqlite), uma pasta de uploads, um arquivo JSON que ele edita. Se sim, confira o modelo de armazenamento do host antes de implantar. Os web services gratuitos do Render e as instâncias gratuitas do Koyeb usam armazenamento local efêmero, enquanto as Vercel Functions têm um sistema de arquivos somente leitura com um espaço /tmp temporário. Coloque o estado persistente em um volume durável, banco de dados ou armazenamento de objetos, em vez de presumir que o disco local do app vai sobreviver.
  • Ele precisa de um segredo em tempo de execução? Uma chave em um arquivo .env funciona sem mexer em nada nos dois primeiros caminhos, já que o app continua rodando na sua máquina. Nos outros dois, você a informa de novo nas configurações de ambiente do provedor, e ela não pode estar no repositório que você envia.

Compartilhe na sua própria rede

next dev já escuta em todas as interfaces de rede da sua máquina (é só isso que 0.0.0.0 significa quando você o vê), e o mesmo vale para python -m http.server. Nenhum dos dois precisa de flag, então o servidor de desenvolvimento que você tem rodando agora provavelmente já é acessível pelo seu celular no mesmo Wi-Fi.

O Next.js documenta -H como a forma de mudar esse hostname, com um padrão de 0.0.0.0, e a documentação do Python diz que o módulo se vincula a todas as interfaces a menos que você passe --bind 127.0.0.1. Isso faz dela a forma mais rápida de compartilhar um app localhost: sem conta, sem instalação, sem implantação. Os outros servidores de desenvolvimento comuns precisam ser avisados.

# Already listening on all interfaces. Nothing to add.
next dev
python -m http.server 8000
streamlit run app.py

# Needs the flag.
npm run dev -- --host             # Vite
flask run --host=0.0.0.0
uvicorn main:app --host 0.0.0.0   # FastAPI

A documentação do Vite: server.host tem como padrão localhost, e aceita --host na linha de comando ou server.host: '0.0.0.0' no arquivo de configuração. O Uvicorn usa por padrão 127.0.0.1, o que cobre o FastAPI, já que é ele que o executa. O Streamlit deixa server.address sem definir, e sua referência de configuração observa que defini-lo restringe o acesso a esse único endereço: sem definir significa sem restrição.

Depois você precisa do endereço para passar adiante. É o IP da sua própria máquina na rede local, não localhost:

# macOS
ipconfig getifaddr en0

# Linux
hostname -I

# Windows (PowerShell)
ipconfig | findstr IPv4

Dê ao seu visitante http://<that-address>:3000 e ele entra. O problema é o formato do caminho inteiro: esse endereço não significa nada fora da sua rede. No segundo em que ele estiver em outro Wi-Fi, na rede móvel ou em casa, o link estará morto para ele.

Nota: se o comando roda bem e o outro dispositivo ainda não consegue conectar, quase sempre é o firewall do sistema operacional, não o comando. A documentação do firewall da Apple diz que o macOS exibe um alerta para um app que você ainda não permitiu e nega a conexão até você agir. O Windows, por sua vez, pergunta qual perfil de rede se aplica, mantendo regras separadas para redes privadas e públicas . Escolha Privada em uma rede doméstica ou de escritório. Nunca Pública.

Coloque-o atrás de um túnel

Um túnel é um pequeno programa que roda ao lado do seu app e dá a ele um endereço HTTPS público. Um único comando garante um túnel gratuito para o localhost em cerca de um minuto, e vale saber de antemão que a URL morre no instante em que esse comando termina:

cloudflared tunnel --url http://localhost:3000

Nada muda no seu roteador, por causa da direção em que a conexão viaja. Sua máquina abre uma conexão de saída para a borda do provedor, do mesmo tipo que o seu navegador abre para carregar qualquer página, e o provedor a mantém aberta e empurra as requisições de entrada de volta por ela. As portas de entrada do seu lado continuam fechadas, e é por isso que funciona no Wi-Fi de hotel, no hotspot do celular e em uma conexão doméstica cujo roteador você não controla.

Nota: esse último caso merece uma verificação de sessenta segundos antes de você pensar em redirecionar portas. Abra a página de status do roteador, encontre o IP WAN que ele informa e compare com o seu IP público real em qualquer consulta de «qual é o meu IP». Se o IP WAN estiver dentro de 100.64.0.0/10, o CGNAT é a causa provável. Se o IP WAN e o IP público simplesmente forem diferentes, você sabe que há outra camada de NAT acima, mas pode ser CGNAT ou um NAT duplo comum. Em qualquer caso, redirecionar portas só neste roteador pode não bastar. Essa faixa é reservada pela RFC 6598 como espaço de endereços compartilhado, que é onde o seu provedor de internet coloca você quando fica sem endereços.

As opções diferem principalmente no que pedem de você primeiro.

Os quick tunnels da Cloudflare são o comando acima: sem conta, sem domínio, um subdomínio aleatório em trycloudflare.com . A Cloudflare os limita a 200 requisições em andamento, retornando 429 além disso, não suporta Server-Sent Events, e diz na mesma documentação que os túneis gratuitos são para testes e desenvolvimento, não para publicar um site em produção.

ngrok exige um cadastro primeiro, e depois ngrok http 3000. O plano gratuito atual dá US$ 5 de uso incluído uma única vez, que não renova todo mês, até 3 endpoints online, 1 GB de transferência, 20.000 requisições HTTP/S e uma página de aviso intermediária pela qual o visitante precisa clicar. Você também recebe um domínio de desenvolvimento gratuito atribuído automaticamente, que o ngrok anunciou em 2023 para acabar com a velha reclamação da URL que mudava a cada reinício.

localtunnel não precisa de cadastro nem de instalação além do npx: npx localtunnel --port 3000. Você recebe um subdomínio aleatório, e o README é explícito ao dizer que --subdomain pede um nome e não o garante.

localhost.run não instala nada, porque usa o cliente SSH que o seu sistema operacional já traz: ssh -R 80:localhost:3000 localhost.run. A documentação observa que nenhum download é necessário e que não é preciso criar conta para os domínios gratuitos.

VS Code tem isso no painel Ports, prático se você já vive dentro do editor. Ele exige login com GitHub ou Microsoft, e o padrão vai te derrubar: uma porta encaminhada é Privada, o que significa que o seu visitante será solicitado a entrar com a sua conta até você mudar a porta para Pública. (Bom para um colega de equipe. Inútil para o cliente que só quer clicar em um link.)

Tailscale Funnel também faz isso, com duas restrições que geralmente decidem a questão: a URL só pode viver no domínio do seu próprio tailnet, e ele só pode escutar nas portas 443, 8443 e 10000.

Seja qual for a escolha, tenha clareza sobre o que você distribuiu. Com um túnel público sem controle de acesso, tudo o que o servidor de desenvolvimento serve fica acessível a qualquer um com essa URL, incluindo rotas que você nunca linkou e qualquer interface de depuração que deixou ligada. Ótimo para uma demo de quinze minutos. Bem menos ótimo para uma URL colada em um Discord público.

A expiração pega você de surpresa porque pode parecer que o app quebrou. A maioria dos caminhos rápidos daqui ainda depende de um software de túnel rodando no seu laptop: pare o cloudflared, o ngrok, o localtunnel ou a sessão SSH do localhost.run e o encaminhamento para. O Tailscale Funnel é a exceção quando você o executa com --bg, que mantém a configuração do Funnel rodando em segundo plano e a restaura após um reinício. Nenhum deles consegue servir o seu app local enquanto o próprio laptop estiver offline. Você pode deixar um túnel rodando por dias, e ele vai funcionar até a tampa fechar ou você atingir o limite de requisições.

Um túnel é a ferramenta certa para uma demo e a ferramenta errada para hospedagem: o uptime dele é o uptime do seu laptop.

Deixe o app sair da sua máquina

Este é o primeiro caminho em que o seu laptop deixa de ser peça fundamental, e o primeiro em que os termos importam mais do que as ferramentas. O que encerra as coisas aqui não é um relógio. É uma hibernação, um reset do sistema de arquivos, ou um plano decidindo que o seu app não é o tipo de coisa que ele quer em uma instância gratuita.

As opções abaixo vão de planos gratuitos permanentes a testes curtos. Algumas conseguem manter um app online indefinidamente dentro dos seus limites; outras param após um teste de duração fixa ou exigem uma conta paga para computação. Confira as regras de cobrança, hibernação e armazenamento antes de implantar.

Os termos dos planos gratuitos abaixo foram conferidos na página de preços ou de documentação de cada provedor em 7 de setembro de 2026.

ProvedorUso comercial?Os dados sobrevivem a um reinício?O porém
NetlifyPermitidoSim, com Netlify Blobs ou DatabaseSem cartão para começar; usar todos os créditos mensais do plano Free pausa os projetos até o próximo ciclo de cobrança, a menos que você faça upgrade
RenderNão informadoPerdidos ao reiniciarSem cartão para começar; hiberna após 15 minutos ociosos; o Postgres gratuito expira 30 dias após a criação
Cloudflare Pages / WorkersNão informadoSim, com KV, D1, R2 ou Durable Objects500 builds do Pages por mês; o Workers gratuito fica em 100.000 requisições por dia
VercelNão no HobbyPerdidos ao reiniciarO Hobby é só para uso pessoal; o sistema de arquivos das funções é somente leitura
GitHub PagesNão permitidoSó saída estáticaNada de negócios online, e-commerce ou SaaS comercial; tempo limite de implantação de 10 minutos
PythonAnywhereNão informadoSimContas gratuitas só alcançam uma lista de permissões de hosts externos; o web app gratuito expira depois de um mês a menos que seja renovado
Fly.ioNão informadoSim, com um Fly VolumeSem plano gratuito permanente: 2 horas de máquina ou 7 dias; as Machines de teste param automaticamente após 5 minutos rodando, e o teste inclui 20 GB de armazenamento em volume; os apps param quando o teste acaba até você adicionar um cartão
KoyebNão informadoSem armazenamento local durávelCartão obrigatório; o Koyeb faz e cancela uma pré-autorização de US$ 29, mas o cadastro seleciona o Pro por padrão e cobra o custo proporcional, a menos que você mude para o Starter
Hugging Face SpacesNão informadoPerdidos ao reiniciarOs Static Spaces são gratuitos; Gradio e Docker geralmente exigem um plano pago, mas contas pessoais gratuitas elegíveis podem hospedar até dois Spaces Gradio no ZeroGPU
RailwayNão informadoSim, se o app usar o volume de 0,5 GB incluídoTeste de 30 dias com US$ 5 de crédito único, depois um plano Free de US$ 0 com US$ 1 de crédito de recursos por mês; sem cartão necessário

«Não informado» significa que as páginas do próprio provedor não respondem à pergunta para o plano gratuito. Trate como desconhecido, e não como um sim ou um não.

Três dessas linhas merecem uma olhada extra antes de começar. O Fly.io não tem plano gratuito permanente: o teste termina após 2 horas de máquina ou 7 dias. O Koyeb inclui uma instância gratuita, mas o fluxo de cadastro e cobrança exige atenção antes de implantar. A Hugging Face mantém os Static Spaces gratuitos, enquanto os novos Spaces Gradio e Docker exigem conta paga, exceto pela exceção limitada do ZeroGPU. O Railway não pertence mais a esta lista de alertas: após o teste de 30 dias com US$ 5 de crédito, agora ele passa para um plano Free de US$ 0 com US$ 1 de crédito de recursos por mês.

Depois vem a questão dos dados, que é onde um app que funciona vira silenciosamente um app quebrado. Os web services gratuitos do Render rodam em um sistema de arquivos efêmero, e a documentação é direta: tudo o que for gravado ali, incluindo explicitamente imagens enviadas e bancos SQLite locais, é perdido a cada nova implantação, reinício e hibernação. As funções da Vercel rodam em um sistema de arquivos somente leitura com apenas um espaço temporário, então um arquivo SQLite gravado pelo seu app também não está seguro lá. Se o seu app guarda estado em arquivo, mova-o para um armazenamento durável: um banco de dados hospedado, um armazenamento de objetos ou um volume persistente onde a plataforma oferecer um.

A hibernação merece ser sentida antes de você se comprometer. No plano gratuito do Render, 15 minutos ociosos colocam o serviço para dormir, e a próxima requisição o acorda em cerca de um minuto, exibindo uma página de carregamento para quem clicou no seu link. Para uma peça de portfólio, um dar de ombros. Para um cliente abrindo o link durante uma call, sessenta segundos ruins.

O PythonAnywhere tem uma versão mais sutil da armadilha. Não há hibernação por ociosidade, mas um web app gratuito expira em um mês e para, a menos que você clique no link de renovação que o PythonAnywhere manda por e-mail, e as contas gratuitas têm acesso restrito à internet de saída e só alcançam uma lista de permissões de hosts externos. Um app que chama uma API fora dessa lista fica ali perfeitamente online e falha em toda requisição para essa API não permitida (um jeito horrível de depurar, já que nada em lugar nenhum parece fora do ar).

Publique como site estático

Se nada do que o seu app faz exige código de servidor no momento da requisição, um host estático é a opção mais próxima de «configurar e esquecer»: ele pode ficar online sem o seu laptop, e não há nenhum processo de app esperando para acordar. A conta e os limites de uso do host continuam valendo. Mais apps se qualificam do que você imagina, e é por isso que vale responder à primeira daquelas três perguntas antes de presumir que precisa de um host do lado do servidor.

A regra é mais estreita do que «ele tem backend?». Seu app se qualifica se toda requisição que ele faz vai ou para os seus próprios arquivos estáticos ou direto do navegador para a API de outra pessoa. Buscar dados no Supabase ou em uma API pública a partir do navegador é tranquilo, com a única ressalva de que uma chave dentro do código do navegador é uma chave que você publicou. O que fecha a porta é precisar que o seu próprio código rode em um servidor a cada requisição.

Se ele se qualifica, o roteiro é curto:

npm run build   # Vite writes to dist/, a Next.js static export writes to out/

Depois implante essa saída de build em um host estático. Cloudflare Pages, Netlify e Vercel conseguem fazer o build a partir de um repositório conectado. O GitHub Pages pode publicar arquivos estáticos de um branch ou usar o GitHub Actions para rodar o build do seu framework e implantar a saída gerada.

O GitHub Pages tem restrições nítidas o bastante para importar desde o início. Só estático, um site de usuário ou organização por conta, e limites de uso que afirmam que ele não é hospedagem gratuita para um negócio, um site de e-commerce ou um SaaS comercial. Se o seu app vai receber pagamentos, isso o elimina antes mesmo de começar.

Este caminho não tem expiração de processo de app. Ele continua funcionando enquanto a conta de hospedagem permanecer ativa e dentro dos limites, e deixa de servir assim que o app precisa de trabalho do lado do servidor no momento da requisição.

Onde os caminhos gratuitos terminam

Os caminhos gratuitos falham em pontos diferentes, não todos de uma vez. Um host estático já resolve o uptime do laptop e dá uma URL estável do provedor. Um host de apps gratuito pode fazer o mesmo, e alguns agora incluem armazenamento persistente. Um VPS começa a fazer sentido quando os requisitos se acumulam: o seu próprio processo do lado do servidor precisa ficar online, você precisa de armazenamento persistente previsível, e as regras de recursos ou de uso do plano gratuito não servem mais.

Esse limite merece respeito. Uma demo não é motivo para comprar um servidor, e um projeto estático de baixo tráfego também não. Fique no túnel para compartilhamentos de curta duração, fique no host estático enquanto o app for realmente estático, e fique no host de apps gratuito enquanto os limites dele comportarem o que você roda.

Migre para um VPS quando precisar de um servidor sempre ligado sob o seu controle e estiver disposto a assumir o trabalho operacional que vem junto. Nosso VPS Linux é uma opção, e um VPS comparável de outro provedor faz o mesmo trabalho. Dimensione o servidor para o app em vez de presumir que o menor plano será suficiente.

Ver planos Linux

Construa num VPS Linux com acesso root, NVMe e o poder do AMD EPYC.

Ver planos Linux

Duas coisas mudam quando você faz isso. O fluxo de implantação com push para o git que a plataforma de hospedagem te dava deixa de ser automático. Você pode recriá-lo com um PaaS auto-hospedado como Coolify ou Dokku, ou montar o seu próprio caminho de CI/CD, e de qualquer forma atualizações e manutenção agora são por sua conta.

A outra mudança é que a máquina abriga mais do que o app. Ela vai adorar rodar Code Server e Claude Code se você preferir que o seu editor também more lá, o que é um belo bônus ou um fim de semana inteiro de trabalho, dependendo de você.

Perguntas frequentes

Por que minha URL pública parou de funcionar depois que fechei o laptop?

Porque o túnel estava atrelado ao processo que o criou, não ao seu app. Fechar o laptop ou matar o terminal encerra esse processo, a URL pública morre, e o seu app continua bem. Reiniciar o túnel dá uma URL nova, a menos que a ferramenta atribua um domínio reservado. Se o link precisa sobreviver ao laptop dormindo, o app precisa sair da sua máquina.

Preciso de um nome de domínio para colocar um app local em uma URL pública?

Não, em quase todos os casos. Um quick tunnel da Cloudflare, o domínio de desenvolvimento atribuído pelo ngrok, o localtunnel, o localhost.run e os planos de hospedagem gratuitos acima atribuem a você um subdomínio no domínio deles sem custo. A exceção é um túnel nomeado da Cloudflare, que precisa de um domínio já adicionado ao Cloudflare DNS.

Alguém em outra rede Wi-Fi consegue abrir o meu endereço IP local?

Não. Um endereço como 192.168.1.42 aponta para o dispositivo que o detém na rede à qual você está conectado agora, o que em qualquer outra rede é um dispositivo diferente ou nada. Quem está fora do seu Wi-Fi precisa de um túnel, de um plano de hospedagem gratuito ou de um host estático.

Quais dessas opções funcionam se meu app tem login e banco de dados?

Os caminhos da mesma rede e do túnel funcionam sem alterações, porque o app continua rodando na sua máquina. Uma implantação estática também pode funcionar se as requisições de login e banco de dados forem direto do navegador para um serviço hospedado e nenhum código privado do lado do servidor precisar rodar a cada requisição. Se o seu próprio código de autenticação ou de banco de dados precisa de um servidor no momento da requisição, use um host do lado do servidor. Em um host de apps gratuito, mantenha os dados persistentes em armazenamento durável em vez de presumir que o sistema de arquivos local do app vai sobreviver.

Partilhar

Discussão

Comentários

Inicie sessão para participar na discussão.

Mais do blogue

Continue a ler.

Pronto para implantar? A partir de $2,48/mês.

Cloud independente, desde 2008. AMD EPYC, NVMe, 40 Gbps. Reembolso em 14 dias.