Skip to main content

把 localhost:3000 绑定到自己的域名:Cloudflare Tunnel、ngrok、frp 与 Tailscale Funnel 对比

Rainy
雨落无声,代码成诗 —— 致力于技术与艺术的极致平衡
Rainy
13 MIN READ... VIEWS

本地开发最常见的需求是:应用跑在 localhost:3000,但你希望外部的人、Webhook 平台、手机真机、客户预览环境或远程同事能通过一个公网 HTTPS 地址访问它。

如果只是临时调试,ngrok http 3000 足够快。如果你已经有自己的域名,并且希望长期用 dev.example.com 指到本机服务,Cloudflare Tunnel 通常是更稳的选择:不需要路由器端口转发,不需要本机有公网 IP,也不需要把家庭或办公室网络直接暴露到公网。


一句话选择

场景推荐特点
最快调试ngrok一条命令把 localhost:3000 暴露出去。免费版可以使用账号分配的 dev domain,但免费版不能选择或保留自己的自定义域名。
有自己的域名,想稳定用Cloudflare Tunnel最推荐。可以把 dev.example.com 指到本机 localhost:3000,不用开路由器端口,也不暴露公网 IP。Cloudflare 官方文档支持通过 public hostname 把公网域名路由到本地服务。
自建、可控、可放国内云服务器frp需要一台有公网 IP 的 VPS。支持 HTTP、HTTPS、TCP、UDP,可以用自己的域名转发到内网服务。
已有 Tailscale 网络Tailscale Funnel可以把本机服务暴露到公网 HTTPS,更偏 Tailscale 生态。官方仍标为 beta,并且公网域名主要是 tailnet-name.ts.net 体系。

我的默认建议:

  1. 只测一次 Webhook:用 ngrok。
  2. 想长期把 dev.example.compreview.example.com 绑定到本机:用 Cloudflare Tunnel。
  3. 想完全自管入口、日志、带宽、国内访问链路:用 frp 加一台 VPS。
  4. 团队已经在 Tailscale 里,且接受 *.ts.net 域名和 beta 状态:用 Tailscale Funnel。

核心对比

维度ngrokCloudflare TunnelfrpTailscale Funnel
是否需要公网 VPS不需要不需要需要不需要
是否支持自己的域名支持,但自定义域名属于付费能力支持,域名需要接入 Cloudflare支持,DNS 指到自己的 VPS不适合自定义域名,主要使用 tailnet 域名
免费临时域名有账号分配的 dev domainQuick Tunnel 可生成 trycloudflare.com 随机域名取决于你的 VPS 和域名使用 Tailscale Funnel URL
适合长期稳定入口中等,取决于套餐和域名能力强,但要自己运维中等,受生态和限制影响
典型协议HTTP、HTTPS、TCP、TLSHTTP/HTTPS 公网应用最顺手;非 HTTP 服务通常需要客户端侧 cloudflaredHTTP、HTTPS、TCP、UDPTLS 加密连接,官方限制端口为 443844310000
运维复杂度低到中中到高低到中
安全入口能力ngrok policy、basic auth、OAuth 等可叠加 Cloudflare Access、WAF、DDoS 防护、DNS、证书需要自己做认证、TLS、限流和审计依赖 Tailscale ACL、Funnel node attribute 和 HTTPS
最适合临时 Demo、Webhook 调试自有域名稳定预览、团队开发环境自托管、国内 VPS、非 HTTP 端口转发已有 Tailscale tailnet 的轻量公开分享

这里的关键差异不是“谁能穿透内网”,而是谁来持有公网入口:

公网入口越托管,越省事;越自建,越可控。


Cloudflare Tunnel 的工作方式

Cloudflare Tunnel 的核心组件是 cloudflared。它运行在你的机器上,主动向 Cloudflare 建立出站连接。公网用户访问 dev.example.com 时,请求先到 Cloudflare,再沿着这条隧道转发到本机 localhost:3000

这和传统端口映射不一样:

传统端口映射Cloudflare Tunnel
路由器或安全组开放公网端口本机只需要能主动访问 Cloudflare
公网能看到你的源站 IP源站 IP 不需要公开
HTTPS、证书、DDoS、WAF 要自己处理可以复用 Cloudflare 的边缘能力
家庭宽带、公司 NAT、动态 IP 容易麻烦对 NAT 和动态 IP 更友好

前提条件:

  1. 有 Cloudflare 账号。
  2. 你的域名已经接入 Cloudflare DNS。
  3. 本机或服务器可以访问外网,并能运行 cloudflared
  4. 你的本地应用已经在 http://localhost:3000 正常工作。

安装 cloudflared

如果你通过 Cloudflare Dashboard 创建 Tunnel,页面会根据系统生成安装和运行命令,直接复制执行即可。这是最省心的路径。

手动安装可以按系统选择:

# macOS
brew install cloudflared

# Debian / Ubuntu
sudo mkdir -p --mode=0755 /usr/share/keyrings
curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | sudo tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null
echo "deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared any main" | sudo tee /etc/apt/sources.list.d/cloudflared.list
sudo apt-get update && sudo apt-get install cloudflared

