Gå til hovedindhold
50% rabat alle planer, tidsbegrænset. Fra $2.48/mo
17 min left
Udviklerværktøjer og DevOps

Sådan gør du localhost-apps offentligt tilgængelige uden en VPS

B Af Bill 17 min læsning
Titelkort „Gør localhost offentlig uden en VPS“: en lokal app på en bærbar spreder sig gennem en tunnel til en telefon, et browservindue og et hjemmenetværk

Din app kører. Du startede dev-serveren, åbnede http://localhost:3000, og den gør, hvad den skal. Så beder nogen om et link, og du opdager, at URL'en på din skærm ikke betyder noget for andre end dig.

Der er tre måder at give en localhost-app en offentlig URL på uden en VPS, plus én hurtigere mulighed, når den anden person er på dit lokale netværk, og valget mellem dem er ikke et værktøjsspørgsmål. Det er et spørgsmål om, hvor længe tingen skal være tilgængelig, og om den kan køre et andet sted end på din bærbare. Herunder får du hver vej, kommandoen, der giver en URL, og præcis det, der får den URL til at holde op med at virke.

TL;DR

  • Nogen på dit wi-fi skal se den: bind dev-serveren til alle netværksinterfaces og giv din LAN-IP videre. Klar på sekunder, død i det øjeblik din gæst forlader dit netværk.
  • Du skal bruge et link, alle kan åbne den næste times tid: kør en tunnel (cloudflared, ngrok, localtunnel, localhost.run). Offentlig HTTPS-URL på cirka et minut, ingen ændringer i routeren, og den dør sammen med den proces, der startede den.
  • Den skal blive kørende, mens din bærbare er lukket: skub appen til et gratis hostingniveau. Det afkobler appen fra din bærbare og indfører nye regler om kreditkort, kommerciel brug, og om dine data overlever en genstart.
  • Din app har ikke brug for serverkode på forespørgselstidspunktet: byg den og læg det statiske output på en statisk host. Den kan blive online uden din bærbare og har ingen app-proces, der skal vækkes, så længe hostens konto og forbrugsgrænser stadig passer.
  • Én standardindstilling, der er værd at kende: next dev og python -m http.server lytter allerede på alle netværksinterfaces uden noget flag. Hvis du gik ud fra, at din dev-server var privat og kun for din bærbare, så er den det ikke.

Hvilken vej passer til din app

Beslutningsdiagram fra din lokale app til én af fire veje: kun LAN, offentlig tunnel, app-host eller statisk build, med opsætningstid, om den bærbare må være slukket, og hvad hver vej egner sig bedst til

Tre af disse fire veje giver din app en offentlig internet-URL; den første når kun dit eget netværk, hvilket gør den både den hurtigste og den mest begrænsede. Sortér dem efter, hvor længe URL'en skal overleve, og valget giver stort set sig selv.

VejTid til en URLHvor længe den holderHvad der dræber denHvem den er til
Samme netværkSekunderSå længe I begge er på netværketDin gæst skifter til et andet wi-fiEn kollega ved nabobordet, eller din egen telefon
TunnelCirka et minutSå længe processen kørerAt lukke den bærbare, dræbe terminalen, ramme niveauets lofterEn demo, en kundegennemgang, en webhook-test
Gratis hostingniveau10 til 30 minutterPå ubestemt tid, med betingelserSpin-down, et flygtigt filsystem eller planens vilkårNoget, der skal svare, mens du sover
Statisk build10 til 20 minutterPå ubestemt tidAt få brug for serverkode på forespørgselstidspunktetApps, der kan genereres fuldt ud ved build eller køre på klientsiden

