Ga naar hoofdinhoud
50% korting alle plannen, beperkte tijd. Vanaf $2.48/mo
17 min left
Developer-tools en DevOps

Zo zet je localhost-apps publiek online zonder VPS

B Door Bill 17 min leestijd
Titelkaart „Localhost publiek online zonder VPS”: een lokale app op een laptop waaiert via een tunnel uit naar een telefoon, een browservenster en een thuisnetwerk

Je app draait. Je hebt de dev-server gestart, http://localhost:3000geopend, en hij doet wat hij moet doen. Dan vraagt iemand om een link, en ontdek je dat de URL op je scherm voor niemand anders dan jou iets betekent.

Er zijn drie manieren om een localhost-app een publieke URL te geven zonder VPS, plus één snellere optie als de ander in je lokale netwerk zit, en kiezen daartussen is geen toolvraag. Het is de vraag hoe lang het ding bereikbaar moet blijven, en of het ergens anders dan op je laptop kan draaien. Hieronder vind je elk pad, het commando dat een URL oplevert, en precies datgene wat die URL weer laat stoppen met werken.

TL;DR

  • Iemand op je wifi moet het zien: bind de dev-server aan alle netwerkinterfaces en geef je LAN-IP door. In seconden klaar, dood zodra je bezoeker je netwerk verlaat.
  • Je hebt een link nodig die iedereen het komende uur kan openen: start een tunnel (cloudflared, ngrok, localtunnel, localhost.run). Publieke HTTPS-URL in ongeveer een minuut, geen routerwijzigingen, en hij sterft met het proces dat hem startte.
  • Het moet blijven draaien terwijl je laptop dicht is: push de app naar een gratis hostingplan. Dat koppelt de app los van je laptop en brengt nieuwe regels mee over creditcards, commercieel gebruik en of je data een herstart overleeft.
  • Je app heeft geen servercode nodig op het moment van het verzoek: bouw hem en zet de statische output op een statische host. Hij kan online blijven zonder je laptop en heeft geen app-proces dat wakker gemaakt moet worden, zolang het account en de gebruikslimieten van de host nog passen.
  • Eén standaardinstelling die je moet kennen: next dev en python -m http.server luisteren al zonder enige flag op elke netwerkinterface. Als je dacht dat je dev-server privé was en alleen op je laptop zichtbaar, dan is dat niet zo.

Welk pad past bij je app

Beslisdiagram van je lokale app naar een van vier paden: alleen LAN, publieke tunnel, app-host of statische build, met de installatietijd, of de laptop uit mag en het beste gebruik van elk pad

Drie van deze vier paden geven je app een publieke internet-URL; het eerste bereikt alleen je eigen netwerk, wat het tegelijk het snelste en het meest beperkte maakt. Sorteer ze op hoe lang de URL moet overleven en de keuze maakt zichzelf grotendeels.

PadTijd tot een URLHoe lang het duurtWat het de das omdoetVoor wie
Zelfde netwerkSecondenZolang jullie allebei op het netwerk zittenJe bezoeker wisselt naar een andere wifiEen collega aan het bureau ernaast, of je eigen telefoon
TunnelOngeveer een minuutZolang het proces draaitDe laptop dichtklappen, de terminal afsluiten, de limieten van het plan bereikenEen demo, een klantpresentatie, een webhook-test
Gratis hostingplan10 tot 30 minutenOnbeperkt, onder voorwaardenSpin-down, een vluchtig bestandssysteem of de voorwaarden van het planIets dat moet antwoorden terwijl jij slaapt
Statische build10 tot 20 minutenOnbeperktServer-side code nodig hebben op het moment van het verzoekApps die volledig tijdens de build gegenereerd kunnen worden of client-side draaien