# RHEL / CentOS / Fedora 系
curl -fsSl https://pkg.cloudflare.com/cloudflared.repo | sudo tee /etc/yum.repos.d/cloudflared.repo
sudo yum update && sudo yum install cloudflared

确认安装:

cloudflared --version

Docker 也可以直接运行:

docker run cloudflare/cloudflared:latest tunnel --no-autoupdate run --token <TUNNEL_TOKEN>

最快试用:Quick Tunnel

如果只是临时看一下效果,不需要账号和自定义域名,可以先跑 Quick Tunnel:

# 先启动你的本地项目
npm run start

# 另开一个终端
cloudflared tunnel --url http://localhost:3000

它会生成一个随机的 trycloudflare.com 子域名。这个模式适合临时测试,不适合长期入口:Cloudflare 官方文档说明 Quick Tunnel 面向测试,并且有并发请求和部分能力限制。

只要你想使用自己的 dev.example.com,就应该创建正式 Tunnel。


方式一:Dashboard 创建 Tunnel

这是推荐给大多数人的方式,因为 token、服务安装命令、Tunnel 健康状态都在页面里。

1. 启动本地应用

以 Docusaurus 或普通前端项目为例:

npm run start

确认本机可以访问:

curl -I http://localhost:3000

2. 创建 Tunnel

进入 Cloudflare Dashboard:

  1. 打开 Networking -> Tunnels
  2. 选择 Create Tunnel
  3. 输入名称,比如 rainlib-dev
  4. 选择运行 cloudflared 的操作系统和 CPU 架构。
  5. 复制页面给出的 install/run 命令,在本机执行。
  6. 等待 Tunnel 状态变成 Healthy

Dashboard 模式通常会给出类似下面的服务安装命令:

sudo cloudflared service install <TUNNEL_TOKEN>

这个 token 是敏感凭证,不要提交到 Git,也不要发到聊天群。

3. 添加公网 Hostname

在 Tunnel 详情页的 Routes 中添加 route:

字段示例
TypePublished application
Subdomaindev
Domainexample.com
Service URLhttp://localhost:3000

保存后,Cloudflare 会把 https://dev.example.com 路由到本机服务。浏览器打开:

https://dev.example.com

如果你的应用在另一台内网机器上,也可以把 Service URL 写成:

http://192.168.1.20:3000

前提是运行 cloudflared 的机器能访问这个内网地址。


方式二:CLI 本地配置 Tunnel

如果你希望配置文件可审计、可备份,或者不想把所有规则都放在 Dashboard 里,可以使用 locally-managed tunnel。

1. 登录 Cloudflare

cloudflared tunnel login

命令会打开浏览器,让你登录 Cloudflare 并选择域名。完成后,本机会生成 cert.pem

2. 创建命名 Tunnel

cloudflared tunnel create rainlib-dev
cloudflared tunnel list

创建成功后会得到 Tunnel UUID,并在 ~/.cloudflared/ 下生成凭证文件。

3. 写配置文件

创建 ~/.cloudflared/config.yml

tunnel: <Tunnel-UUID>
credentials-file: /Users/<you>/.cloudflared/<Tunnel-UUID>.json

ingress:
- hostname: dev.example.com
service: http://localhost:3000
- service: http_status:404

Linux 上路径通常是:

credentials-file: /home/<you>/.cloudflared/<Tunnel-UUID>.json

注意最后一条 catch-all 规则。Cloudflare 文档要求包含兜底 ingress 规则,否则未匹配的请求不知道该如何处理。这里用 http_status:404 是最干净的默认值。

4. 创建 DNS 路由

cloudflared tunnel route dns rainlib-dev dev.example.com

这会创建一个 CNAME,指向类似 <Tunnel-UUID>.cfargotunnel.com 的目标。

5. 前台运行测试

cloudflared tunnel run rainlib-dev

浏览器访问:

https://dev.example.com

6. 服务化运行

macOS 登录后自动运行:

cloudflared service install

macOS 开机运行:

sudo cloudflared service install
sudo launchctl start com.cloudflare.cloudflared

Linux systemd:

cloudflared service install
systemctl start cloudflared
systemctl status cloudflared

如果你用 sudo 安装 Linux service,要注意 $HOME 可能变成 /root。配置文件在普通用户目录时,应显式指定:

sudo cloudflared --config /home/<USER>/.cloudflared/config.yml service install
sudo systemctl restart cloudflared

Cloudflare Tunnel 常见配置

多个子域名

tunnel: <Tunnel-UUID>
credentials-file: /Users/<you>/.cloudflared/<Tunnel-UUID>.json

ingress:
- hostname: dev.example.com
service: http://localhost:3000
- hostname: api-dev.example.com
service: http://localhost:8080
- hostname: admin-dev.example.com
service: http://localhost:9000
- service: http_status:404

匹配路径