Hvilke rækker der er åbne for dig, afhænger af tre ting, du kan tjekke i dit eget projekt:

  • Har appen brug for, at din serverkode kører på forespørgselstidspunktet? En Flask- eller FastAPI-rute, et server.js -endpoint eller forespørgselsspecifik serverlogik kræver en server-side host. Serverkode ved build udelukker ikke automatisk en statisk udrulning: Next.js Server Components kan køre under next build, og statiske GET Route Handlers kan prerenderes. Hvis hver runtime-forespørgsel kan serveres som statiske assets eller sendes direkte fra browseren til et eksternt API, er den statiske vej stadig åben.
  • Læser eller skriver den en fil, den skal beholde? En databasefil (.db, .sqlite), en upload-mappe, en JSON-fil, den redigerer. Hvis ja, så tjek hostens lagringsmodel, før du udruller. Renders gratis webservices og Koyebs gratis instanser bruger flygtigt lokalt lager, mens Vercel Functions har et skrivebeskyttet filsystem med midlertidig /tmp -plads. Læg vedvarende tilstand i et varigt volume, en database eller et objektlager i stedet for at antage, at appens lokale disk overlever.
  • Har den brug for en hemmelighed ved runtime? En nøgle i en .env -fil virker uændret på de to første veje, da appen stadig kører på din maskine. På de to andre indtaster du den igen i udbyderens miljøindstillinger, og den må ikke ligge i det repo, du pusher.

Del den på dit eget netværk

next dev lytter allerede på alle netværksinterfaces på din maskine (det er alt, hvad 0.0.0.0 betyder, når du ser det), og det samme gør python -m http.server. Ingen af dem har brug for et flag, så den dev-server, du har kørende lige nu, er sandsynligvis allerede tilgængelig fra din telefon på samme wi-fi.

Next.js dokumenterer -H som måden at ændre dette hostnavn på, med en standardværdi på 0.0.0.0, og Pythons dokumentation siger, at modulet binder sig til alle interfaces , medmindre du angiver --bind 127.0.0.1. Det gør dette til den hurtigste måde at dele en localhost-app på: ingen konto, ingen installation, ingen udrulning. De andre almindelige dev-servere skal have besked.

# 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

Vites dokumentation: server.host har som standard localhost, og tager --host på kommandolinjen eller server.host: '0.0.0.0' i konfigurationsfilen. Uvicorn bruger som standard 127.0.0.1, hvilket dækker FastAPI, da det er det, der kører den. Streamlit lader server.address stå tom, og dens konfigurationsreference bemærker, at at sætte den begrænser adgangen til netop den ene adresse: tom betyder ubegrænset.

Så skal du bruge den adresse, du giver videre. Det er din maskines egen IP på det lokale netværk, ikke localhost:

# macOS
ipconfig getifaddr en0

# Linux
hostname -I

# Windows (PowerShell)
ipconfig | findstr IPv4

Giv din gæst http://<that-address>:3000 og de er inde. Hagen er formen på hele vejen: den adresse betyder ingenting uden for dit netværk. I det sekund de er på et andet wi-fi, på mobildata eller derhjemme, er linket dødt for dem.

Bemærk: hvis kommandoen kører fint, og den anden enhed stadig ikke kan forbinde, er det næsten hver gang styresystemets firewall, ikke kommandoen. Apples firewall-dokumentation siger, at macOS viser en advarsel for en app, du ikke har tilladt, og afviser forbindelsen, indtil du handler. Windows spørger i stedet, hvilken netværksprofil der gælder, og holder separate regler for private og offentlige netværk. Vælg Privat på et hjemme- eller kontornetværk. Aldrig Offentlig.

Læg den bag en tunnel

En tunnel er et lille program, der kører ved siden af din app og giver den en offentlig HTTPS-adresse. Én kommando giver dig en gratis tunnel til localhost på cirka et minut, og det er værd at vide på forhånd, at URL'en dør i det øjeblik, kommandoen gør det:

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

Intet ændrer sig på din router på grund af den retning, forbindelsen går i. Din maskine åbner en udgående forbindelse til udbyderens edge, samme slags som din browser laver for at indlæse en hvilken som helst side, og udbyderen holder den åben og skubber indgående forespørgsler tilbage gennem den. Indgående porte på din side forbliver lukkede, og derfor virker det på hotel-wi-fi, på et telefon-hotspot og på en hjemmeforbindelse, hvis router du ikke kontrollerer.