Welke rijen voor jou openstaan, hangt af van drie dingen die je in je eigen project kunt nakijken:

  • Heeft de app je servercode nodig op het moment van het verzoek? Een Flask- of FastAPI-route, een server.js -endpoint of verzoekspecifieke serverlogica heeft een server-side host nodig. Servercode tijdens de build sluit een statische deployment niet automatisch uit: Next.js Server Components kunnen draaien tijdens next build, en statische GET Route Handlers kunnen worden geprerenderd. Als elk runtime-verzoek als statische assets geserveerd kan worden of rechtstreeks vanuit de browser naar een externe API gaat, staat het statische pad nog open.
  • Leest of schrijft hij een bestand dat hij moet bewaren? Een databasebestand (.db, .sqlite), een uploadmap, een JSON-bestand dat hij bewerkt. Zo ja, controleer dan het opslagmodel van de host voordat je deployt. Gratis webservices van Render en gratis instances van Koyeb gebruiken vluchtige lokale opslag, terwijl Vercel Functions een alleen-lezen bestandssysteem hebben met tijdelijke /tmp -ruimte. Zet persistente state in een duurzaam volume, een database of objectopslag in plaats van aan te nemen dat de lokale schijf van de app het overleeft.
  • Heeft hij tijdens runtime een secret nodig? Een sleutel in een .env -bestand werkt onaangepast op de eerste twee paden, omdat de app nog op je machine draait. Op de andere twee voer je hem opnieuw in bij de omgevingsinstellingen van de provider, en hij mag niet in de repo staan die je pusht.

Deel hem op je eigen netwerk

next dev luistert al op elke netwerkinterface van je machine (meer betekent 0.0.0.0 niet als je het ziet), en dat geldt ook voor python -m http.server. Geen van beide heeft een flag nodig, dus de dev-server die je nu hebt draaien is waarschijnlijk al bereikbaar vanaf je telefoon op dezelfde wifi.

Next.js documenteert -H als de manier om die hostnaam te wijzigen, met een standaardwaarde van 0.0.0.0, en de Python-documentatie zegt dat de module zich aan alle interfaces bindt , tenzij je --bind 127.0.0.1meegeeft. Dat maakt dit de snelste manier om een localhost-app te delen: geen account, geen installatie, geen deployment. De andere gangbare dev-servers moet je het vertellen.

# 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

De documentatie van Vite: server.host staat standaard op localhost, en accepteert --host op de commandoregel of server.host: '0.0.0.0' in het configuratiebestand. Uvicorn gebruikt standaard 127.0.0.1, wat FastAPI dekt, want daar draait het op. Streamlit laat server.address leeg, en de configuratiereferentie merkt op dat het instellen de toegang beperkt tot dat ene adres: leeg betekent onbeperkt.

Dan heb je het adres nodig om door te geven. Dat is het eigen IP van je machine in het lokale netwerk, niet localhost:

# macOS
ipconfig getifaddr en0

# Linux
hostname -I

# Windows (PowerShell)
ipconfig | findstr IPv4

Geef je bezoeker http://<that-address>:3000 en hij is binnen. De adder onder het gras is de vorm van het hele pad: dat adres betekent buiten je netwerk niets. Zodra hij op een andere wifi zit, op mobiel internet of thuis, is de link voor hem dood.

Opmerking: als het commando prima draait en het andere apparaat nog steeds geen verbinding krijgt, is het bijna altijd de firewall van het besturingssysteem, niet het commando. Apples firewall-documentatie zegt dat macOS een melding toont voor een app die je nog niet hebt toegestaan en de verbinding weigert totdat je iets doet. Windows vraagt in plaats daarvan welk netwerkprofiel van toepassing is, met aparte regels voor privé- en openbare netwerken. Kies Privé op een thuis- of kantoornetwerk. Nooit Openbaar.

Zet hem achter een tunnel

Een tunnel is een klein programma dat naast je app draait en hem een publiek HTTPS-adres geeft. Eén commando levert je in ongeveer een minuut een gratis tunnel naar localhost op, en het is goed om vooraf te weten dat de URL sterft op het moment dat dat commando stopt:

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

Er verandert niets aan je router, vanwege de richting waarin de verbinding loopt. Je machine opent een uitgaande verbinding naar de edge van de provider, hetzelfde soort verbinding dat je browser maakt om een pagina te laden, en de provider houdt die open en stuurt inkomende verzoeken erdoorheen terug. Inkomende poorten aan jouw kant blijven dicht, en daarom werkt dit op hotel-wifi, op een telefoonhotspot en op een thuisverbinding waarvan je de router niet beheert.

