中文 English

受够远程控制被限速?我把 RustDesk 服务端搬回自己家:多合一部署、避坑与安全加固

发布时间: 2026-07-10
RustDesk 远程桌面 Docker Docker Compose 自托管 开源 运维 Windows Ubuntu macOS

先说结论

RustDesk 是一款强调开源与自托管的远程桌面工具。客户端之间能直接连接时,画面和键鼠数据优先点对点传输;直连失败时,才由中继服务转发。把服务端部署在自己控制的机器上,最大的价值不是“完全不要服务器”,而是把设备登记、中继路径、密钥、账号和日志重新放回自己的控制范围。

本文使用社区维护的 lejianwen/rustdesk-server-s6 多合一镜像,把 RustDesk OSS 的 hbbshbbr 与社区 API、Web 管理功能放进一个容器。它适合家庭、实验室和小团队简化部署,但不是 RustDesk 官方发行的多合一服务端。生产环境仍需自行评估社区镜像、固定版本或镜像摘要、备份数据,并测试升级和回滚。

本文所有域名都使用 example.com,没有展示真实 IP、私有域名、主机名、设备 ID、账号、密钥、Token、Cookie 或镜像仓库地址。公开截图来自项目官方页面或社区仓库公开素材。

原创题图:把远程桌面的登记、中继和数据重新放回自己的服务器

为什么我最后还是选择自建远程桌面

远程桌面最容易被低估的地方,是它看起来只像“把另一台电脑的屏幕搬过来”。真正使用时,它同时涉及账号、设备发现、网络穿透、加密、中继带宽、文件传输、剪贴板和管理员权限。任何一环不稳定,体验都会从“像坐在电脑前”变成“像隔着结冰的玻璃按鼠标”。

商业远程控制服务很方便,但你通常需要接受它的账号体系、连接策略、并发限制、带宽路线与价格变化。自建 RustDesk 不是为了否定这些产品,而是给自己增加一个可控选项:服务器放在哪里、数据经过哪里、什么时候升级、日志保留多久,都由自己决定。

RustDesk 的客户端代码公开,官方也提供开源服务端项目。其 GitHub 项目把自己描述为一款面向自托管的开源远程桌面应用。对个人用户来说,它最直观的吸引力是界面和常见远程控制软件相似;对运维人员来说,更重要的是 ID 服务和 Relay 服务可以自己部署。

真实截图:RustDesk 官方 GitHub 项目页面,截图时间为本文写作时

先把连接原理讲明白:它更像打电话,不像视频网站

很多人第一次部署失败,是因为把 RustDesk 服务端想象成视频网站服务器:以为每一帧画面都必须上传到服务器,再下载到控制端。实际上,RustDesk 会优先尝试让两台设备直接连接。

可以把整个过程想成打电话:

因此,中继可用不等于点对点连接正常。如果每次远程都走 Relay,功能可能看起来没有坏,但服务器带宽、延迟和流量成本会明显增加。

原创流程图:hbbs 负责登记牵线,能直连就直连,失败才由 hbbr 中继

官方服务端与社区多合一方案有什么区别

RustDesk 官方 OSS 服务端的核心是两个程序:

官方文档推荐大多数 Linux 部署使用 Docker Compose,并强调持久化数据、开放正确端口、启动 hbbshbbr,再让客户端指向新的自建服务器。Linux 上可以使用 network_mode: host 简化端口映射;Docker Desktop 下则更适合显式映射端口。

真实截图:RustDesk 官方文档中的 Docker 部署建议与检查清单

社区项目 lejianwen/rustdesk-api 在基础服务端之外增加了账号、地址簿、管理后台、Web Client、OIDC 等能力。rustdesk-server-s6 则把 hbbshbbr 和这套 API/Web 能力收进同一个由 S6 管理的容器。

这就像原本需要分别租“前台、转接台、档案室和网页办公室”四个房间,现在把它们安排进同一套办公空间。岗位没有消失,只是启动、日志和生命周期由一个容器统一管理。好处是 Compose 更短、部署更直观;代价是组件耦合更紧,社区镜像的升级也必须整体测试。