Bemærk: det sidste tilfælde fortjener et tres sekunders tjek, før du overvejer portviderestilling i stedet. Åbn routerens statusside, find den WAN-IP, den rapporterer, og sammenlign den med din faktiske offentlige IP fra et hvilket som helst „hvad er min IP“-opslag. Hvis WAN-IP'en ligger inden for 100.64.0.0/10, er CGNAT den sandsynlige årsag. Hvis WAN-IP og offentlig IP bare er forskellige, ved du, at der er endnu et NAT-lag opstrøms, men det kan være CGNAT eller almindelig dobbelt NAT. I begge tilfælde er portviderestilling på denne router alene måske ikke nok. Det interval er reserveret af RFC 6598 som delt adresserum, hvilket er det, din udbyder placerer dig bag, når den løber tør for adresser.

Mulighederne adskiller sig mest i, hvad de vil have fra dig først.

Cloudflare quick tunnels er kommandoen ovenfor: ingen konto, intet domæne, et tilfældigt trycloudflare.com -underdomæne. Cloudflare begrænser dem til 200 igangværende forespørgsler og returnerer 429 derover, understøtter ikke Server-Sent Events og siger i samme dokumentation, at gratis tunneler er til test og udvikling, ikke til at udrulle et produktionswebsted.

ngrok kræver først en tilmelding, derefter ngrok http 3000. Den nuværende gratis plan giver dig $5 i engangsforbrug, der ikke fornyes månedligt, op til 3 online endpoints, 1 GB overførsel, 20.000 HTTP/S-forespørgsler og en mellemliggende advarselsside, din gæst skal klikke sig igennem. Du får også et gratis, automatisk tildelt udviklingsdomæne, som ngrok annoncerede i 2023 for at gøre op med den gamle klage over, at URL'en skiftede ved hver genstart.

localtunnel kræver ingen tilmelding og ingen installation ud over npx: npx localtunnel --port 3000. Du får et tilfældigt underdomæne, og README'en siger udtrykkeligt, at --subdomain beder om et navn uden at garantere det.

localhost.run installerer ingenting, fordi den bruger den SSH-klient, dit styresystem allerede leverer: ssh -R 80:localhost:3000 localhost.run. Dokumentationen bemærker, at ingen download er nødvendig og at der ikke kræves nogen kontooprettelse for gratis domæner.

VS Code har dette i Ports-panelet, praktisk hvis du alligevel bor i editoren. Den kræver et GitHub- eller Microsoft-login, og standardindstillingen vil spænde ben for dig: en viderestillet port er Privat, hvilket betyder, at din gæst bliver bedt om at logge ind med din konto, indtil du skifter porten til Offentlig. (Fint til en kollega. Ubrugeligt til den kunde, der bare vil klikke på et link.)

Tailscale Funnel kan også dette, med to begrænsninger, der som regel afgør sagen: URL'en kan kun ligge på dit eget tailnets domæne, og den kan kun lytte på portene 443, 8443 og 10000.

Uanset hvad du vælger, så vær klar over, hvad du har delt ud. Med en offentlig tunnel uden adgangskontrol er alt, hvad dev-serveren serverer, tilgængeligt for enhver med den URL, inklusive ruter, du aldrig har linket til, og enhver debug-grænseflade, du har ladet stå tændt. Fint til en demo på et kvarter. Langt mindre fint til en URL, du sætter ind i en offentlig Discord.

Udløbet kommer bag på dig, fordi det kan ligne, at appen er gået i stykker. De fleste af de hurtige veje her afhænger stadig af tunnelsoftware, der kører på din bærbare: stop cloudflared, ngrok, localtunnel eller localhost.run-SSH-sessionen, og viderestillingen stopper. Tailscale Funnel er undtagelsen, når du kører den med --bg, som holder Funnel-konfigurationen kørende i baggrunden og genopretter den efter en genstart. Ingen af dem kan servere din lokale app, mens selve den bærbare er offline. Du kan lade en tunnel køre i dagevis, og den virker lige indtil låget lukkes, eller du rammer forespørgselsloftet.

