借助CloudflareTunnel实现内网穿透
需求描述
- 海外VPS
- 域名 最好是拥有主域名
- CF(cloudflare)账号 订阅了
Teams Free Base免费套餐 - Tabby 开源Shell终端
- SwitchHosts 开源本地Hosts切换工具
- CloudflareSpeedTest 开源cloudflare IP优选工具
直接用域名绑定VPS主机IP并访问端口,长期来看,不仅有端口暴露风险,而且还需要忍受线路丢包、延迟波动所带来的命令行输入漂移等问题。
最好能够长期在不对外暴露端口并隐藏VPS主机IP的情况下,能够实现公网或者本地对VPS主机的访问。
VPS主机IP被封禁的情况下,依然能够使用本地Shell终端进行访问。
不依赖特定云厂商环境,能够在多个云厂商之间进行服务发布切换。
操作配置
1. 注册一个CF账号并订阅免费套餐
点击访问cloudflare dashboard进行账号注册。
点击左侧导航栏中的Zero Trust,设置团队名称,不知道怎么填,也可以截取注册邮箱的名称并输入。
付费计划选择第一个0元每月的套餐进行绑定即可。
支付方式选择PayPal,PayPal应该很容易注册,也能够绑定储蓄卡和借记卡。这个0元套餐也绑定几年了,目前还没有变卦。
2. 创建Cloudflare Tunnels
在套餐绑定成功后,在点击进入Zero Trust,然后再点击左侧导航栏中的Networks > Connectors(网络 > 连接器),进入后点击Create a tunnel(创建一个隧道)。创建隧道界面如下:

进入页面后,选择点击Select Cloudflared,输入隧道名称,比如vps-tunnel,然后点击Save tunnel进行保存创建。隧道命名界面如下:

目前CF tunnel支持多个平台的终端安装,为方便环境切换,现在选择Docker平台,安装命令可以复制出来并进行修改:

1 | |
将$yourtoken替换成刚才在页面中安装命令中的token字符串,docker的network选择的是bridge,使用的默认网段为172.17.0.0,宿主机在此网段的IP为172.17.0.1。当然也可以将network指定为host,此时与宿主机共用端口范围,如果端口被docker占用了,宿主机就不能再占用该端口了。因为采用了host,将端口开在宿主机上,少了一层网络转换,可以提供更好的网络连接和传输性能表现。
3. 在VPS主机上安装cloudflared终端
先按照常规方式SSH登录VPS主机,推荐使用云厂商提供的web shell在线登录,或者也可以通过本地直连VPS主机IP进行登录,后者的话,需要临时忍受网络丢包和延迟波动带来的命令输入漂移等问题。如果IP被封禁,或者只有IPv6地址,但是本地访问不了IPv6地址,那就只能选择前者了。
登录VPS主机后,先要安装docker运行环境,执行如下命令进行安装:
1 | |
等待docker安装好后,输入以下命令查看docker是否安装成功:
1 | |
将从cloudflare dashboard上复制并修改后的docker隧道建立命令在VPS主机上执行。如果在cloudflare dashboard显示如下信息,则CF tunnel连接成功。

成功后,点击Next进行下一步操作。如果没来得及在VPS主机上连接隧道,也可以点击Next,此页面命令信息是可以重复查看的。
4. 发布应用路由
当隧道连接成功后,接下来就是发布应用,目前可以支持的协议类型有:
- HTTP
- HTTPS
- UNIX
- TCP
- SSH
- RDP
- UNIX+TLS
- SMB
- HTTP_STATUS
- BASTION
在发布应用页面中,如果Domain主域名无法选择,可以去CF上买了一个域名。如果有其他厂商提供的域名,也可以让CF进行托管。
如果主域名没有绑定其他服务,则Subdomain可以为空,但推荐还是自定义一个子域名,比如输入vps-tunnel。
目前准备发布SSH协议的应用,Path可以不用填写,保持默认即可。Service信息栏进行如下配置:
Type:SSHURL:172.17.0.1:22

本次发布的应用是为了SSH登录,协议类型选择SSH,目前docker部署的cloudfalred终端是使用了bridge网络,而宿主机在该网络的IP是172.17.0.1,同时宿主机的SSH端口默认是22,如果不是默认的,特别是后续修改了SSH端口,URL中的端口需要改成对应的端口。
如果cloudfalred终端是采用了host网络,Service信息栏进行如下配置:
Type:SSHURL:localhost:22
点击Complete setup进行发布。发布成功后的效果如下:


5. 使ProxyCommand登录VPS主机
打开Tabby Shell终端,点击配置中Profiles & connections,选择New profile和SSH connection来创建一个SSH登录配置。配置如下:
Name:vps-tunnelConnection:Proxy commandProxy command:$CloudflaredPath access ssh --hostname $DomainUsename:VPS主机可登录的用户名
Authentication method可按需选择,如果是密码口令登录,选择Password,如果是SSH密钥登录,则选择Key。
$CloudflaredPath是cloudfalred终端程序的路径,示例路径为D:\\cloudflared.exe如果没有,可点击Windows版进行下载,下载好后,建议将文件重命名为cloudflared.exe
$Domain就是之前的子域名和主域名的组合Subdomain.Domain,也可在vps-tunnel隧道中的Published application routes页面中查询。
保存好后,就可以选择该SSH配置进行登录了。需要注意的是,登录的时候会打开一个cloudflared.exe应用程序窗口,如果手动关闭,会导致SSH会话结束,如果是同一域名开启多个SSH会话,则该窗口只有一个。除此之外,同一路径下cloudflared.exe只能供一个域名使用,如果有多个域名,建议将cloudfalred终端程序分发到多个目录,或者在同一目录下,复制多个命名不同的cloudfalred终端程序。
6. 将VPS主机服务端口映射到本地
在CF tunnel中嵌套SSH tunnel将VPS主机端口映射到本地,可将VPS服务只暴露给本地,这可用于服务器环境运行测试,等测试好后,再通过云厂商提供的平台防火墙将端口对外开放出去。
以docker部署nginx为例,将nginx容器80端口映射到宿主机的8080端口,现在通过CF tunnel和SSH tunnel将宿主机的8080端口映射到本地的8080端口上,在本地浏览器上访问http://localhost:8080,即可访问nginx上的网页。在本地使用powershell执行如下命令:
1 | |
-f:让 SSH 客户端在后台运行-N:只建立连接,不执行远程命令-i:指定SSH私钥文件路径
$PrivateKeyPath是SSH的私钥文件路径,示例路径为$HOME\.ssh\id_rsa,使用$HOME是为了避免中文路径乱码。
$CloudflaredPath是cloudfalred终端程序的路径,示例路径为D:\\cloudflared.exe
$Domain是Published application routes页面中的应用发布域名
Username是VPS宿主机上可登录的用户名
输入命令运行后,在浏览器上访问http://localhost:8080即可访问VPS上的nginx网页。
需要注意的是,powershell执行命令后不要关闭,如果手动关闭,则无法成功建立SSH隧道映射。
故障排查
1. Docker中的cloudflared无法和宿主机通信
这个一般是防火墙拦截了来自docker网络中的请求,只要允许访问即可。
- 通用方式
1 | |
- Ubuntu/Debian
1 | |
- RHEL/CentOS/Fedora/Rocky
1 | |
- Arch Linux/OpenSUSE
编辑/etc/nftables.conf,在input链中添加:
1 | |
1 | |
然后运行如下代码进行加载:
1 | |
2. Cloudflare给域名分配的IP延迟太高
cloudflare对于内地常常分配欧美IP进行响应,导致高延迟易丢包,解决办法就是在本地Hosts中把域名指向cloudflare优选后的IP,一般是日本节点的IP,延迟大概在80ms-90ms之间,虽然延迟依然不低,但是胜在稳定。如果是部署在美西的VPS,传输路径如下:
- 美西VPS数据中心 -> 美西CF数据中心 -> 日本CF数据中心 -> 本地
- 本地 -> 日本CF数据中心 -> 美西CF数据中心 -> 美西VPS数据中心
使用CloudflareSpeedTest进行IP优选,优选开始前,最好将网络代理或者加速器关闭,避免影响IP优选质量。以下是优选好的IP:
- 162.159.38.82
- 172.64.229.181
- 162.159.44.167
- 162.159.39.25
以管理员的身份打开SwitchHosts,添加一个新的Hosts配置,命名为vps-tunnel,添加如下记录:
1 | |
$IP为通过优选工具得到的CF边缘节点IP$Domain是Published application routes页面中的应用发布域名
编辑好后,点击配置名称旁边的开关,如果是绿色就代表操作成功。SwitchHosts只是在原有系统Hosts基础上添加记录,如果有相同记录,以新加入的为主,即使SwitchHosts退出或者系统重启依然生效。需要注意的是,如果命令行ping域名没有变化,建议重启命令行后再进行操作。
3. Powershell因私钥权限而无法建立SSH隧道
1 | |
执行上述命令后如果出现下述提示:
It is required that your private key files are NOT accessible by others.
则表示你的SSH私钥文件的权限不满足powershell的安全设置,可通过修改密钥文件权限或者更换密钥路径来解决。
- 修改密钥文件权限
1 | |
需要注意$PrivateKeyPath的格式,示例为D:\id_rsa
- 更换密钥文件路径
将私钥文件放到C盘的用户 > $用户名中的.ssh目录中,$用户名是你操作系统登录时的用户名。如果没有.ssh目录就新建一个.ssh文件夹,并将私钥文件放入该目录。如果.ssh目录中有重名的私钥文件,可将本次私钥文件重命名后放入其中。
参考信息
1. Tabby github开源项目
https://github.com/Eugeny/tabby
2. SwitchHosts github开源项目
https://github.com/oldj/SwitchHosts