原创结构图:单容器包含多个服务,但数据和日志仍应独立持久化

端口到底做什么:别把所有门都当成 HTTP

常见端口职责如下:

端口 协议 主要职责
21114 TCP 社区 API、管理后台或 Web 入口
21115 TCP NAT 类型测试
21116 TCP + UDP ID 注册、心跳、连接协调与打洞
21117 TCP Relay 中继
21118 TCP Web Client 的 ID WebSocket 支持
21119 TCP Web Client 的 Relay WebSocket 支持

其中 21116/UDP 很容易漏开。只开放 TCP 时,设备可能能登记、甚至看起来偶尔能连上,但打洞成功率会明显下降。

另一个常见误区,是把所有端口都塞进普通 HTTPS 反向代理。API 和 WebSocket 可以通过支持升级连接的反向代理发布;211152111621117 则是 RustDesk 的原生通信端口,不能把它们当普通网页路径处理。需要四层转发时,应使用明确支持 TCP/UDP 的转发能力。

脱敏后的 Docker Compose

下面的配置保留了实际部署需要的关键结构,但域名、路径和地址全部换成示例值。为了兼容 Windows 与 macOS 的 Docker Desktop,这里使用显式端口映射;在确认网络模型后,Linux 用户也可以按官方建议评估 host 网络。

services:
  rustdesk:
    image: lejianwen/rustdesk-server-s6:latest
    container_name: rustdesk-server-s6
    restart: unless-stopped
    ports:
      - "21114:21114/tcp"
      - "21115:21115/tcp"
      - "21116:21116/tcp"
      - "21116:21116/udp"
      - "21117:21117/tcp"
      - "21118:21118/tcp"
      - "21119:21119/tcp"
    environment:
      RELAY: rustdesk.example.com:21117
      ENCRYPTED_ONLY: "1"
      MUST_LOGIN: "N"
      TZ: Asia/Shanghai
      RUSTDESK_API_LANG: zh-CN
      RUSTDESK_API_ADMIN_TITLE: RustDesk Console
      RUSTDESK_API_RUSTDESK_ID_SERVER: rustdesk.example.com:21116
      RUSTDESK_API_RUSTDESK_RELAY_SERVER: rustdesk.example.com:21117
      RUSTDESK_API_RUSTDESK_API_SERVER: https://api.example.com
      RUSTDESK_API_RUSTDESK_WS_HOST: wss://ws.example.com
      RUSTDESK_API_KEY_FILE: /data/id_ed25519.pub
      RUSTDESK_API_APP_TOKEN_EXPIRE: 168h
    volumes:
      - ./data/server:/data
      - ./data/api:/app/data
      - ./logs:/app/runtime

部署前必须理解几项变量:

部署完成后,第一件事不是远控,而是检查

启动容器:

docker compose pull
docker compose up -d
docker compose ps
docker compose logs --tail=200 rustdesk

接着检查持久化目录中是否生成公钥:

test -s ./data/server/id_ed25519.pub && cat ./data/server/id_ed25519.pub

公钥需要填入客户端的自建服务器配置。私钥绝对不要复制到客户端、文章、工单或聊天记录中。

社区管理后台首次启动时可能在日志中提示初始化信息。登录后应立即修改默认密码,关闭不需要的注册入口,并确认地址簿、登录日志和设备页面没有暴露到不受信任网络。

真实截图:社区 RustDesk API 项目公开的 Web 管理后台示例

客户端如何配置

客户端通常需要三类信息:

如果启用了社区 API 账号、地址簿或 Web Client,还要配置 API Server。这里最容易犯的错误,是把网页后台地址误填进 ID Server,或把 https:// 前缀写进只接受主机和端口的字段。

最稳妥的测试顺序是:

就像新房验收:先确认水电和门锁,再测试智能音箱。基础通信没有通过时,过早调 WebSocket 和 OIDC 只会把问题混在一起。

常见问题表现、分析与真正根因

原创排障图:从症状到证据逐层确认,不靠猜配置