En tunnel er det rigtige værktøj til en demo og det forkerte værktøj til hosting: dens oppetid er din bærbares oppetid.

Lad appen forlade din maskine

Det er den første vej, hvor din bærbare holder op med at være bærende, og den første, hvor vilkårene betyder mere end værktøjet. Det, der afslutter det her, er ikke et ur. Det er en spin-down, en nulstilling af filsystemet eller en plan, der beslutter, at din app ikke er den slags, den vil have på en gratis instans.

Mulighederne herunder spænder fra løbende gratis planer til korte prøveperioder. Nogle kan holde en app online på ubestemt tid inden for deres grænser; andre stopper efter en fast prøveperiode eller kræver en betalt konto til compute. Tjek reglerne for fakturering, dvale og lagring, før du udruller.

Vilkårene for de gratis niveauer herunder blev tjekket mod hver udbyders egen pris- eller dokumentationsside den 7. september 2026.

LeverandørKommerciel brug?Overlever data en genstart?Hagen
NetlifyTilladtJa, med Netlify Blobs eller DatabaseIntet kort for at starte; bruger du alle månedens Free-plan-kreditter, sættes projekter på pause indtil næste faktureringsperiode, medmindre du opgraderer
RenderIkke angivetGår tabt ved genstartIntet kort for at starte; går i dvale efter 15 minutters inaktivitet; gratis Postgres udløber 30 dage efter oprettelse
Cloudflare Pages / WorkersIkke angivetJa, med KV, D1, R2 eller Durable Objects500 Pages-builds om måneden; gratis Workers er 100.000 forespørgsler om dagen
VercelIkke på HobbyGår tabt ved genstartHobby er kun til personlig brug; funktionernes filsystem er skrivebeskyttet
GitHub PagesIkke tilladtKun statisk outputIngen onlineforretning, e-handel eller kommerciel SaaS; 10 minutters timeout ved udrulning
PythonAnywhereIkke angivetJaGratis konti når kun en allowlist af eksterne hosts; den gratis webapp udløber efter en måned , medmindre den fornyes
Fly.ioIkke angivetJa, med et Fly VolumeIntet løbende gratis niveau: 2 maskintimer eller 7 dage; prøve-Machines stopper automatisk efter 5 minutters kørsel, og prøveperioden inkluderer 20 GB volume-lager; apps stopper, når prøveperioden slutter, indtil du tilføjer et kort
KoyebIkke angivetIntet varigt lokalt lagerKort påkrævet; Koyeb foretager og annullerer en forhåndsgodkendelse på $29, men tilmeldingen vælger Pro som standard og opkræver dens forholdsmæssige pris, medmindre du skifter til Starter
Hugging Face SpacesIkke angivetGår tabt ved genstartStatic Spaces er gratis; Gradio og Docker kræver generelt en betalt plan, men berettigede gratis personlige konti kan hoste op til to Gradio Spaces på ZeroGPU
RailwayIkke angivetJa, hvis appen bruger det inkluderede volume på 0,5 GB30 dages prøveperiode med $5 i engangskredit, derefter en Free-plan til $0 med $1 i ressourcekredit om måneden; intet kort påkrævet

„Ikke angivet“ betyder, at udbyderens egne sider ikke svarer på spørgsmålet for deres gratis niveau. Behandl det som ukendt snarere end som et ja eller et nej.

Tre af de rækker fortjener et ekstra kig, før du går i gang. Fly.io har intet løbende gratis niveau: prøveperioden slutter efter 2 maskintimer eller 7 dage. Koyeb har en gratis instans, men tilmeldings- og faktureringsforløbet kræver opmærksomhed, før du udruller. Hugging Face holder Static Spaces gratis, mens nye Gradio- og Docker-Spaces kræver en betalt konto, bortset fra den begrænsede ZeroGPU-undtagelse. Railway hører ikke længere til på denne advarselsliste: efter prøveperioden på 30 dage med $5 i kredit går den nu over til en Free-plan til $0 med $1 i ressourcekredit om måneden.