Opmerking: dat laatste geval verdient een controle van zestig seconden voordat je in plaats daarvan port forwarding overweegt. Open de statuspagina van je router, zoek het WAN-IP dat hij meldt en vergelijk het met je echte publieke IP via een willekeurige „wat is mijn IP”-opzoeking. Als het WAN-IP binnen 100.64.0.0/10valt, is CGNAT de waarschijnlijke oorzaak. Als het WAN-IP en het publieke IP gewoon verschillen, weet je dat er stroomopwaarts nog een NAT-laag zit, maar dat kan CGNAT zijn of gewone dubbele NAT. In beide gevallen is port forwarding op alleen deze router mogelijk niet genoeg. Die reeks is door RFC 6598 gereserveerd als gedeelde adresruimte, en daar zet je provider je achter als hij door zijn adressen heen is.

De opties verschillen vooral in wat ze eerst van je willen.

Cloudflare quick tunnels zijn het commando hierboven: geen account, geen domein, een willekeurig trycloudflare.com -subdomein. Cloudflare begrenst ze op 200 lopende verzoeken, daarboven krijg je 429's, ondersteunt geen Server-Sent Events, en zegt in dezelfde documentatie dat gratis tunnels bedoeld zijn voor testen en ontwikkelen, niet voor het uitrollen van een productiewebsite.

ngrok vraagt eerst om een registratie, en daarna ngrok http 3000. Het huidige gratis plan geeft je eenmalig $5 aan inbegrepen gebruik dat niet maandelijks vernieuwt, tot 3 online endpoints, 1 GB dataverkeer, 20.000 HTTP/S-verzoeken en een tussenpagina met waarschuwing waar je bezoeker doorheen moet klikken. Je krijgt ook een gratis, automatisch toegewezen ontwikkeldomein, dat ngrok in 2023 aankondigde om de oude klacht over de URL die bij elke herstart veranderde uit de wereld te helpen.

localtunnel heeft geen registratie en geen installatie nodig buiten npx: npx localtunnel --port 3000. Je krijgt een willekeurig subdomein, en de README is er duidelijk over dat --subdomain een naam aanvraagt en die niet garandeert.

localhost.run installeert niets, omdat het de SSH-client gebruikt die je besturingssysteem al meelevert: ssh -R 80:localhost:3000 localhost.run. De documentatie merkt op dat geen download nodig is en dat er voor gratis domeinen geen account hoeft te worden aangemaakt.

VS Code heeft dit in het Ports-paneel, handig als je toch al in de editor leeft. Het wil een GitHub- of Microsoft-login, en de standaardinstelling laat je struikelen: een doorgestuurde poort is Privé, wat betekent dat je bezoeker wordt gevraagd in te loggen met jouw account totdat je de poort op Openbaar zet. (Prima voor een teamgenoot. Nutteloos voor de klant die gewoon op een link wil klikken.)

Tailscale Funnel doet dit ook, met twee beperkingen die het meestal beslissen: de URL kan alleen op het domein van je eigen tailnet leven, en hij kan alleen luisteren op de poorten 443, 8443 en 10000.

Wat je ook kiest, wees je bewust van wat je hebt weggegeven. Met een publieke tunnel zonder toegangscontrole is alles wat de dev-server serveert bereikbaar voor iedereen met die URL, inclusief routes waar je nooit naar hebt gelinkt en elke debug-interface die je aan hebt laten staan. Prima voor een demo van een kwartier. Een stuk minder prima voor een URL die je in een openbare Discord plakt.

Het verlopen overvalt je, omdat het kan lijken alsof de app kapot is. De meeste snelle routes hier hangen nog af van tunnelsoftware die op je laptop draait: stop cloudflared, ngrok, localtunnel of de SSH-sessie van localhost.run en het doorsturen stopt. Tailscale Funnel is de uitzondering als je het draait met --bg, wat de Funnel-configuratie op de achtergrond laat draaien en na een herstart herstelt. Geen van deze kan je lokale app serveren terwijl de laptop zelf offline is. Je kunt een tunnel dagen laten draaien, en hij werkt precies tot het deksel dichtgaat of je de verzoeklimiet raakt.

