跳至主要内容
五折优惠 全部方案,限时优惠。起价 $2.48/mo
17 min left
开发者工具与 DevOps

如何在没有 VPS 的情况下公开部署 localhost 应用

B 作者 Bill 17 分钟阅读
「无需 VPS 公开部署 localhost」标题卡:笔记本上的本地应用通过一条隧道分别延伸到手机、浏览器窗口和家庭网络

你的应用跑起来了。你启动了开发服务器,打开 http://localhost:3000,它也按预期工作。然后有人问你要一个链接,你才发现屏幕上的这个 URL 对除你之外的任何人都毫无意义。

在没有 VPS 的情况下,给 localhost 应用一个公开 URL 有三种方法,另外当对方就在你的本地网络里时还有一个更快的选项。在它们之间做选择并不是工具问题,而是这个应用需要保持可访问多久、以及它能否在你的笔记本之外运行的问题。下面逐一介绍每条路径、获得 URL 的命令,以及会让这个 URL 失效的确切原因。

TL;DR(太长不看版)

  • 同一 Wi-Fi 下的人需要看: 把开发服务器绑定到所有网络接口,然后把你的局域网 IP 交出去。几秒钟就绪,访客一离开你的网络就失效。
  • 你需要一个接下来一小时内任何人都能打开的链接: 运行一条隧道(cloudflared、ngrok、localtunnel、localhost.run)。大约一分钟就能得到公开的 HTTPS URL,无需改动路由器,但它会随着启动它的进程一起消失。
  • 笔记本合上后它也得继续在线: 把应用推到免费托管套餐上。这样应用就与你的笔记本脱钩了,但也带来了新规则:信用卡、商业用途,以及你的数据能否在重启后保留。
  • 你的应用在请求时不需要服务器代码: 构建它,把静态产物放到静态托管上。它可以在没有你笔记本的情况下保持在线,也没有需要唤醒的应用进程,只要托管方的账户和用量限制仍然合适。
  • 一个值得知道的默认行为: next devpython -m http.server 在不加任何参数的情况下,就已经在监听所有网络接口。如果你以为开发服务器只对自己的笔记本可见,那你想错了。

哪条路径适合你的应用

从你的本地应用出发、通往四条路径之一的决策流程图:仅限 LAN、公开隧道、应用托管或静态构建,并标注了设置时间、笔记本能否关机,以及各自最适合的用途

这四条路径中有三条能给你的应用一个公开的互联网 URL;第一条只能到达你自己的网络,这让它既最快也最受限。按 URL 需要存活多久来排序,选择基本就自然明了了。

路径获得 URL 所需时间能持续多久什么会让它失效适合谁
同一网络几秒钟只要你们都在这个网络里访客换到了另一个 Wi-Fi隔壁工位的同事,或者你自己的手机
隧道大约一分钟只要进程在运行合上笔记本、关掉终端、触到套餐上限一次演示、一次客户讲解、一次 webhook 测试
免费托管套餐10 到 30 分钟无限期,但有条件闲置休眠、临时文件系统,或套餐条款在你睡觉时也必须响应的东西
静态构建10 到 20 分钟无限期在请求时需要服务端代码能在构建时完整生成、或在客户端运行的应用

哪些行对你开放,取决于三件你可以在自己项目里检查的事:

  • 应用在请求时需要运行你的服务器代码吗? 一个 Flask 或 FastAPI 路由、一个 server.js 端点,或任何随请求变化的服务器逻辑,都需要服务端托管。构建时的服务器代码并不自动排除静态部署:Next.js 的 Server Components 可以在 next build期间运行,静态的 GET Route Handler 也可以预渲染。如果运行时的每个请求都能作为静态资源提供,或者直接从浏览器发送到外部 API,静态路径就仍然可行。
  • 它是否读写需要保留的文件? 数据库文件(.db, .sqlite)、上传目录、它会编辑的 JSON 文件。如果有,部署前先查看托管方的存储模型。Render 的免费 Web 服务和 Koyeb 的免费实例使用临时本地存储,而 Vercel Functions 的文件系统是只读的,只有临时的 /tmp 空间。把持久状态放进持久卷、数据库或对象存储,而不是假设应用的本地磁盘能保留下来。
  • 它在运行时需要密钥吗? 前两条路径中, .env 文件里的密钥可以原样使用,因为应用仍然运行在你的机器上。另外两条路径则需要你在服务商的环境设置里重新填写,而且它绝不能出现在你推送的仓库里。