Så er der dataspørgsmålet, hvor en fungerende app stille og roligt bliver til en ødelagt. Renders gratis webservices kører på et flygtigt filsystem, og dokumentationen er ligefrem: alt, hvad der skrives der, uploadede billeder og lokale SQLite-databaser udtrykkeligt inkluderet, går tabt ved hver ny udrulning, genstart og spin-down. Vercels funktioner kører på et skrivebeskyttet filsystem med kun et midlertidigt arbejdsområde, så en SQLite-fil, din app skriver, er heller ikke sikker der. Hvis din app gemmer tilstand i en fil, så flyt den til varigt lager: en hostet database, et objektlager eller et vedvarende volume, hvor platformen tilbyder et.

Spin-down er værd at mærke, før du binder dig. På Renders gratis niveau sender 15 minutters inaktivitet tjenesten i dvale, og den næste forespørgsel vækker den over cirka et minut med en indlæsningsside for den, der klikkede på dit link. For et portfoliostykke et skuldertræk. For en kunde, der åbner linket under et opkald, tres dårlige sekunder.

PythonAnywhere har en mere subtil version af fælden. Der er ingen spin-down ved inaktivitet, men en gratis webapp udløber efter en måned og stopper, medmindre du klikker på det fornyelseslink, PythonAnywhere sender dig på mail, og gratis konti får begrænset udgående internetadgang og når kun en allowlist af eksterne hosts. En app, der kalder et API uden for den liste, står der og er helt online og fejler ved hver forespørgsel til det ikke-tilladte API (en forfærdelig ting at debugge, da intet nogen steder ser nede ud).

Udgiv den som statisk site

Hvis intet af det, din app gør, kræver serverkode på forespørgselstidspunktet, er en statisk host den mulighed her, der kommer tættest på „sæt op og glem“: den kan blive online uden din bærbare, og der er ingen app-proces, der venter på at blive vækket. Hostens konto og forbrugsgrænser gælder stadig. Flere apps kvalificerer sig, end du ville forvente, og derfor er det første af de tre spørgsmål værd at besvare, før du antager, at du har brug for en server-side host.

Reglen er snævrere end „har den en backend“. Din app kvalificerer sig, hvis hver forespørgsel, den laver, enten går til dine egne statiske filer eller direkte fra browseren til en andens API. At hente fra Supabase eller et offentligt API fra browseren er fint, med det ene forbehold, at en nøgle i browserkode er en nøgle, du har offentliggjort. Det, der lukker døren, er behovet for, at din egen kode kører på en server ved hver forespørgsel.

Hvis den kvalificerer sig, er fremgangsmåden kort:

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

Udrul derefter det build-output til en statisk host. Cloudflare Pages, Netlify og Vercel kan bygge fra et forbundet repo. GitHub Pages kan udgive statiske filer fra en branch eller bruge GitHub Actions til at køre dit frameworks build og udrulle det genererede output.

GitHub Pages har begrænsninger, der er skarpe nok til at betyde noget fra starten. Kun statisk, ét bruger- eller organisations-site pr. konto, og forbrugsgrænser, der fastslår, at det ikke er gratis hosting til en forretning, et e-handelssite eller kommerciel SaaS. Hvis din app skal tage imod betalinger, udelukker det den, før du går i gang.

Denne vej har ingen udløb af app-processen. Den bliver ved med at virke, så længe hostingkontoen er aktiv og inden for sine grænser, og den holder op med at passe, så snart appen har brug for server-side arbejde på forespørgselstidspunktet.

Hvor de gratis veje ender