Een tunnel is het juiste gereedschap voor een demo en het verkeerde voor hosting: zijn uptime is de uptime van je laptop.

Laat de app je machine verlaten

Dit is het eerste pad waarop je laptop niet langer dragend is, en het eerste waarop de voorwaarden zwaarder wegen dan de tooling. Wat het hier beëindigt, is geen klok. Het is een spin-down, een reset van het bestandssysteem, of een plan dat besluit dat jouw app niet het soort ding is dat het op een gratis instance wil.

De opties hieronder lopen van doorlopende gratis plannen tot korte proefperiodes. Sommige kunnen een app binnen hun limieten onbeperkt online houden; andere stoppen na een vaste proefperiode of vereisen een betaald account voor rekenkracht. Controleer de regels voor facturering, slaapstand en opslag voordat je deployt.

De voorwaarden van de gratis plannen hieronder zijn op 7 september 2026 gecontroleerd op de eigen prijs- of documentatiepagina van elke provider.

LeverancierCommercieel gebruik?Overleeft data een herstart?De adder onder het gras
NetlifyToegestaanJa, met Netlify Blobs of DatabaseGeen kaart om te starten; alle maandelijkse credits van het Free-plan opmaken pauzeert projecten tot de volgende factureringscyclus, tenzij je upgradet
RenderNiet vermeldVerloren bij herstartGeen kaart om te starten; slaapt na 15 minuten inactiviteit; gratis Postgres verloopt 30 dagen na aanmaak
Cloudflare Pages / WorkersNiet vermeldJa, met KV, D1, R2 of Durable Objects500 Pages-builds per maand; gratis Workers zit op 100.000 verzoeken per dag
VercelNiet op HobbyVerloren bij herstartHobby is alleen voor persoonlijk gebruik; het bestandssysteem van functions is alleen-lezen
GitHub PagesNiet toegestaanAlleen statische outputGeen online bedrijf, e-commerce of commerciële SaaS; deploy-timeout van 10 minuten
PythonAnywhereNiet vermeldJaGratis accounts bereiken alleen een allowlist van externe hosts; de gratis web-app verloopt na een maand tenzij verlengd
Fly.ioNiet vermeldJa, met een Fly VolumeGeen doorlopend gratis plan: 2 machine-uren of 7 dagen; proef-Machines stoppen automatisch na 5 minuten draaien, en de proefperiode bevat 20 GB volume-opslag; apps stoppen als de proefperiode eindigt totdat je een kaart toevoegt
KoyebNiet vermeldGeen duurzame lokale opslagKaart vereist; Koyeb plaatst en annuleert een pre-autorisatie van $29, maar de registratie selecteert standaard Pro en rekent de pro-rata kosten daarvan af, tenzij je overstapt naar Starter
Hugging Face SpacesNiet vermeldVerloren bij herstartStatic Spaces zijn gratis; Gradio en Docker vereisen doorgaans een betaald plan, maar in aanmerking komende gratis persoonlijke accounts kunnen tot twee Gradio Spaces op ZeroGPU hosten
RailwayNiet vermeldJa, als de app het inbegrepen volume van 0,5 GB gebruiktProefperiode van 30 dagen met eenmalig $5 aan credit, daarna een Free-plan van $0 met $1 aan resource-credit per maand; geen kaart vereist

„Niet vermeld” betekent dat de eigen pagina's van de provider de vraag voor hun gratis plan niet beantwoorden. Behandel het als onbekend, niet als een ja of een nee.

Drie van die rijen verdienen een extra blik voordat je begint. Fly.io heeft geen doorlopend gratis plan: de proefperiode eindigt na 2 machine-uren of 7 dagen. Koyeb heeft een gratis instance, maar het registratie- en factureringsproces vraagt aandacht voordat je deployt. Hugging Face houdt Static Spaces gratis, terwijl nieuwe Gradio- en Docker-Spaces een betaald account vereisen, op de beperkte ZeroGPU-uitzondering na. Railway hoort niet meer in deze waarschuwingslijst: na de proefperiode van 30 dagen met $5 aan credit gaat het nu over op een Free-plan van $0 met $1 aan resource-credit per maand.