在你自己的网络里分享

next dev 已经在监听你机器上的所有网络接口(你看到的 0.0.0.0 就是这个意思), python -m http.server也一样。两者都不需要参数,所以你此刻正在运行的开发服务器,很可能已经能从同一 Wi-Fi 下的手机访问了。

Next.js 的文档把 -H 记为修改这个主机名的方式, 默认值为 0.0.0.0;Python 的文档则说该模块会 绑定到所有接口 ,除非你传入 --bind 127.0.0.1。这让它成为分享 localhost 应用最快的方式:不用账号、不用安装、不用部署。其他常见的开发服务器则需要明确告知。

# 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

Vite 的文档: server.host 的默认值是 localhost,并且在命令行接受 --host ,或在配置文件中接受 server.host: '0.0.0.0'Uvicorn 的默认值是 127.0.0.1,这也覆盖了 FastAPI,因为 FastAPI 正是由它运行的。Streamlit 把 server.address 留空,其配置参考指出 设置它会限制访问 ,只允许那一个地址:不设置就意味着不限制。

接下来你需要一个可以交出去的地址。那是你机器在本地网络上的自身 IP,而不是 localhost:

# macOS
ipconfig getifaddr en0

# Linux
hostname -I

# Windows (PowerShell)
ipconfig | findstr IPv4

http://<that-address>:3000 交给访客,他们就能进来了。问题出在整条路径的形态上:这个地址在你的网络之外没有任何意义。一旦对方换到另一个 Wi-Fi、切到蜂窝网络或者回到家,这个链接对他们来说就失效了。

注意: 如果命令运行正常,另一台设备却仍然连不上,几乎每次都是操作系统的防火墙在作怪,而不是命令本身。Apple 的防火墙文档说,macOS 会对尚未允许的应用弹出提示,并 在你处理之前拒绝连接。Windows 则会询问适用哪个网络配置文件,并为 专用网络和公用网络保留各自独立的规则 。在家庭或办公室网络里选「专用」。永远不要选「公用」。

把它放到隧道后面

隧道是一个和你的应用并排运行的小程序,它会给应用一个公开的 HTTPS 地址。一条命令就能在大约一分钟内获得通往 localhost 的免费隧道,但你需要提前知道:这条命令一停,URL 就跟着消失:

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

你的路由器不需要任何改动,原因在于连接的方向。你的机器向服务商的边缘节点发起一个出站连接,和浏览器加载任何网页时发起的连接是同一种,服务商保持这个连接打开,并把入站请求顺着它推回来。你这一侧的入站端口始终关闭,所以它在酒店 Wi-Fi、手机热点,以及你无法控制路由器的家庭网络上都能用。

注意: 最后这种情况值得你花六十秒检查一下,再考虑改用端口转发。打开路由器的状态页面,找到它报告的 WAN IP,再用任意「我的 IP 是多少」服务查一下你真实的公网 IP 并作比较。如果 WAN IP 落在 100.64.0.0/10范围内,那很可能是 CGNAT。如果 WAN IP 和公网 IP 只是不一致,你能确定上游还有一层 NAT,但那可能是 CGNAT,也可能是普通的双重 NAT。无论哪种情况,只在这台路由器上做端口转发都可能不够。这个地址段 由 RFC 6598 预留为共享地址空间,也就是运营商在地址用尽时把你放到其后面的那个地址段。

各个选项的差别主要在于它们一开始向你要什么。

Cloudflare 快速隧道 就是上面那条命令:不用账号、不用域名,会得到一个随机的 trycloudflare.com 子域名。Cloudflare 将其限制为 200 个并发请求,超出则返回 429,不支持 Server-Sent Events,并在同一份文档中说明免费隧道只用于测试和开发,不用于部署生产网站。

