通过 Cloudflare Tunnel 访问内网服务
出于实际需求,需要访问位于内网的 Windows 实例。TeamViewer 和 AnyDesk 等第三方方案存在授权和安全问题,而 FRP 既不灵活也不安全(服务直接暴露于公网)。最终决定使用 Cloudflare Tunnel。
严格按照本文说明,仅需 15 分钟即可完成所有操作。
服务端侧
首先从 Cloudflare/Cloudflared 下载编译好的二进制,解压至本地。
1 | # 1. 登录到账号 |
如果你没有 Cloudflare 账号,或者 Cloudflare 账号没有域名,则可以通过下方命令进行测试,会自动生成一个临时的 URL 用于访问。
1 | .\cloudflared.exe tunnel --url rdp://127.0.0.1:3389 |
这里的 --url
参数为 service URL,用于指定要代理的服务,格式为 <协议头>://<IP>:<端口>
。一些样例如下:
1 | # RDP |
Cloudflare Tunnel 可以用于中转任意 TCP 服务,也可以用于映射至内网其他服务,具体细节可以参考官方文档。暂时不支持 UDP 服务。
客户端侧
客户端侧比较简单,下载编译好的二进制后
1 | .\cloudflared.exe access rdp --hostname <域名> --url localhost:<映射至本地的端口> |
随后,在 RDP 客户端中填写 localhost:<本地端口>
即可访问到远程桌面了。
注意:如果此处端口使用 3389
,Windows 自带的 RDP 客户端会阻止连接。我们可以
- 访问
127.0.0.2
,它其实是127.0.0.1
的另一个别名。 - 换一个端口。
- 使用兼容性设置,让 mstsc.exe 以另一个系统环境运行。
注册为 Windows 服务实现自动运行
服务端侧
我们可以将其注册为系统服务于后台运行,免去手动运行 daemon 的烦恼。参考此页面。
注册为系统服务
1
.\cloudflared.exe service install
C:\Users\%USERNAME%\.cloudflared\
目录下有一个形如6ff42ae2-765d-4adf-8112-31c55c1551ef.json
的文件,为刚刚所创建的隧道的鉴权信息。在同目录下创建config.yaml
,内容如下1
2
3
4
5
6
7
8
9
10
11# 隧道的 UUID
tunnel: 6ff42ae2-765d-4adf-8112-31c55c1551ef
# 鉴权文件的绝对路径
credentials-file: C:\Users\%USERNAME%\.cloudflared\6ff42ae2-765d-4adf-8112-31c55c1551ef.json
ingress:
# 修改为自己的二级域名
- hostname: rdp.example.com
service: rdp://localhost:3389
# 兜底规则,将不符合前序规则的请求回应 404 错误
- service: http_status:404配置 DNS 记录(需要使用自己的域名)
1
.\cloudflared.exe tunnel route dns <NAME> <DOMAIN>
修改注册表(
regedit.exe
),配置启动参数:在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services
找到Cloudflared
,将ImagePath
修改为<cloudflared.exe 绝对路径> --config=<YAML 配置文件绝对路径> tunnel run
。通过命令行或任务管理器重启 Cloudflared 服务即可完成。
1
2
3# 需要管理员权限
sc stop cloudflared
sc start cloudflared
客户端侧
只需将 ImagePath
修改为 <cloudflared.exe 绝对路径> access rdp --hostname <域名> --url localhost:<映射至本地的端口>
,然后重启 cloudflared
服务。
可选操作:为 RDP 文件签名
mkcert 生成自签名的证书 host.pem
和 host-key.pem
改成同样的名字 host.pem
和 host.key
,使用 Windows 自带的 certutil
,合并为 host.pfx
文件。
1 | certutil -mergepfx host.pem host.pfx |
将 host.pfx
导入至 certmgr
的 Personal 目录。复制该证书的 SHA-1 指纹(thumbnail),使用 Windows 自带的 rdpsign
进行签名。
1 | rdpsign /sha256 <sha1 hash> test.rdp |
可选操作:将桌面程序配置为 RemoteApp
RemoteApp 是基于 Windows RDP 的增强功能,将远端的程序以本地程序的形式显示,效果和 VMware 的 Unity Mode 相似。
从这里下载 RemoteApp Tool,添加本地程序(例如 Chrome, VMWare 等),并为之生成 .rdp
文件即可。全程傻瓜化操作,十分简单。注意 hostname 和端口需要修改为前文对应的客户端侧地址。
用户体验
默认设置
播放 YouTube 视频、打字都很流畅。快速滚动页面时可能会有一些掉帧;快速拖动窗口会存在少量拖影和延迟。
以 RemoteApp 形式运行应用时,部分 pop-up 菜单的显示效果不理想,可能会出现短暂的黑色或阴影部分。
细节优化
RDP 服务端优化:修改组策略(gpedit.msc
),找到 计算机配置 -> 管理模板 -> Windows 组件 -> 远程桌面服务 -> 远程桌面会话主机 -> 远程会话环境
。
- RDP 默认帧率 30,可以手动提升至 60 上限(不一定能达到):在注册表的
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations
路径下新建DWMFRAMEINTERVAL
,值设为十进制15
。在 1080p 分辨率下,修改前测试为 22 fps,修改后测试为 33 fps,提升 50%。 - 隐藏壁纸:建议开启,节约带宽。
- 硬件 GPU 加速:建议开启。
- H.264/AVC 硬编码支持:如果有看视频需求,建议开启,否则建议关闭。
- RemoteFX data compression:看情况吧,我设置为 optimize for use less network bandwidth。
- Image quality:默认是由 RDP 客户端和服务端根据网络情况自协商的,可以在此强制指定。
RDP 客户端优化
- 在 RDP 客户端高级选项中的 Experience 菜单指定。在网络质量很好的情况下,选择 WAN(10Mbps with high latency)或 Auto detect 对稳定性没有明显影响。建议设置为自动。
- Colors:设置为 16-bit 足够满足办公需求。
总结
从本地到 Cloudflare DC 到远端计算机的 RTT 约为 60 ms
。经过上述优化,在 16-bit 色彩、1080p 分辨率和自动画质的设置下,流畅性与本机应用近乎一致。
最后,为什么使用 RDP 而非 VNC 呢?
正如前面提到的 VNC 协议是基于像素的。尽管这带来了极大的灵活性,可以显示任何类型的桌面,但它的效率往往不如那些更好地理解底层图形布局(例如: X11)或桌面(例如:RDP)的解决方案。这些协议以更简单的形式(例如:打开窗口)发送图形原语或高级命令,而 VNC 的 RFB 协议尽管支持压缩但只能是发送原始像素数据。