Dan is er de datavraag, waar een werkende app stilletjes een kapotte wordt. De gratis webservices van Render draaien op een vluchtig bestandssysteem, en de documentatie is er duidelijk over: alles wat daar geschreven wordt, geüploade afbeeldingen en lokale SQLite-databases nadrukkelijk inbegrepen, gaat verloren bij elke redeploy, herstart en spin-down. De functions van Vercel draaien op een alleen-lezen bestandssysteem met slechts een tijdelijke kladruimte, dus een SQLite-bestand dat je app schrijft is daar ook niet veilig. Als je app state in een bestand bewaart, verplaats die dan naar duurzame opslag: een gehoste database, objectopslag of een persistent volume waar het platform er een aanbiedt.

Spin-down moet je gevoeld hebben voordat je je vastlegt. Op het gratis plan van Render brengen 15 minuten inactiviteit de service in slaap, en het volgende verzoek maakt hem wakker in ongeveer een minuut, met een laadpagina voor degene die op je link klikte. Voor een portfoliostuk: schouderophalen. Voor een klant die de link tijdens een call opent: zestig slechte seconden.

PythonAnywhere heeft een subtielere versie van de valkuil. Er is geen spin-down bij inactiviteit, maar een gratis web-app verloopt na een maand en stopt tenzij je op de verlengingslink klikt die PythonAnywhere je mailt, en gratis accounts krijgen beperkte uitgaande internettoegang en bereiken alleen een allowlist van externe hosts. Een app die een API buiten die lijst aanroept, staat keurig online en laat elk verzoek naar die niet-toegestane API mislukken (afschuwelijk om te debuggen, want nergens lijkt iets stuk).

Lever hem op als statische site

Als niets van wat je app doet servercode vereist op het moment van het verzoek, is een statische host hier de optie die het dichtst bij „instellen en vergeten” komt: hij kan online blijven zonder je laptop, en er is geen app-proces dat wacht om wakker gemaakt te worden. Het account en de gebruikslimieten van de host blijven gelden. Meer apps komen in aanmerking dan je zou verwachten, en daarom is de eerste van die drie vragen het beantwoorden waard voordat je aanneemt dat je een server-side host nodig hebt.

De regel is smaller dan „heeft hij een backend”. Je app komt in aanmerking als elk verzoek dat hij doet óf naar je eigen statische bestanden gaat, óf rechtstreeks vanuit de browser naar de API van iemand anders. Supabase of een publieke API vanuit de browser ophalen is prima, met de ene kanttekening dat een sleutel in browsercode een sleutel is die je hebt gepubliceerd. Wat de deur sluit, is dat je eigen code voor elk verzoek op een server moet draaien.

Komt hij in aanmerking, dan is het stappenplan kort:

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

Deploy die build-output vervolgens naar een statische host. Cloudflare Pages, Netlify en Vercel kunnen bouwen vanuit een gekoppelde repo. GitHub Pages kan statische bestanden vanuit een branch publiceren of GitHub Actions gebruiken om de build van je framework te draaien en de gegenereerde output te deployen.

GitHub Pages heeft beperkingen die scherp genoeg zijn om vooraf mee te wegen. Alleen statisch, één gebruikers- of organisatiesite per account, en gebruiksvoorwaarden die stellen dat het geen gratis hosting voor een bedrijf, een e-commercesite of commerciële SaaS is. Als je app betalingen gaat aannemen, valt dat al af voordat je begint.

Dit pad kent geen verlopen van een app-proces. Het blijft werken zolang het hostingaccount actief en binnen zijn limieten blijft, en het past niet meer zodra de app server-side werk nodig heeft op het moment van het verzoek.

Waar de gratis paden ophouden