ngrok 需要先注册,然后运行 ngrok http 3000. 当前的免费套餐 提供 5 美元的一次性包含用量(不会按月刷新)、最多 3 个在线端点、1 GB 流量、20,000 次 HTTP/S 请求,以及一个访客必须点击通过的中间警告页。你还会得到一个自动分配的免费开发域名,这是 ngrok 在 2023 年宣布的 ,目的就是解决每次重启 URL 都会变的老问题。

localtunnel 不需要注册,除了 npx 之外也不需要安装任何东西: npx localtunnel --port 3000。你会得到一个随机子域名,README 明确说明 --subdomain 只是申请一个名字,并不保证能拿到.

localhost.run 什么都不用安装,因为它用的是你操作系统自带的 SSH 客户端: ssh -R 80:localhost:3000 localhost.run。它的文档指出 无需下载 ,免费域名也不需要设置账号。

VS Code 在 Ports 面板里提供了这个功能,如果你本来就常驻编辑器,会很顺手。它需要用 GitHub 或 Microsoft 账号登录,而默认设置会让你栽跟头: 转发的端口默认是私有的,这意味着在你把端口切换为公开之前,访客会被要求用你的账号登录。(给队友用没问题。给只想点个链接的客户用则毫无用处。)

Tailscale Funnel 也能做到,但有两个通常起决定作用的限制:URL 只能放在你自己的 tailnet 域名下,而且它只能 监听 443、8443 和 10000 端口.

无论选哪个,都要清楚自己交出去的是什么。对于没有访问控制的公开隧道,开发服务器提供的一切都能被任何持有该 URL 的人访问到,包括你从未链接过的路由,以及你忘了关掉的调试界面。用于一场十五分钟的演示没问题。贴到公开 Discord 里的 URL 就远没那么合适了。

过期之所以让人措手不及,是因为它看起来像应用坏了。这里大多数快捷方案仍然依赖运行在你笔记本上的隧道软件:停掉 cloudflared、ngrok、localtunnel 或 localhost.run 的 SSH 会话,转发就停止了。Tailscale Funnel 是个例外,如果你用 --bg运行它,Funnel 配置会在后台持续运行,并在重启后恢复。但只要笔记本本身离线,这些方案都无法继续提供你的本地应用。你可以让隧道连续运行好几天,它会一直工作,直到合上盖子或触到请求上限为止。

隧道是演示的正确工具,却是托管的错误工具:它的在线时长就是你笔记本的在线时长。

让应用离开你的机器

这是第一条你的笔记本不再是承重墙的路径,也是第一条条款比工具更重要的路径。在这里让一切结束的不是计时器,而是闲置休眠、文件系统重置,或者套餐方判定你的应用不是他们想放在免费实例上的那种东西。

下面的选项从长期免费套餐到短期试用都有。有些能在限额内让应用无限期在线;有些则在固定试用期后停止,或者需要付费账户才能获得算力。部署前先查清计费、休眠和存储规则。

下面的免费套餐条款,已于 2026 年 9 月 7 日对照各服务商自己的定价或文档页面核对过。

提供商商业用途?数据能在重启后保留吗?坑在哪
Netlify允许能,配合 Netlify Blobs 或 Database无需绑卡即可开始;用完 Free 套餐的当月额度后,项目会暂停到下一个计费周期,除非升级
Render未说明重启即丢失无需绑卡即可开始;闲置 15 分钟后休眠;免费 Postgres 在创建 30 天后过期
Cloudflare Pages / Workers未说明能,配合 KV、D1、R2 或 Durable ObjectsPages 每月 500 次构建;Workers 免费版为 每天 100,000 次请求
VercelHobby 不允许重启即丢失Hobby 仅限个人用途;函数的文件系统为只读
GitHub Pages不允许仅限静态产物不得用于在线业务、电商或商业 SaaS;部署超时为 10 分钟
PythonAnywhere未说明免费账户只能访问白名单内的外部主机; 免费 Web 应用一个月后过期 ,除非续期
Fly.io未说明能,配合 Fly Volume没有长期免费套餐:2 个机器小时或 7 天;试用 Machine 运行 5 分钟后自动停止,试用包含 20 GB 卷存储;试用结束后应用会停止,直到你添加银行卡
Koyeb未说明没有持久的本地存储必须绑卡;Koyeb 会做一笔 29 美元的预授权并随即取消,但注册时默认选中 Pro,并按比例收取其费用,除非你切换到 Starter
Hugging Face Spaces未说明重启即丢失Static Spaces 免费;Gradio 和 Docker 通常需要付费套餐,但符合条件的免费个人账户可以在 ZeroGPU 上托管最多两个 Gradio Space
Railway未说明能,前提是应用使用附带的 0.5 GB 卷30 天试用,含一次性 5 美元额度,之后转为 0 美元的 Free 套餐,每月 1 美元资源额度;无需绑卡

