下拉查看上一篇

tunnelto 实战指南:用 Rust 写的开源内网穿透工具自建 localhost 通道


内网穿透(localhost tunnel)这几年几乎成了每个后端、全栈、AI Agent 开发者的标配。你可能在调试 Stripe Webhook、LINE Bot、GitHub App、微信小程序,或者只是想把本地跑起来的 Streamlit Demo 临时发给同事。选型上主流有三个方向:ngrok 托管服务、Cloudflare Tunnel、自托管方案。其中 tunnelto 属于"自托管派"里最轻的一个——用 Rust + async-io 写成,只需一个二进制文件就能同时跑客户端和服务端。

本文会带你走一遍 tunnelto 的定位、托管版与自建版的对比、以及在 Ubuntu + Nginx + HTTPS 环境下的完整自建流程。

tunnelto Demo TODO App 通过公网 URL 访问

tunnelto 是什么?和 ngrok / Cloudflare Tunnel 有何区别?

tunnelto 的核心主张就一句话:把你本地运行的 web server,通过一个公网 URL 暴露出去。从用户视角,它和 ngrok 几乎一样:

tunnelto --port 3000

执行完就会得到一个类似 https://amused-camel.tunnelto.me 的可分享链接。但和 ngrok 最大的区别在于:

维度 ngrok Cloudflare Tunnel tunnelto
写作语言 Go Go Rust(async-io + tokio)
是否能自托管 只有 Enterprise 版 服务端不可自托管 完全开源、可自托管
免费 URL 临时子域名 需要自有域名 临时子域名 / 自有域名
付费起步 较贵 免费(但绑 CF) 月 4 美元起
静态子域名 付费 需 DNS 配置 付费或自托管即可

tunnelto 最大的优势不是"便宜",而是——客户端和服务端是同一个二进制。自己跑一台 VPS,就能拥有属于自己的 *.yourdomain.com 通道服务。

选择托管版还是自建版?

托管版适合:

  • 只是偶尔调试 Webhook,一年也就用几十次;
  • 不想维护 VPS / 证书;
  • 需要固定子域名但不想折腾 DNS。

自建版适合:

  • 对数据流过境第三方服务有顾虑(例如内部测试环境、医疗 / 金融类项目);
  • 已经有一台带公网 IP 的 VPS;
  • 愿意用 Cloudflare / Let's Encrypt 管理证书;
  • 想把多个队友共享的通道统一收拢到自有域名下。

下面的实战部分默认你选择自建版。

自托管实战:Ubuntu + Nginx + Let's Encrypt

1. 准备工作

  • 一台 Ubuntu 22.04 / 24.04 VPS,带公网 IP;
  • 一个你能改 DNS 的域名(以 example.com 为例);
  • DNS 上添加一条 通配符 A 记录:*.tunnel.example.com → VPS IP;
  • 开放 TCP 80 / 443 / 5000(tunnelto 控制通道)。

2. 安装 tunnelto 服务端

tunnelto 在 GitHub 提供了 Release 二进制,也可以直接用 Cargo 构建:

# 方式 A:下载 Release
curl -L https://github.com/tunneltodev/tunnelto/releases/latest/download/tunnelto-server-linux-x86_64.tar.gz \
  | sudo tar -xz -C /usr/local/bin/

# 方式 B:从源码构建
sudo apt install -y build-essential pkg-config libssl-dev
curl https://sh.rustup.rs -sSf | sh
cargo install --git https://github.com/tunneltodev/tunnelto tunnelto_server

3. 用 systemd 守护 tunnelto_server

新建 /etc/systemd/system/tunnelto.service:

[Unit]
Description=tunnelto self-hosted server
After=network.target

[Service]
Environment=CTRL_PORT=5000
Environment=DOMAIN=tunnel.example.com
Environment=ALLOWED_HOSTS=*.tunnel.example.com
ExecStart=/usr/local/bin/tunnelto_server
Restart=on-failure
User=tunnelto

[Install]
WantedBy=multi-user.target

然后执行:

sudo useradd -r -s /usr/sbin/nologin tunnelto
sudo systemctl daemon-reload
sudo systemctl enable --now tunnelto

4. Nginx + HTTPS 反向代理

tunnelto 自身只处理 HTTP + 控制通道,TLS 终止交给 Nginx:

server {
  listen 443 ssl http2;
  server_name *.tunnel.example.com;

  ssl_certificate     /etc/letsencrypt/live/tunnel.example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/tunnel.example.com/privkey.pem;

  # WebSocket + 正常 HTTP
  location / {
    proxy_pass http://127.0.0.1:8080;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
  }
}

证书用 certbot + DNS 验证(Cloudflare 或 Route 53 插件)签一张通配符证书,注意不要用 HTTP-01 验证,因为我们要覆盖 *.tunnel.example.com。

5. 客户端连到自建服务

开发者机器上安装同一个 tunnelto 二进制,然后:

tunnelto set-auth --key YOUR_SHARED_SECRET
tunnelto --port 3000 \
         --sub hello-demo \
         --host tunnel.example.com

此时 https://hello-demo.tunnel.example.com 就会映射到你本地的 3000 端口。

tunnelto Webhook 示意

踩坑与优化建议

  1. 别用 HTTP-01 申请通配符证书:只能走 DNS-01,否则 Let's Encrypt 会直接拒绝 *. 通配符。
  2. 控制端口 5000 默认是明文,如果你的 VPS 暴露在公网,建议用 iptables 仅对内网 / VPN 开放,或者把共享密钥做得足够强。
  3. WebSocket 超时:Nginx 默认 proxy_read_timeout 60s,长连接应用(如 LINE Bot 消息流)建议调到 3600s。
  4. 不要在 tunnelto 后面跑压测:tunnelto 设计目标是调试通道,不是生产反向代理,打高并发请用 Nginx 直连后端。
  5. 和 Cloudflare 一起用时要注意 "Full (strict)" 模式 下证书必须匹配,否则会 521。

什么场景不适合 tunnelto?

  • 生产级接入层:请用 Cloudflare Tunnel + Access,或 AWS ALB + PrivateLink;
  • 跨地域低延迟:tunnelto 是单服务端结构,没有类似 Cloudflare 的全球 Anycast;
  • 超长 TCP 隧道:tunnelto 对非 HTTP 协议支持有限,TCP 透传建议用 frp 或 WireGuard。

总结

tunnelto 最大的亮点是同时拥有"开源自托管"和"简单到两行命令"这两个在 ngrok / Cloudflare Tunnel 上很难兼得的特性。如果你:

  • 有一台闲置 VPS,
  • 不想把调试流量过境第三方,
  • 又懒得折腾复杂的 Cloudflare Zero Trust 策略,

那么用一个下午把 tunnelto 架起来,几乎可以一劳永逸地替换掉 ngrok。对于 AI Agent 开发场景(webhook 回调、LLM 工具调用、MCP 调试),它也足够轻量。

参考来源

评论

上滑查看下一篇