原文Cloudflare Argo Tunnel with RustRaspberry Pi作者 Steven Pack家里有一块吃灰的树莓派一直想用来跑点什么但总绕不开两个问题家庭宽带没有固定 IP路由器也不想随便开放端口。这篇文章记录的就是 Cloudflare 一位工程师的实验把树莓派、Rust 异步 Web 框架和 Cloudflare Tunnel 三者结合起来在完全不动路由器、不配 DNS 记录的前提下把树莓派上的 Web 服务暴露到公网。整个过程出乎意料地顺滑。问题在哪里想让家里的机器对外提供服务传统方式大概有这几条路动态域名解析DDNS家庭宽带 IP 会变得在路由器上跑一个 DDNS 客户端不稳定配置也烦琐端口映射在路由器上开放指定端口转发到内网机器等于把内网暴露了一个口子有安全风险租云服务器花钱而且家里的树莓派就成了摆设Cloudflare Tunnel原名 Argo Tunnel的思路完全不同让内网机器主动向外建立一条持久连接流量通过这条连接进来不需要任何入站规则。原理反向隧道整个架构用一句话描述就是树莓派上的cloudflared客户端向最近的 Cloudflare 节点建立一条出站的 HTTP/2 长连接当外网用户请求你的域名时Cloudflare 把请求通过这条连接反向推送给树莓派树莓派处理后再原路返回。几个关键点流量方向是出站的。树莓派只需要能访问外网不需要任何端口对外开放安全性由证书保证。cloudflared登录时会生成一个证书文件cert.pem隧道连接用它来做身份验证Cloudflare 负责域名解析和 HTTPS。你只需要有一个托管在 Cloudflare 上的域名其余的它帮你搞定准备工作需要以下几样东西一块树莓派作者用的是 Raspberry Pi 3 Model B已安装 Raspbian一个托管在 Cloudflare 的域名树莓派能正常访问外网确认树莓派联网正常最简单的方法是 curl 一下curl-Ihttps://www.cloudflare.com看到HTTP/2 200就说明出站连接没问题。第一步安装 cloudflaredcloudflared是 Cloudflare 提供的隧道客户端。树莓派是 ARM 架构需要下载对应版本wgethttps://bin.equinox.io/c/VdrWdbjqyF/cloudflared-stable-linux-arm.tgzmkdirargo-tunneltar-xvzfcloudflared-stable-linux-arm.tgz-C./argo-tunnelcdargo-tunnel ./cloudflared--version如果看到版本号输出就说明可以正常运行了。第二步登录并授权域名运行登录命令./cloudflared login它会输出一个 URL让你在浏览器里打开因为树莓派是无头环境复制到自己的电脑浏览器里打开就行。登录 Cloudflare 账号后选择你想用来建隧道的域名点击授权。授权成功后树莓派控制台会显示You have successfully logged in. If you wish to copy your credentials to a server, they have been saved to: /home/pi/.cloudflared/cert.pem这个cert.pem就是隧道的凭证文件后续都会用到它。第三步用内置 Hello World 验证隧道在正式部署自己的服务之前先用cloudflared自带的 Hello World 模式验证隧道是否通./cloudflared--hostnametunnel.yourdomain.com --hello-world把tunnel.yourdomain.com换成你自己的子域名。启动后会看到类似这样的日志INFO[0005] Connected to LAX INFO[0010] Connected to SFO-DOG这说明客户端已经连上了 Cloudflare 节点。此时在浏览器里访问https://tunnel.yourdomain.com应该能看到一个 Hello World 页面。路由器没动防火墙没动DNS 没手动配置就这样通了。第四步用 Rust 跑一个真正的 Web 服务Hello World 验证完隧道没问题下一步换成一个真实的 Rust Web 服务。原博客作者选择了 Gotham一个基于异步 I/O 的 Rust Web 框架。首先安装 Rust 工具链curlhttps://sh.rustup.rs-sSf|sh# 安装完成后刷新环境变量source$HOME/.cargo/env克隆 Gotham 并编译 hello_world 示例gitclone https://github.com/gotham-rs/gothamcdgotham/examples/hello_worldcargobuild树莓派编译比较慢cargo build花了将近 8 分钟。编译完成后运行cd../../target/debug ./gotham_examples_hello_world# Listening for requests at http://127.0.0.1:7878Web 服务现在监听在本地 7878 端口。把隧道指向它./cloudflared--hostnamegotham.yourdomain.com http://127.0.0.1:7878访问https://gotham.yourdomain.comRust 服务的响应就出来了。第五步配置开机自启每次 SSH 进去手动启动太麻烦需要让两个进程在系统启动时自动运行。配置 cloudflared 自启先把证书和配置文件放到系统目录sudocp~/.cloudflared/cert.pem /etc/cloudflaredsudonano/etc/cloudflared/config.ymlconfig.yml内容hostname:gotham.yourdomain.comurl:http://127.0.0.1:7878然后安装为系统服务sudo./cloudflaredserviceinstallcloudflared会自动注册成 systemd 服务开机自启。配置 Rust Web 服务自启把编译好的二进制文件复制到一个稳定的位置cptarget/debug/gotham_examples_hello_world /home/pi/argo-tunnel/server/bin/编辑/etc/rc.local在exit 0之前加一行/home/pi/argo-tunnel/server/bin/gotham_examples_hello_world重启树莓派SSH 回来后检查两个进程是否都在运行sudops-aux|grepcloudflaredsudops-aux|grepgotham看到进程就说明配置成功了。这件事有意思在哪纯粹的技术实现层面这个方案并不复杂每一步都很直白。但把这几样东西组合在一起解决的问题其实很实际家宽没有固定 IP 不再是障碍。Cloudflare Tunnel 的连接是从内网发起的IP 怎么变都无所谓隧道会自动重连。不需要开防火墙端口。对家庭网络来说不在路由器上开洞安全性本质上好了一个层次。所有流量都经过 Cloudflare还能顺带享受 DDoS 防护和 HTTPS。Rust 在资源受限设备上表现不错。Gotham 是异步框架内存占用低这一点在只有 1GB 内存的树莓派上很重要。编译慢是确实慢但一次编译、长期运行是嵌入式类场景的合理取舍。当然这个方案也有局限。Cloudflare Tunnel 需要你有一个托管在 Cloudflare 上的域名流量也会经过 Cloudflare 的节点如果对数据经过第三方有顾虑就需要另想办法。小结这个实验的路径是这样的树莓派联网安装cloudflaredcloudflared login授权域名获取证书先用内置 Hello World 验证隧道通路安装 Rust编译 Gotham 示例把隧道指向本地 Web 服务配置 systemd 和 rc.local 实现两个进程的开机自启整个过程没有动过路由器没有手动配过 DNS家里的树莓派就这样对外提供了一个有正经域名和 HTTPS 的 Web 服务。对于那些一直想折腾树莓派但被网络配置挡在门外的人来说这条路值得一试。