「未说明」指服务商自己的页面没有就其免费套餐回答这个问题。请把它当作未知,而不是「是」或「否」。

其中三行在开始前值得再多看一眼。Fly.io 没有长期免费套餐:试用在 2 个机器小时或 7 天后结束。Koyeb 包含一个免费实例,但它的注册和计费流程在部署前需要留意。Hugging Face 保留了免费的 Static Spaces,而新建的 Gradio 和 Docker Space 除了有限的 ZeroGPU 例外之外都需要付费账户。Railway 已经不再属于这份警示名单:在含 5 美元额度的 30 天试用之后,它现在会转为 0 美元的 Free 套餐,每月 1 美元资源额度。

接着是数据问题,一个能正常运行的应用往往就是在这里悄无声息地坏掉的。Render 的免费 Web 服务运行在临时文件系统上,其文档直言不讳:写到那里的任何内容,明确包括上传的图片和本地 SQLite 数据库,都会在每次重新部署、重启和休眠时丢失。Vercel 的函数运行在只读文件系统上,只有一个临时的暂存空间,所以你的应用写入的 SQLite 文件在那里同样不安全。如果你的应用把状态保存在文件里,就把它迁移到持久存储:托管数据库、对象存储,或者平台支持的持久卷。

在做决定之前,值得亲身感受一下休眠。在 Render 的免费套餐上,闲置 15 分钟服务就会进入休眠,下一次请求要 大约一分钟才能唤醒它,期间会显示一个加载页面 给点了你链接的人看。对作品集项目来说,耸耸肩就过去了。对一个在通话中打开链接的客户来说,那是糟糕的六十秒。

PythonAnywhere 的坑更隐蔽一些。它没有闲置休眠,但免费 Web 应用有一个月的有效期,除非你点击 PythonAnywhere 通过邮件发来的续期链接,否则会停止;此外免费账户的 出站互联网访问受限 ,只能访问白名单内的外部主机。一个调用白名单外 API 的应用会好端端地保持在线,却对那个未获允许的 API 的每次请求都失败(调试起来相当折磨,因为哪里看起来都没坏)。

作为静态站点发布

如果你的应用所做的一切都不需要在请求时运行服务器代码,那么静态托管就是这里最接近「配置一次就不用管」的选项:它可以在没有你笔记本的情况下保持在线,也没有等待被唤醒的应用进程。托管方的账户和用量限制仍然适用。符合条件的应用比你想象的多,这也是为什么在假定自己需要服务端托管之前,值得先回答那三个问题中的第一个。

这条规则比「它有没有后端」更窄。只要你的应用发出的每个请求,要么指向你自己的静态文件,要么直接从浏览器发往别人的 API,它就符合条件。从浏览器请求 Supabase 或公开 API 没有问题,只有一点要注意:放在浏览器代码里的密钥就是你已经公开的密钥。真正关上这扇门的,是需要为每个请求在服务器上运行你自己的代码。

如果符合条件,流程很短:

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

然后把构建产物部署到静态托管上。Cloudflare Pages、Netlify 和 Vercel 都可以从关联的仓库直接构建。GitHub Pages 可以从某个分支发布静态文件,或者用 GitHub Actions 运行你框架的构建并部署生成的产物。