De gratis veje fejler forskellige steder, ikke alle på én gang. En statisk host løser allerede den bærbares oppetid og giver dig en stabil udbyder-URL. En gratis app-host kan det samme, og nogle inkluderer nu vedvarende lager. En VPS begynder at give mening, når kravene hober sig op: din egen server-side proces skal forblive online, du har brug for forudsigeligt vedvarende lager, og den gratis plans ressource- eller forbrugsregler passer ikke længere.

Den tærskel er værd at respektere. Én demo er ikke en grund til at købe en server, og det er et statisk projekt med lav trafik heller ikke. Bliv på en tunnel til kortvarig deling, bliv på en statisk host, så længe appen reelt er statisk, og bliv på en gratis app-host, så længe dens grænser passer til det, du kører.

Skift til en VPS, når du har brug for en altid-tændt server, du selv kontrollerer, og du er villig til at påtage dig det driftsarbejde, der følger med. Vores Linux VPS er én mulighed, og en tilsvarende VPS fra en anden udbyder kan gøre det samme arbejde. Dimensionér serveren til appen i stedet for at antage, at den mindste plan er nok.

Se Linux-planer

Byg på en Linux VPS med root-adgang, NVMe og AMD EPYC-kraft.

Se Linux-planer

To ting ændrer sig, når du gør det. Det push-til-git-udrulningsflow, en platformshost gav dig, er ikke længere automatisk. Du kan genskabe det med en self-hosted PaaS som Coolify eller Dokku, eller bygge din egen CI/CD-vej, og uanset hvad ejer du nu opdateringer og vedligeholdelse.

Den anden ændring er, at maskinen rummer mere end appen. Den vil med glæde køre Code Server og Claude Code , hvis du hellere vil have din editor til at bo der også, hvilket enten er en fin bonus eller en helt ny weekend, alt efter dig.

Ofte stillede spørgsmål

Hvorfor holdt min offentlige URL op med at virke, efter jeg lukkede min bærbare?

Fordi tunnelen var bundet til den proces, der oprettede den, ikke til din app. At lukke den bærbare eller dræbe terminalen afslutter den proces, den offentlige URL dør, og din app har det fint. Genstarter du tunnelen, får du en ny URL, medmindre værktøjet tildeler dig et reserveret domæne. Hvis linket skal overleve, at din bærbare går i dvale, skal appen forlade din maskine.

Har jeg brug for et domænenavn for at lægge en lokal app på en offentlig URL?

Nej, i næsten alle tilfælde. En Cloudflare quick tunnel, ngroks tildelte udviklingsdomæne, localtunnel, localhost.run og de gratis hostingniveauer ovenfor tildeler dig alle gratis et underdomæne på deres eget domæne. Undtagelsen er en Cloudflare named tunnel, som kræver et domæne, du allerede har føjet til Cloudflare DNS.

Kan nogen på et andet wi-fi-netværk åbne min lokale IP-adresse?

Nej. En adresse som 192.168.1.42 peger på den enhed, der tilfældigvis har den på det netværk, du er på lige nu, hvilket på ethvert andet netværk er en anden enhed eller slet ingenting. Alle uden for dit wi-fi har i stedet brug for en tunnel, et gratis hostingniveau eller en statisk host.

Hvilke af disse virker, hvis min app har login og en database?

Samme netværk- og tunnelvejene virker uændret, fordi appen stadig kører på din maskine. En statisk udrulning kan også virke, hvis login- og databaseforespørgsler går direkte fra browseren til en hostet tjeneste, og ingen privat server-side kode skal køre ved hver forespørgsel. Hvis din egen autentificerings- eller databasekode har brug for en server på forespørgselstidspunktet, så brug en server-side host i stedet. På en gratis app-host skal du holde vedvarende data i varigt lager i stedet for at antage, at appens lokale filsystem overlever.

Del

Diskussion

Kommentarer

Log ind for at deltage i diskussionen.

Mere fra bloggen

Læs videre.

Klar til at udrulle? Fra 2,48 $/md.

Uafhængig cloud siden 2008. AMD EPYC, NVMe, 40 Gbps. 14 dages pengene-tilbage-garanti.