日志
前言
RustDesk是一个开源的远程桌面项目,包含了全平台(ios,ipados不能做被控)的互控实现,支持服务端自部署,不经过第三方服务器,功能完善且免费。相比之下,同类型的产品如todesk,向日葵等已经成彻底被商业化,各种细分的vip捆绑收费,且并不支持全平台互控,实在令人难绷。
关于rustdesk已经有很多现有的教程,但是这些文章描述web客户端和后台管理API的部分不是很清晰,我还是自己部署踩一遍坑吧。
快速了解一下,关于rustdesk使用的端口:
端口 | 协议 | 服务 | 作用 |
---|---|---|---|
21114 | TCP | hbbs/API | Web 控制台API |
21115 | TCP | hbbs | NAT 类型探测 & 信令 |
21116 | UDP/TCP | hbbs | UDP 心跳注册 TCP P2P 打洞握手 |
21117 | TCP | hbbr | 中继服务(P2P 失败时回落) |
21118 | TCP | hbbs | Web 客户端 WebSocket 信令 |
21119 | TCP | hbbr | Web 客户端 WebSocket 中继 |
部署
这里我分了三类,根据需要使用就行
纯IP部署
准备:
- 一台有公网IP的服务器
- 安装使用1panel面板
服务端
使用docker-compose,可以参考我之前的文章Docker Compose的使用 – Clif's Blog
以下是yaml配置:
networks:
rustdesk-net:
external: false
services:
rustdesk:
ports:
- 21114:21114 #Web控制台API接口
- 21115:21115 #用于NAT类型测试及信令协商,是实现 NAT 穿透的关键端口。
- 21116:21116 #用于 TCP 打洞及连接服务,协助两个客户端直接建立连接。
- 21116:21116/udp #用于客户端向 ID 服务器注册自身 ID 并发送心跳,保证在线状态能被实时感知。
- 21117:21117 #提供中继转发服务,当直接打洞失败时,流量会回落到此端口通过中继服务器转发。
- 21118:21118 #为 RustDesk Web 客户端提供WebSocket通道,实现浏览器端的实时信令。
- 21119:21119 #为 RustDesk Web 客户端提供中继WebSocket通道,支持Web客户端的中继连接。
image: lejianwen/rustdesk-server-s6:latest
container_name: rustdesk
environment:
- RELAY= #服务器ip地址+端口(例:123.123.123.123:21117)
- RUSTDESK_API_RUSTDESK_ID_SERVER= #服务器ip地址+端口(例:123.123.123.123:21116)
- RUSTDESK_API_RUSTDESK_RELAY_SERVER= #服务器ip地址+端口(例:123.123.123.123:21117)
- RUSTDESK_API_RUSTDESK_API_SERVER= #http://ip地址+端口(http://123.123.123.123:21114)
- RUSTDESK_API_RUSTDESK_WS_HOST= #http这里不用填写就可以使用web客户端了
- RUSTDESK_API_APP_WEB_CLIENT=1 #是否开启网页客户端
- ENCRYPTED_ONLY=1 #强制客户端仅使用加密通道(TLS/WebSocket+TLS)
- MUST_LOGIN=Y #用户登陆才可以使用
- TZ=Asia/Shanghai
- RUSTDESK_API_KEY_FILE=/data/id_ed25519.pub
- RUSTDESK_API_JWT_KEY=eqowedj #jwt key
volumes:
- /opt/rustdesk/server:/data
- /opt/rustdesk/api:/app/data #将数据库挂载
networks:
- rustdesk-net
restart: unless-stopped
需要你设置的环境变量如下:
- RELAY= #服务器ip地址+端口(例:123.123.123.123:21117)
- RUSTDESK_API_RUSTDESK_ID_SERVER= #服务器ip地址+端口(例:123.123.123.123:21116)
- RUSTDESK_API_RUSTDESK_RELAY_SERVER= #服务器ip地址+端口(例:123.123.123.123:21117)
- RUSTDESK_API_RUSTDESK_API_SERVER= #http://ip地址+端口(http://123.123.123.123:21114)
- RUSTDESK_API_RUSTDESK_WS_HOST= #http这里留空就可以使用web客户端了
客户端
在docker容器日志获取获取key和网页管理密码:
完成上述步骤后就可以使用(IP+端口21114)登录你的网页管理API:
接下来需要配置客户端,这里以windows客户端为例,填写如下内容:
安卓,ios等其他平台同理配置,后续就可以正常使用了。
补充说明
- 记得开启防火墙端口,如果你更换了端口,请仔细核对
RUSTDESK_API_RUSTDESK_API_SERVER
变量必须加前缀http://,因为rustdesk使用Go的URL解析,否则web客户端无法使用- 后续实测基本只能走中继模式,打洞成功率极低,几乎不可用,需要使用打洞工具
- 如果需要直接在zerotier或tailscale这样的自建组网中使用,将ip替换为服务器的自建组网ip即可
https部署
准备:
- 一台有公网IP的服务器
- 一个域名(国内服务器需要备案)
- 安装使用1panel面板
服务端
准备一个域名,这部分需要对API网页管理设置反代,还需要对前端请求路径做反代
同样的使用docker-compose,可以参考我之前的文章Docker Compose的使用 – Clif's Blog
以下是yaml配置:
networks:
rustdesk-net:
external: false
services:
rustdesk:
ports:
- 21114:21114 #Web控制台API接口
- 21115:21115 #用于NAT类型测试及信令协商,是实现 NAT 穿透的关键端口。
- 21116:21116 #用于 TCP 打洞及连接服务,协助两个客户端直接建立连接。
- 21116:21116/udp #用于客户端向 ID 服务器注册自身 ID 并发送心跳,保证在线状态能被实时感知。
- 21117:21117 #提供中继转发服务,当直接打洞失败时,流量会回落到此端口通过中继服务器转发。
- 21118:21118 #为 RustDesk Web 客户端提供WebSocket通道,实现浏览器端的实时信令。
- 21119:21119 #为 RustDesk Web 客户端提供中继WebSocket通道,支持Web客户端的中继连接。
image: lejianwen/rustdesk-server-s6:latest
container_name: rustdesk
environment:
- RELAY= #服务器域名+端口(例:example.com:21117)
- RUSTDESK_API_RUSTDESK_ID_SERVER= #服务器域名+端口(例:example.com:21116)
- RUSTDESK_API_RUSTDESK_RELAY_SERVER= #服务器域名+端口(例:example.com:21117)
- RUSTDESK_API_RUSTDESK_API_SERVER= #https://域名(https://example.com)
- RUSTDESK_API_RUSTDESK_WS_HOST= #https://域名(https://example.com)
- RUSTDESK_API_APP_WEB_CLIENT=1 #是否开启网页客户端
- ENCRYPTED_ONLY=1 #强制客户端仅使用加密通道(TLS/WebSocket+TLS)
- MUST_LOGIN=Y #用户登陆才可以使用
- TZ=Asia/Shanghai
- RUSTDESK_API_KEY_FILE=/data/id_ed25519.pub
- RUSTDESK_API_JWT_KEY=eqowedj #jwt key
volumes:
- /opt/rustdesk/server:/data
- /opt/rustdesk/api:/app/data #将数据库挂载
networks:
- rustdesk-net
restart: unless-stopped
在1panel中,配置反向代理:
网页管理API地址反代,在1panel中创建网站,选择反向代理的方式,并做如下配置:
继续配置前端请求路径:ws/id
,或ws/relay
,反代后端代理地址为:http://内网ip地址:21118/ws/id
或 http://内网ip地址:21118/ws/relay
,后端域名不用做设置。
启用https,并添加SSL证书,这里可以通过1panel面板获取SSL证书,需要创建一个Acme账户和DNS账户,具体如下:
-
创建Acme账户,填写邮箱即可:
-
创建DNS账户,这里我使用腾讯云,需要到腾讯云面板的API密钥管理界面,添加Secret ID和Key,如果不知道在哪里,可以参考我之前的文章,里面有详细的位置博客图床配置(Typora+PicGo) – Clif's Blog
-
申请证书,填写你的主域名(例如example.com),以及其他域名(例如rustdesk.example.com),这样你所有的子域名也都可以使用同一个证书,方便管理。把自动续签勾上,会提前30天自动续签,方便托管。点击确定后,可能要等待2-3分钟,如果你的子域名过多的话,最后成功日志会有successful提示。
-
开启https,位置如下:
客户端
接下来需要配置客户端,以windows为例,注意这里反代了之后,不需要在API服务器后加21114端口了:
安卓,ios等其他平台同理配置,后续就可以正常使用了。
补充说明
- 记得开启防火墙端口,如果你更换了端口,请仔细核对
RUSTDESK_API_RUSTDESK_API_SERVER
变量必须加前缀https://,因为rustdesk使用Go的URL解析,否则web客户端无法使用。- 后续实测,与ip部署相同,局域网能打通直连,但是距离一旦拉远,只能走中继,且打洞成功率不高。属于基本不能用,所以还得加自建组网
自建组网部署
自建组网,可以使用zerotier,或者tailscale,关于这两者的搭建和配置可以参考我的另外两篇文章:
到这一步,首先需要区分你的使用需求,针对需求做出不同配置
- 个人使用+ip访问(将配置的端口全部绑定到组网服务器的ip上即可)
- 个人使用+域名访问(这样可以使用https但是只有组网内的设备可以使用,感觉有点多此一举,具体方法:将dns解析的地址改为你的自建组网服务器的ip地址即可,实测几乎都可以稳定直连,但和你的网络环境有很大关系,存在打洞失败的情况。其实这一步也可以使用两个子域名来配置,一个用于自建组网的服务,只有加入组网设备可直连使用,另一个部署在公网,实现外部用户访问或局域网使用。)
- 公网使用 + 组网内部设备走直连 + 组网外部设备依靠 RustDesk 自带打洞(只需要把
rustdesk.example.com
解析到公网 IP;全程只用这一个域名)
上述方案我使用的是第3种,组网方式我选用的tailscale,按实现方式分两种:
-
使用Headscale:开启 MagicDNS +
extra_records
,其原理大致是:-
MagicDNS 负责给tailscale设备下发 DNS 规则
-
当 tailscale 设备解析
rustdesk.example.com
时,先查extra_records
:命中:直接返回你写的 tailscale 内网 IP,从而控制面(ID/Relay/信令)走专网。
未命中:按
nameservers
(global)去递归解析(由递归器再去问权威 DNS),获得公网 IP。
Headscale的
config.yaml
配置示例(片段):dns: magic_dns: true #开启magic_dns base_domain: ts.example.com #独立子域,不要用根域 override_local_dns: false nameservers: #不做改动 global: - 1.1.1.1 - 1.0.0.1 extra_records: #添加extra_records - { name: "rustdesk.example.com", type: "A", value: "你的服务都ipv4地址" } #如果你需要继续添加其他记录,继续向下这样添加即可。 #- { name: "other.example.com", type: "A", value: "你的其他服务的ipv4地址" }
这个方式的优点是配置便捷,适合少量条目的情况 → MagicDNS +
extra_records
-
-
使用Headscale:开启 MagicDNS + Split+coredns,其作用分别是:
-
MagicDNS 负责给tailscale设备下发 DNS 规则
-
Split DNS 指定:凡是
example.com
的解析,tailscale 设备先问你的 CoreDNS服务;CoreDNS 命中 hosts:返回 tailscale 内网 IP,直走专网;
未命中:CoreDNS forward 到公共递归(如 1.1.1.1),由递归器再去问权威 DNS → 得到公网 IP
这个方案的好处是,只“劫持”你写在
hosts
里的条目,其余*.example.com
自动走公网,不影响headscale.example.com
等站点,且一旦有大量的内部服务需要走内网直连,就更方便批量部署和统一管理。Headscale的
config.yaml
配置示例(片段):dns: magic_dns: true #开启magic_dns base_domain: ts.example.com #独立子域,不要用根域 override_local_dns: false nameservers: global: [1.1.1.1, 1.0.0.1] split: example.com: [100.123.123.123] #跑CoreDNS的服务器tailscale内网ip,这里是示例100.123.123.123)
构建CoreDNS(docker-compose部署)
-
构建docker-compse.yaml:
services: coredns: image: coredns/coredns:latest container_name: coredns command: -conf /etc/coredns/Corefile volumes: - ./Corefile:/etc/coredns/Corefile:ro - ./hosts:/etc/coredns/hosts:ro ports: - "100.123.123.123:53:53/udp" #CoreDNS的服务器tailscale内网ip:53:53 - "100.123.123.123:53:53/tcp" restart: unless-stopped
-
新建
Corefile
文件(仅命中 hosts 改写,其它全部转发).:53 { log errors hosts /etc/coredns/hosts { fallthrough } forward . 1.1.1.1 8.8.8.8 cache 30 }
-
新建
hosts
文件:#跑你的rustdesk服务的服务器的ip + 域名(如果你的coredns和rustdesk在同一个服务器上,填一样的就好) 100.123.123.123 rustdesk.example.com #需要更多内网直连的服务,继续往下加: #100.64.0.5 git.example.com #100.64.0.6 wiki.example.com
-
将上述三个文件放在同一目录下,打开防火墙端口,用于coredns监听:53/tcp,53/udp
完成上述配置后,docker-compose up -d启动,然后使用下面的命令检查上述两种方法其一是否配置成功:
-
接入内网的Windows端:
nslookup rustdesk.example.com 100.100.100.100 #预期返回 内网 IP
返回预期内网ip
-
未接入内网的Windows端:
nslookup rustdesk.example.com 100.100.100.100 #预期无法返回 内网 IP
无法返回内网服务ip,测试公网:
nslookup rustdesk.example.com 8.8.8.8 #预期返回 公网 IP
返回公网ip
其他平台的客户端自检自行gpt,这里就不重复了。
综上,如果成功看到上述自检结果,说明完成方案3的部署了,可以正常使用rustdesk进行控制了,测试过程中发现,内网设备使用rustdesk中的设备id直连,%99的情况可以直连成功的。如果依然是中继模式,说明你配置的split没有生效,或者你的客户端没有接收到headscale下发的规则,需要重启一下内网设备以及tailscale软件。直连图标如图:
除了使用客户端设备id直连,还可以使用内网ip直连的方式进行控制,即直接输入tailscale组网设备的ip地址进行连接。ip直连图标显示如图:
相关参考
rustdesk部署相关参考
WebClient的自动连接时,填入的ID的英文大小写有问题。 · Issue #186 · lejianwen/rustdesk-api
RustDesk 完整部署教程:支持 Web 管理后台和网页客户端远程,保姆级教学来了!_rustdesk api-CSDN博客
rustdesk打洞能力参考
About P2P direct connection without relay · rustdesk/rustdesk · Discussion #6689
RustDesk 自建中转服务器卡顿,疑是 UDP 打洞遭运营商限制 - V2EX
关于rustdesk的打洞疑问 - 开发调优 - LINUX DO
内网穿透方案对比参考
所有内网穿透方案折腾一圈后的总结-软路由,x86系统,openwrt(x86),Router OS 等-恩山无线论坛 - Powered by Discuz!
Tailscale相比Zerotier的两个优点-OPENWRT专版-恩山无线论坛 - Powered by Discuz!