客户端一直显示未就绪

先检查域名解析、21116/TCP21116/UDP 和容器日志。真正的判断标准不是“网页能打开”,而是客户端是否成功向 hbbs 登记并维持心跳。

常见根因包括:域名仍指向旧地址、防火墙只放行 TCP、路由器转发到了错误主机、容器端口未映射,或客户端配置里混入了协议前缀。

能看到设备,但连接超时

这说明“电话簿里能找到人”,不代表“电话已经接通”。查看 hbbshbbr 日志,区分是直连协商失败,还是 Relay 也无法建立。

如果 Relay 可用而直连失败,重点检查 UDP、双重 NAT、运营商级 NAT、企业防火墙和对称 NAT。不要因为最终能连上就误判 P2P 正常。

只能走 Relay,服务器流量很高

先确认 21116/UDP 是否双向可达,再检查路由器端口映射和多层路由。家庭宽带中的“光猫路由一次、自己的路由器再路由一次”就像小区门口有两道互不沟通的门卫,双方很难直接确认彼此位置。

如果网络条件决定无法稳定打洞,Relay 并不是错误;只需要按实际并发和分辨率准备带宽,并把服务器部署到两端延迟都能接受的位置。

网页后台能打开,Web 远控却失败

网页加载成功只证明 HTTP 路径正常。Web Client 还依赖 WebSocket、证书、Host、Origin 和反向代理的 Upgrade 头。它们就像商场正门和地下卸货通道:正门能进,不代表货车通道也已经放行。

检查浏览器开发者工具中的 WebSocket 状态、反向代理日志、证书域名与 RUSTDESK_API_RUSTDESK_WS_HOST。不要把 API URL 和 WebSocket URL 当成同一个字段随意互换。

账号登录失败或突然被拒绝

检查 API 服务时间、Token 有效期、验证码与封禁策略、代理后的真实来源地址,以及 /app/runtime 日志。若反向代理没有正确传递来源地址,所有用户可能被识别成同一个代理 IP,一次封禁就像门卫把整辆大巴上的人全部拒之门外。

安全加固:自建不等于天然安全

自建只是把责任从别人手里拿回来,并不会自动完成安全工作。至少应做到:

如果把容器比作租来的办公室,镜像只是装修图纸,数据卷才是保险柜。办公室烧了可以按图重建,保险柜没备份就真的没了。

三个平台的一键部署脚本

三套脚本使用相同的 Compose 模型,不会上传配置、扫描局域网或调用额外管理服务。它们需要从容器镜像仓库拉取社区镜像;Windows 和 macOS 需要已经启动 Docker Desktop,Ubuntu 脚本可在缺少 Docker 时尝试使用系统软件仓库安装。

Ubuntu 示例:

sudo bash install-rustdesk-ubuntu2604.sh \
  rustdesk.example.com \
  https://api.example.com \
  wss://ws.example.com

Windows 11 示例:

.\install-rustdesk-windows11.ps1 `
  -PublicHost rustdesk.example.com `
  -ApiUrl https://api.example.com `
  -WsUrl wss://ws.example.com

macOS 26 示例:

zsh install-rustdesk-macos26.zsh \
  rustdesk.example.com \
  https://api.example.com \
  wss://ws.example.com

Windows 与 macOS 更适合实验、演示或确实会长期在线的桌面主机。面向公网的长期生产服务,优先选择有稳定网络、备份、监控与系统更新流程的 Linux 服务器。

人工自动执行:复制命令,但每一步都看得见

如果不想直接运行下载脚本,可以采用“人工自动”方式:

这种方式像使用洗衣机的“自动程序”,但在按开始前仍然确认衣服口袋、洗涤剂和水龙头。自动化负责重复动作,人负责确认前提没有错。

Agent 自动配置:把下面这段交给本机 Agent

请在当前机器部署 RustDesk 社区多合一服务端。

