大善人Cloudflare在zero trust的网络里提供了一个叫做Tunnels的东西, 通过它可以很轻松地建立多条连接到cloudflare 网络的隧道.
Tunnels提供了多种常见协议支持, 比如HTTP, HTTPS, TCP, SSH, RDP, SMB等, 甚至还支持与本地Unix socket文件通信.
本文主要以SSH为例介绍Tunnels的用法(其他协议也大同小异), 可以用于以下场景:
- 在没有公网ip的情况下实现内网穿透SSH连接内网机器
- 在没有ipv6的环境下连接只有ipv6 ip的主机
- 远程主机到本地的线路质量很差, 丢包严重造成SSH操作卡顿, 通过tunnels传输SSH来缓解
我这里以第一种场景为例, 内网中的主机是ubuntu 24.04.2 在后文我会把它称作服务端, 远程连接改服务端的pc是win 10, 后文我会称作客户端. 简单的原理图如下:
准备工作
- 一个NS解析在cloudflare的域名
- 开通zero trust. zero trust的基础功能的免费的, 包括Tunnels, 但是需要绑定一个支付方式开通, 支持visa信用卡或者PayPal, 这里推荐PayPal, 因为PayPal可以绑定国内的银联卡, 无需信用卡.
创建Cloudflare Tunnels
登录Cloudflare控制台,然后进入页面左侧的Zero Trust → 网络→ Tunnels → 创建隧道。
隧道类型选择cloudflared, 自定义隧道名称(这里我以localSSH为例)。
安装Cloudflared
接下来会进入到cloudflared的安装指导页面, cloudflared是隧道的创建和连接客户端, 选择适合服务端的架构, 这里我是ubuntu, 所以选的是Debian, 64bit. 复制知道页面的命令在服务端运行, 这些命令运行后会创建一个开机自启Systemd服务以确保隧道的时刻可用性.
同时客户端也需要下载cloudflared, 因为前面说过cloudflared同时也是连接器. 可以在同一个页面选择客户端的架构版本下载, 但是不要运行后面的cloudflared service install
, 这个命令只有服务端需要运行.也可以在cloudflared的官方仓库下载各个版本的文件: https://github.com/cloudflare/cloudflared/releases/
路由隧道
点击完成后在这个页面填写协议, ip, 端口, 并为该隧道分配一个子域名用于连接, ip填127.0.0.1, 建议不要填localhost, 可能会不成功. 如果服务器是只有ipv6的情况下填127.0.0.1可能无法连接, 需要填[::1]. 点击完成后cloudflare会自动创建dns记录, 下面就可以测试连接了.
连接测试
接下来通过ssh 的ProxyCommand 来让cloudflared把我们的ssh流量转发到隧道中:
ssh -o ProxyCommand="E:\code\go\bin\cloudflared access ssh --hostname localssh.merack.top" [email protected]
cloudflared 的路径, 用户名, host都换成自己的. 如果嫌每次都要写这么长的命令麻烦, 那么可以将其配置到ssh的配置文件里, 在windows下是 C:\Users\<User>\.ssh\config
文件(<User>替换为自己windows上的用户名)
Host localssh User root HostName localssh.merack.top ProxyCommand E:\code\go\bin\cloudflared access ssh --hostname %h
这时我们只需要在命令行里输入 ssh localssh
即可
如果是通过公钥文件的方式连接, 只需再加一行 IdentityFile
配置就好:
Host localssh User root HostName localssh.merack.top ProxyCommand E:\code\go\bin\cloudflared access ssh --hostname %h IdentityFile C:\path\to\.ssh\id_remote-ssh
扩展
通过上面的操作已经可以完成通过对内网服务器的ssh连接.此外tunnels还可以与zero trust中的其他功能想配合. 比如通过zero trust中的Access我们可以创建一个在浏览器上进行ssh操作tunnel所连接的内网服务器的网页, 无需写任何代码即可完成.下面进行简单的演示.
搭建网页版ssh控制台并配置访问策略
为了方便演示, 我又在上文的localssh tunnels里配置了一个用于web ssh的公共访问域名: localpanel.merack.top
登录Cloudflare控制台,然后进入页面左侧的Zero Trust → Access→ 应用程序→ 创建一个应用程序
应用程序类型选择自托管, 公共主机名设置成我们上面的localpanel.merack.top
为了确保只能我们自己访问, 在页面下方我们新建一个访问策略
访问策略里提供了相当多的规则, 这里我就选择emails, 表示只有规定的邮件地址才能进行验证, 然后在后方输入我们用于验证的email, 可以是多个, 可以不是注册cloudflare的邮箱.
添加完访问策略后回到应用程序配置页面进行选择
然后一直点击下一步来到高级设置, 打开浏览器呈现
这里是设置告诉cloudflare渲染什么样的界面, 有vnc和ssh, 这里我们选择ssh
点击完成后web ssh应用程序就完成了, 这时我们打开为应用程序配置的公共域名localpanel.merack.top就会自动跳转到cloudflare access的验证页面, 这里只有填入我们刚才在访问策略里配置的邮箱地址才能收到cloudflare access的验证码
验证完后就可以在浏览器中对内网服务器进行ssh操作了.
此外访问策略也可用于上文提到的用ssh 命令行连接的方式, cloudflared会自动在浏览器拉起验证页面
优选IP加速访问
cloudflare tunnels是建立在cloudflare的全球cdn节点上的, 但是cloudflare为ssh连接域名分配的默认泛播ip在国内体验不太好, 为了提升tunnels的连接体验, 我们可以手动修改hosts文件让ssh公共连接域名使用优选的ip节点. cloudflare优选ip网上的教程有很多, 最简单的就是直接ping我的博客域名: www.merack.top, 我的博客使用了SaaS, 这个域名会根据不同运营商返回优选好的ip.
比如windows上的hosts文件在C:\Windows\System32\drivers\etc\hosts, 那么我们可以做如下修改:
保存好后重新进行连接应该体验会有所改善
限制
因为在服务端ssh连接是通过的本地cloudflared, 所以ssh server看到的连接ip都是来自127.0.0.1, 那么像 fail2ban 这种基于连接ip的工具可能会失去其效果.
但是可以通过配合zero trust里的访问策略来对密码爆破做一定限制, 比如可以配置一个与前文提到的网页版ssh的同款访问策略, 那么在你使用ssh命令连接时, cloudflared会自动拉起浏览器打开cloudflare access验证窗口, 通过验证后才能进行后续的操作.