ingress:
- hostname: dev.example.com
path: /api/*
service: http://localhost:8080
- hostname: dev.example.com
service: http://localhost:3000
- service: http_status:404

转发到局域网服务

ingress:
- hostname: nas.example.com
service: http://192.168.1.50:5000
- service: http_status:404

不要把 NAS、数据库、管理后台裸露到公网。至少叠加 Cloudflare Access、强认证、IP 限制或应用自身登录。


安全建议

Cloudflare Tunnel 解决的是“公网入口如何到达本机”,不是“你的应用是否应该被任何人访问”。

建议最少做这些事:

  1. 使用独立子域名,比如 dev.example.com,不要直接占用主站根域名。
  2. 本机服务保持监听 127.0.0.1 即可,cloudflared 在同一台机器时不需要应用监听 0.0.0.0
  3. 不要把 Tunnel token、cert.pem、credentials JSON 提交到仓库。
  4. 预览站、后台、API 文档、调试面板建议加 Cloudflare Access。
  5. 如果只是给 Webhook 平台调用,优先限制路径、加签名校验、检查来源。
  6. 对长期运行的 Tunnel 配置监控和重启策略,避免电脑睡眠后入口不可用。

排障清单

现象排查方向
502 Bad Gateway本地服务没有启动,端口写错,或者 cloudflared 机器访问不到 localhost:3000
Tunnel 不健康检查 cloudflared 是否在运行,网络是否能访问 Cloudflare,受限网络下留意出站端口 7844
域名打不开检查域名是否已接入 Cloudflare,CNAME 是否创建,Tunnel route 是否绑定到了正确 hostname。
本地能访问,公网访问样式或接口异常检查应用里的 baseUrl、CORS、allowed hosts、回调地址和 cookie domain。
HMR 或 WebSocket 异常开发服务器可能需要允许外部 host,或者需要检查 HTTPS、WebSocket 地址和代理头。
service 启动后配置不生效重启 cloudflared service,并确认 service 读取的是你编辑的那个 config.yml

ngrok 怎么用

ngrok 最适合“马上给一个公网地址”:

ngrok config add-authtoken <NGROK_AUTHTOKEN>
ngrok http 3000

如果你有可用的 ngrok 域名:

ngrok http 3000 --url https://example.ngrok.app

ngrok 的优点是极快、跨平台、调试体验好,适合 Webhook、本地 Demo、短时间联调。限制是免费版域名能力有限:官方 Domains 文档说明,免费账号可以使用自动分配的 dev domain;选择或保留自定义域名需要付费计划,自带域名属于更高套餐能力。


frp 怎么配置

frp 的模式是你自己准备一台有公网 IP 的 VPS,公网入口由 frps 持有,本机运行 frpc 主动连出去。

VPS 上的 frps.toml

bindPort = 7000
vhostHTTPPort = 80
vhostHTTPSPort = 443

启动:

./frps -c ./frps.toml

本机 frpc.toml

serverAddr = "x.x.x.x"
serverPort = 7000

[[proxies]]
name = "web"
type = "http"
localIP = "127.0.0.1"
localPort = 3000
customDomains = ["dev.example.com"]

启动:

./frpc -c ./frpc.toml

DNS 配置:

dev.example.com A x.x.x.x

frp 的优点是自托管、协议支持广、成本可控,适合你已经有云服务器、希望走国内线路、需要 TCP/UDP 或更多代理能力的场景。代价是你要自己处理 VPS 安全、系统更新、TLS 证书、日志、限流、鉴权和进程守护。


Tailscale Funnel 怎么看

Tailscale Funnel 适合已经使用 Tailscale 的团队:你可以把本机服务通过公网 HTTPS 暴露出去,让不在 tailnet 里的用户也能访问。

典型命令形态:

tailscale serve --bg 3000
tailscale funnel 443 on

它的边界也很明确:

  1. 官方文档仍标为 beta。
  2. 需要 Tailscale 版本、MagicDNS、HTTPS 证书和 tailnet policy 中的 Funnel node attribute。
  3. Funnel 只能使用 tailnet 的 DNS 名称,比如 machine.tailnet-name.ts.net
  4. 官方限制监听端口为 443844310000
  5. 更适合 Tailscale 生态里的分享,不是“把任意自有域名稳定绑定到 localhost”的首选。

如果你的诉求是 dev.example.com -> localhost:3000,Cloudflare Tunnel 更直接。


最终建议

你想要什么直接选
今天马上给别人看本地页面ngrok
把自己的域名长期指向本机开发服务Cloudflare Tunnel
有 VPS,想完全自管入口和转发规则frp
团队已经在 Tailscale,并接受 beta 和 ts.net 域名Tailscale Funnel

对个人开发者和小团队来说,Cloudflare Tunnel 是最均衡的方案:配置比 frp 少,域名能力比 ngrok 免费版稳定,安全能力又比简单端口转发完整。它尤其适合把 dev.example.compreview.example.comwebhook-dev.example.com 这类开发入口长期挂到本机或内网机器上。


参考资料

Logo
RainLib

Exploring the frontiers of technology, design, and distributed systems. Building tools for the future developers.

Suggestions & Feedback

© 2026 RainLib. Built for the Future.
All rights reserved.
System Normal