RustDesk部署教程——基于Docker/1Panel
本文最后更新于10 天前,如有错误请在评论区中留言。

ChatGPT Image 2025年8月6日 20_02_24

日志

2025-8-9
更新了自建组网部署的内容
2025-8-7
完善了rustdesk介绍部分的内容
2025-8-5
部署过程发现rustdesk打洞也太垃圾了...除非是局域网否则%95概率都是走中继。想做公网访问的话,距离一但拉远了几乎必走中继。没办法只能向打洞异地组网工具妥协,比如tailscale,或者zerotier。但这样就非常难受了,给别人使用的话,得先进组网再用客户端。
2025-8-4
记录rustdesk部署过程,包含web客户端,后台管理API

前言

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和网页管理密码:

image-20250805162807214

完成上述步骤后就可以使用(IP+端口21114)登录你的网页管理API:

image-20250805163200134

接下来需要配置客户端,这里以windows客户端为例,填写如下内容:

image-20250805150924301

安卓,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中创建网站,选择反向代理的方式,并做如下配置:

image-20250805182721561

继续配置前端请求路径:ws/id,或ws/relay,反代后端代理地址为:http://内网ip地址:21118/ws/idhttp://内网ip地址:21118/ws/relay,后端域名不用做设置。

image-20250805190621995

启用https,并添加SSL证书,这里可以通过1panel面板获取SSL证书,需要创建一个Acme账户和DNS账户,具体如下:

image-20250805183928332

  1. 创建Acme账户,填写邮箱即可:

    image-20250805184214546

  2. 创建DNS账户,这里我使用腾讯云,需要到腾讯云面板的API密钥管理界面,添加Secret ID和Key,如果不知道在哪里,可以参考我之前的文章,里面有详细的位置博客图床配置(Typora+PicGo) – Clif's Blog

    image-20250805184634219

  3. 申请证书,填写你的主域名(例如example.com),以及其他域名(例如rustdesk.example.com),这样你所有的子域名也都可以使用同一个证书,方便管理。把自动续签勾上,会提前30天自动续签,方便托管。点击确定后,可能要等待2-3分钟,如果你的子域名过多的话,最后成功日志会有successful提示。

    image-20250805185247865

  4. 开启https,位置如下:

    image-20250805190406082

客户端

接下来需要配置客户端,以windows为例,注意这里反代了之后,不需要在API服务器后加21114端口了:

image-20250805195115474

安卓,ios等其他平台同理配置,后续就可以正常使用了。

补充说明

  • 记得开启防火墙端口,如果你更换了端口,请仔细核对
  • RUSTDESK_API_RUSTDESK_API_SERVER变量必须加前缀https://,因为rustdesk使用Go的URL解析,否则web客户端无法使用。
  • 后续实测,与ip部署相同,局域网能打通直连,但是距离一旦拉远,只能走中继,且打洞成功率不高。属于基本不能用,所以还得加自建组网

自建组网部署

自建组网,可以使用zerotier,或者tailscale,关于这两者的搭建和配置可以参考我的另外两篇文章:

到这一步,首先需要区分你的使用需求,针对需求做出不同配置

  1. 个人使用+ip访问(将配置的端口全部绑定到组网服务器的ip上即可)
  2. 个人使用+域名访问(这样可以使用https但是只有组网内的设备可以使用,感觉有点多此一举,具体方法:将dns解析的地址改为你的自建组网服务器的ip地址即可,实测几乎都可以稳定直连,但和你的网络环境有很大关系,存在打洞失败的情况。其实这一步也可以使用两个子域名来配置,一个用于自建组网的服务,只有加入组网设备可直连使用,另一个部署在公网,实现外部用户访问或局域网使用。)
  3. 公网使用 + 组网内部设备走直连 + 组网外部设备依靠 RustDesk 自带打洞(只需要把 rustdesk.example.com 解析到公网 IP;全程只用这一个域名

上述方案我使用的是第3种,组网方式我选用的tailscale,按实现方式分两种:

  1. 使用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

  2. 使用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软件。直连图标如图:

image-20250809203031829

 

除了使用客户端设备id直连,还可以使用内网ip直连的方式进行控制,即直接输入tailscale组网设备的ip地址进行连接。ip直连图标显示如图:

image-20250809203333057

相关参考

rustdesk部署相关参考

lejianwen/rustdesk-api: Custom Rustdesk Api Server, include web admin ,web client, web client v2 preview and oidc login

WebClient的自动连接时,填入的ID的英文大小写有问题。 · Issue #186 · lejianwen/rustdesk-api

RustDesk 完整部署教程:支持 Web 管理后台和网页客户端远程,保姆级教学来了!_rustdesk api-CSDN博客

RustDesk 搭建 - 忽如一夜春风来~ - 博客园

rustdesk打洞能力参考

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!

zerotier还是tailscale?理想很丰满,现实很骨感 - 知乎

Docker下中心化部署EasyTier - 悠笙の开发日记

如果您觉得本博客内容有所帮助,可以打赏一下吗~,此打赏将会用于博客维护运营,十分感谢!
作者:Clif
版权声明: 本博客所有文章除未特别声明外,均采用CC BY-NC-SA 4.0协议。转载请注明文章地址及作者!
暂无评论

发送评论(请正确填写邮箱地址,否则将会当成垃圾评论处理) 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