GitHub Pages 的限制足够明确,值得一开始就考虑。仅限静态,每个账户只能有一个用户或组织站点,并且其使用限制明确指出它 不是给企业用的免费托管,也不适用于电商站点或商业 SaaS。如果你的应用要收款,那在开始之前就被排除了。

这条路径没有应用进程过期的问题。只要托管账户保持活跃且在限额之内,它就会一直工作;一旦应用在请求时需要服务端处理,它就不再合适了。

免费路径的尽头在哪里

免费路径不是同时失效,而是各自在不同的地方走到头。静态托管已经解决了笔记本在线时长的问题,还给了你一个稳定的服务商 URL。免费应用托管也能做到这一点,其中一些现在还包含持久存储。当各种需求叠加起来时,VPS 才开始有意义:你自己的服务端进程需要一直在线,你需要可预期的持久存储,而免费套餐的资源或使用规则已经不再合适。

这道门槛值得尊重。一次演示不是买服务器的理由,一个低流量的静态项目也不是。短期分享就继续用隧道,应用真正是静态的就继续用静态托管,限额还能容纳你所运行的内容就继续用免费应用托管。

当你需要一台由自己掌控、始终在线的服务器,并且愿意承担随之而来的运维工作时,再迁移到 VPS。 我们的 Linux VPS 是一个选择,其他服务商的同类 VPS 也能完成同样的工作。按应用需求来选服务器规格,而不是假设最小的套餐就够用。

查看 Linux 套餐

在拥有 root 权限、NVMe 与 AMD EPYC 强大性能的 Linux VPS 上构建应用。

查看 Linux 套餐

这么做之后会有两处变化。平台托管给你的「推送到 git 即部署」的工作流不再是自动的了。你可以用 Coolify 或 Dokku这样的自托管 PaaS 把它重建出来,或者搭建自己的 CI/CD 流程,但无论哪种方式,更新和维护现在都归你负责。

另一处变化是,这台机器上能放的不只是应用。如果你也想把编辑器搬到那里,它会很乐意 运行 Code Server 和 Claude Code ,这究竟是个不错的附加福利,还是一个全新的周末工程,就看你自己了。

常见问题

为什么我合上笔记本后公开 URL 就失效了?

因为隧道绑定的是创建它的那个进程,而不是你的应用。合上笔记本或关掉终端会结束那个进程,公开 URL 随之失效,而你的应用本身没有任何问题。重启隧道会得到一个新 URL,除非工具给你分配了保留域名。如果链接需要在笔记本睡眠时依然可用,应用就必须离开你的机器。

把本地应用放到公开 URL 上需要域名吗?

几乎所有情况下都不需要。Cloudflare 快速隧道、ngrok 分配的开发域名、localtunnel、localhost.run 以及上面的免费托管套餐,都会免费给你分配一个它们自己域名下的子域名。例外是 Cloudflare 的命名隧道,它需要一个你已经添加到 Cloudflare DNS 的域名。

其他 Wi-Fi 网络上的人能打开我的本地 IP 地址吗?

不能。像 192.168.1.42 这样的地址,指向的是你当前所在网络中恰好持有它的那台设备,而在任何其他网络里,它指向的是另一台设备,或者什么都不是。你 Wi-Fi 之外的任何人都需要改用隧道、免费托管套餐或静态托管。

如果我的应用有登录和数据库,哪些方法可行?

同一网络和隧道这两条路径无需改动就能用,因为应用仍然运行在你的机器上。如果登录和数据库请求直接从浏览器发往托管服务,并且没有任何请求需要运行私有的服务端代码,静态部署也可行。如果你自己的认证或数据库代码在请求时需要服务器,就改用服务端托管。在免费应用托管上,请把持久数据放在持久存储中,而不是假设应用的本地文件系统能保留下来。

分享

讨论

评论

登录后参与讨论。

博客更多内容

继续阅读。

准备好部署了吗? 起价 $2.48/月。

独立云厂商,自 2008 年起。AMD EPYC、NVMe、40 Gbps。14 天退款保证。