约束:
- 先只读检查操作系统、Docker、Docker Compose、现有端口占用和目标目录。
- 不显示或上传完整 IP、私有域名、主机名、密钥、Token、Cookie 和密码。
- 不删除现有容器、网络、卷或防火墙规则。
- 使用 lejianwen/rustdesk-server-s6 镜像,但在执行前展示镜像名、计划和回滚方法。
- 使用参数化 compose.yaml;持久化 server data、API data 和 runtime logs。
- 同时映射 21116/TCP 与 21116/UDP。
- 先运行 docker compose config,确认成功后再启动。
- 启动后检查容器状态、最近日志、公钥文件和监听端口。
- 不回显私钥;只说明公钥文件位置。
- 如果发现端口冲突、Docker 未启动或已有同名服务,停止并报告,不要覆盖。

目标配置:
- ID/Relay 主机:rustdesk.example.com
- API 地址:https://api.example.com
- WebSocket 地址:wss://ws.example.com
- 时区:Asia/Shanghai
- 只允许加密连接
- 默认不强制账号登录

完成后给出:改管理员密码、客户端填写 ID/Relay/Key、外网验证、备份和升级回滚清单。

Agent 的价值不是“替你猜地址”,而是把检测、生成、启动和验证变成可重复流程。遇到端口冲突或未知环境时,正确行为是停下来报告,而不是为了完成任务强行覆盖。

备份、升级与回滚

升级前:

docker compose ps
docker image inspect lejianwen/rustdesk-server-s6:latest --format '{{.Id}}'
tar -C . -czf rustdesk-backup-$(date +%Y%m%d-%H%M%S).tar.gz \
  compose.yaml .env data logs

升级时先拉取镜像,再重新创建容器:

docker compose pull
docker compose up -d
docker compose logs --tail=200 rustdesk

验证失败时,恢复备份的 Compose、环境文件与数据,再使用之前记录的镜像摘要启动。不要只备份 SQLite 文件而忘记服务端密钥;客户端信任的是那把钥匙,钥匙变了,就像整栋楼突然换了门锁。

Q&A

RustDesk 自建后还需要公网 IP 吗?

服务端必须能被客户端访问,但不一定要求家庭宽带直接拥有固定公网 IPv4。可以使用云服务器、可达的 IPv6、端口映射或合适的组网方案。无论选择哪种方式,客户端填写的地址必须真正可达。

可以只开放 2111621117 吗?

如果只使用桌面客户端的基础 ID 与 Relay 能力,可以按实际功能缩小暴露面;但 NAT 测试、Web 管理、Web Client 与 WebSocket 会涉及其他端口。不要照抄端口表后全部开放,也不要在不理解用途时随意关闭。

为什么建议 Ubuntu,而文章还提供 Windows 和 macOS 脚本?

因为三种平台都可以运行 Docker,但“能跑”与“适合长期公网生产”不是同一件事。Windows 与 macOS 脚本方便测试和家庭常开机;Ubuntu 更容易实现无桌面运行、系统服务、自启动、防火墙、监控与自动备份。

多合一容器是不是比三个容器更安全?

不是。容器数量减少只代表运维入口更少,不代表攻击面自动消失。安全性取决于镜像来源、版本、配置、端口、密码、日志、备份与更新速度。

强制登录应该打开吗?

如果团队需要统一账号审计,可以评估 MUST_LOGIN 与 JWT;如果只是家庭设备,先把基础加密、密钥、无人值守密码和网络访问控制做好。强制登录是一套认证设计,不是一个孤立开关。

最后总结

RustDesk 自建服务端真正值得学习的,不是某一份 Compose,而是远程连接背后的分层思路:hbbs 负责“找到对方”,P2P 负责“尽量直接说话”,hbbr 负责“实在不行就中转”,API 与 Web 则负责账号和管理体验。

多合一镜像把这些岗位放进一个容器,降低了第一次部署的门槛,但没有取消网络、安全、备份和升级责任。先理解连接路径,再开放端口;先验证基础客户端,再接反向代理和 Web Client;先备份密钥和数据,再谈升级。做到这些,自建远程桌面才不是“又多养了一个容器”,而是真正多了一条自己掌握的远程通道。

参考资料