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