De gratis paden falen op verschillende plekken, niet allemaal tegelijk. Een statische host lost de laptop-uptime al op en geeft je een stabiele provider-URL. Een gratis app-host kan hetzelfde, en sommige bieden nu persistente opslag. Een VPS begint zinvol te worden als de eisen zich opstapelen: je eigen server-side proces moet online blijven, je hebt voorspelbare persistente opslag nodig, en de resource- of gebruiksregels van het gratis plan passen niet meer.

Die drempel verdient respect. Eén demo is geen reden om een server te kopen, en een statisch project met weinig verkeer ook niet. Blijf op een tunnel voor kortstondig delen, blijf op een statische host zolang de app echt statisch is, en blijf op een gratis app-host zolang de limieten passen bij wat je draait.

Stap over op een VPS als je een altijd-aan server nodig hebt die je zelf beheert en je bereid bent het bijbehorende operationele werk op je te nemen. Onze Linux VPS is één optie, en een vergelijkbare VPS van een andere provider doet hetzelfde werk. Dimensioneer de server voor de app in plaats van aan te nemen dat het kleinste plan genoeg is.

Bekijk Linux-plannen

Bouw op een Linux VPS met root-toegang, NVMe en AMD EPYC-kracht.

Bekijk Linux-plannen

Twee dingen veranderen als je dat doet. De push-naar-git-deploymentworkflow die een platformhost je gaf, is niet langer automatisch. Je kunt hem nabouwen met een self-hosted PaaS zoals Coolify of Dokku, of je eigen CI/CD-pad bouwen, en hoe dan ook zijn updates en onderhoud nu jouw verantwoordelijkheid.

De andere verandering is dat de machine meer herbergt dan de app. Hij zal met plezier Code Server en Claude Code draaien als je liever ook je editor daar laat wonen, wat afhankelijk van jou óf een leuke bonus óf een compleet nieuw weekend werk is.

Veelgestelde vragen

Waarom werkte mijn publieke URL niet meer nadat ik mijn laptop dichtklapte?

Omdat de tunnel gebonden was aan het proces dat hem aanmaakte, niet aan je app. De laptop dichtklappen of de terminal afsluiten beëindigt dat proces, de publieke URL gaat dood, en met je app is niets mis. De tunnel opnieuw starten geeft een nieuwe URL, tenzij de tool je een gereserveerd domein toewijst. Als de link de slaapstand van je laptop moet overleven, moet de app je machine verlaten.

Heb ik een domeinnaam nodig om een lokale app op een publieke URL te zetten?

Nee, in vrijwel alle gevallen niet. Een Cloudflare quick tunnel, het door ngrok toegewezen ontwikkeldomein, localtunnel, localhost.run en de gratis hostingplannen hierboven wijzen je allemaal gratis een subdomein op hun eigen domein toe. De uitzondering is een Cloudflare named tunnel, die een domein nodig heeft dat je al aan Cloudflare DNS hebt toegevoegd.

Kan iemand op een ander wifinetwerk mijn lokale IP-adres openen?

Nee. Een adres als 192.168.1.42 wijst naar het apparaat dat het toevallig heeft op het netwerk waar jij nu op zit, en dat is op elk ander netwerk een ander apparaat of helemaal niets. Iedereen buiten je wifi heeft in plaats daarvan een tunnel, een gratis hostingplan of een statische host nodig.

Welke hiervan werken als mijn app een login en een database heeft?

De paden zelfde netwerk en tunnel werken ongewijzigd, omdat de app nog op je machine draait. Een statische deployment kan ook werken als login- en databaseverzoeken rechtstreeks vanuit de browser naar een gehoste dienst gaan en er voor geen enkel verzoek privé server-side code hoeft te draaien. Als je eigen authenticatie- of databasecode op het moment van het verzoek een server nodig heeft, gebruik dan een server-side host. Bewaar op een gratis app-host persistente data in duurzame opslag in plaats van aan te nemen dat het lokale bestandssysteem van de app het overleeft.

Delen

Discussie

Reacties

Log in om mee te praten.

Meer van de blog

Blijf lezen.

Klaar om uit te rollen? Vanaf $2,48/mnd.

Onafhankelijke cloud, sinds 2008. AMD EPYC, NVMe, 40 Gbps. 14 dagen niet-goed-geld-terug.