【实用的开源工具】RustDesk 自建服务器:把远程桌面的 ID 和中继放在自己手里
「实用的开源工具」系列:我只收集值得用的开源项目,写清楚它能做什么、怎么部署、有哪些坑,并在文末标明出处。内容整理自官方文档,核对日期 2026-10-31,具体版本以官方为准。这篇只讲服务端(自建 ID 服务器和中继服务器),客户端只涉及“怎么指向你的服务器”。
项目信息卡
| 项目 | 说明 |
|---|---|
| 名称 | RustDesk(客户端)与 RustDesk Server OSS(服务端) |
| 做什么 | 远程桌面软件。服务端负责让两台设备互相找到对方(ID/信令),直连不通时再中继流量 |
| 许可证 | GitHub 上显示:客户端仓库 rustdesk/rustdesk 是 AGPL-3.0;服务端仓库 rustdesk/rustdesk-server 也是 AGPL-3.0(两个仓库都带 AGPL v3 的许可证文件)。其他仓库或闭源部分我没有逐个核对 |
| 服务端最近版本 | 1.1.16(2026-07-20 发布,查询于 2026-10-31);客户端最近版本 1.5.0(2026-09-30 发布) |
| 项目状态 | 两个仓库都未归档,客户端最近一次推送是 2026-10-31,服务端是 2026-10-10 |
| 服务端组成 | hbbs:ID/会合(信令)服务器;hbbr:中继服务器;仓库里还有命令行工具 rustdesk-utils |
| 官方镜像 | rustdesk/rustdesk-server(只含程序)、rustdesk/rustdesk-server-s6(用 s6 同时启动两个程序,并带几个便利变量) |
| 需要开放的端口 | 至少 TCP 21115、21116、21117 和 UDP 21116,必须对公网开放(详见下文) |
| OSS 与 Pro | 官方文档把服务端分成两个选项:RustDesk Server OSS(免费开源,含 hbbs 和 hbbr,社区支持,手动部署)和 RustDesk Server Pro(面向企业,有网页控制台、API、OIDC、LDAP、2FA、设备管理、访问控制、多中继管理等)。这篇只讲 OSS |
它能做什么
官方的说明是:自建后你自己掌握 ID 和中继基础设施,把部署数据留在自己管理的系统上。它的工作方式(文档原意):
- 只要设备上的 RustDesk 在运行,就会不断向 ID 服务器(
hbbs)报告自己当前的地址和端口。 - 设备 A 要连设备 B 时,先问 ID 服务器,ID 服务器尝试让两边通过“打洞”直接连接。
- 打洞失败时,才通过中继服务器(
hbbr)转发。文档说大多数情况下打洞能成功,中继用不上。
适合:自己有一台公网 IP 的小服务器,想让自己的 RustDesk 客户端走自己的服务器。不适合:想要网页管理后台、账号体系、设备分组的人,这些在官方文档里属于 Pro。
端口:哪些必须对外
官方文档给的端口表(OSS 相关的部分):
| 端口 | 协议 | 属于 | 用途 |
|---|---|---|---|
| 21115 | TCP | hbbs | NAT 类型测试 |
| 21116 | TCP 和 UDP | hbbs | UDP 用于 ID 注册和心跳;TCP 用于 TCP 打洞和连接服务。TCP 和 UDP 都要开 |
| 21117 | TCP | hbbr | 中继 |
| 21118 | TCP | hbbs | WebSocket,仅为网页客户端 |
| 21119 | TCP | hbbr | WebSocket,仅为网页客户端 |
| 21114 | TCP | hbbs | 仅 Pro 的网页控制台/API,OSS 用不到 |
官方原话:21115 到 21117 是让 RustDesk 能工作的最低要求端口,负责信令、中继和 NAT 穿透。不用网页客户端,21118 和 21119 就不用开。
和“反向代理后面只暴露 127.0.0.1”不同,这里的 21115 到 21117 必须对公网可达,客户端要直接连这些端口。
官方安装页给的 ufw 命令是开放 21114:21119/tcp 和 21116/udp。按上面的表,OSS 只用最小集合时可以这样写(这是我根据端口表缩小的,不是官方原文):
ufw allow 21115:21117/tcp
ufw allow 21116/udp安全警告(官方文档原文意思): 打开 21118/21119 时,
hbbs/hbbr会信任 WebSocket 连接里的X-Real-IP和X-Forwarded-For头来判断客户端 IP,而且不验证这些头。直接能访问这两个端口的人可以伪造任意 IP,绕过按 IP 的限速和封禁,也会让日志里的 IP 失真。所以用网页客户端时,这两个端口只应通过一个自己设置X-Real-IP的反向代理暴露,并用防火墙限制只有代理能连;不用网页客户端就保持关闭。
部署(Docker Compose)
官方文档的结论:多数 Linux 服务器上,Docker Compose 加 network_mode: "host" 是最简单可靠的方式。先建目录:
mkdir -p /opt/rustdesk && cd /opt/rustdeskcompose.yaml(结构来自官方 Docker 文档,我只把镜像从 latest 改成固定版本 1.1.16):
services:
hbbs:
container_name: hbbs
image: rustdesk/rustdesk-server:1.1.16
command: hbbs
volumes:
- ./data:/root
network_mode: "host"
depends_on:
- hbbr
restart: unless-stopped
hbbr:
container_name: hbbr
image: rustdesk/rustdesk-server:1.1.16
command: hbbr
volumes:
- ./data:/root
network_mode: "host"
restart: unless-stopped启动:
docker compose up -d
docker compose logs hbbs- 我在 Docker Hub 的标签列表里看到
1.1.16、1和latest,与 GitHub 最近版本一致;你部署时请再确认标签存在。 - 官方文档说明
--net=host只在 Linux 上有效,好处是hbbs/hbbr能看到真实的来访 IP,而不是容器 IP(172.17.0.1)。遇到连接问题的平台可以去掉它;去掉后就要自己写ports映射。官方仓库里的docker-compose.yml就是不用 host 网络的写法:映射 21115、21116(TCP 和 UDP)、21118、21117、21119,并给hbbs加上-r rustdesk.example.com:21117。 - 因为是 host 网络,上面没有
ports,也就无法像其他文章那样“只绑定 127.0.0.1”。端口是否对外,要靠防火墙控制。 ./data同时挂给hbbs和hbbr(容器内/root)。官方文档说明hbbs首次运行时在工作目录或数据目录里生成密钥文件。
没有 Compose 时,官方也给了 docker run 的写法:
sudo docker run --name hbbs -v ./data:/root -td --net=host --restart unless-stopped rustdesk/rustdesk-server hbbs
sudo docker run --name hbbr -v ./data:/root -td --net=host --restart unless-stopped rustdesk/rustdesk-server hbbr官方还提供了 Podman Quadlet 示例、Windows(PM2 或 NSSM)、Synology 的部署文档,见文末出处。
第一次使用:拿公钥,填到客户端
1. 拿公钥。 官方说明:密钥通常在 hbbs 第一次运行时生成,放在数据目录里的 id_ed25519.pub。按上面的 Compose,就是:
cat /opt/rustdesk/data/id_ed25519.pub同目录的 id_ed25519 是私钥,不要外传,只把 .pub 里的内容给客户端。官方还特别说明,这个 Key 是用于连接加密的公钥,和购买 Pro 时拿到的授权 key 不是一回事。
2. 客户端设置。 官方的手动配置步骤:在 RustDesk 主界面,点自己 ID 旁边的菜单按钮 ⋮,进入 Network,用管理员权限解锁后填写:
| 字段 | 填什么 |
|---|---|
ID Server | 你的 hbbs 主机名或 IP,例如 hbbs.example.com,也可以带端口 hbbs.example.com:21116。连接两端(本机和被控端)都要填 |
Relay Server | 可以留空,RustDesk 会自动推断;它指的是 hbbr(端口 21117) |
API Server | 仅 Pro 用 |
Key | 上一步 id_ed25519.pub 的内容 |
- 批量配置。 官方文档列出了导出再导入服务器配置(设置 → Network → 解锁 → Export/Import Server Config,再点 Apply)、部署脚本,以及命令行
rustdesk.exe --config <配置串>。配置串可以从客户端 “Settings → Network” 得到。定制客户端生成器是 Pro 才有的功能。
- 验证:两台设备都配置好后,互相用对方的 ID 连一次。如果连不上,先回头核对端口、公钥和两端的 ID Server。
反向代理?一般不需要
RustDesk 的 21115 到 21117 是 TCP/UDP 直连端口,不是普通的 HTTP 服务,没有“前面套个 Nginx 就行”的做法。官方文档里的反向代理只用于 WebSocket(网页客户端等):它写的示例是把 /ws/id 转发到 http://127.0.0.1:21118,把 /ws/relay 转发到 http://127.0.0.1:21119,并带上 Upgrade、Connection、X-Real-IP、X-Forwarded-For 等头。这个示例出现在官方 Pro 的 FAQ 页面里,我没有核实它是否同样适用于 OSS 的网页客户端,所以这里不展开,请直接看原文。
官方还提到一种只开 TCP 443 的方式:所有通信走 WSS 中继,此时没有点对点直连。
可选配置
下面都来自仓库的 docs/environment-variables.md,其中带 🅴 的变量只能通过进程环境设置。要在 Compose 里加,可以像官方示例那样写 environment:。
| 变量 | 说明 |
|---|---|
ALWAYS_USE_RELAY | Y 强制所有会话走中继(禁用直连打洞),默认 N |
RELAY-SERVERS(或 -r) | 中继用了不同地址或非标准端口时才需要设置;中继与 hbbs 同地址、端口 21117 时留空即可 |
KEY(或 -k) | hbbs 默认值是 -,即加载或生成密钥对 |
PORT(或 -p) | 主端口,hbbs 默认 21116,会同时占用 PORT-1(NAT 测试)和 PORT+2(WebSocket);hbbr 默认 21117 |
RUST_LOG | 日志级别,默认 info;必须设在进程环境里,写在 .env 或配置文件里无效 |
DB_URL | SQLite 数据库路径,默认 ./db_v2.sqlite3 |
中继的带宽限制也有默认值(单位 Mb/s):SINGLE_BANDWIDTH 128,TOTAL_BANDWIDTH 1024,LIMIT_SPEED 32。文档说明单个连接过了 DOWNGRADE_START_CHECK(默认 1800 秒)之后,平均速度超过 SINGLE_BANDWIDTH * DOWNGRADE_THRESHOLD 就会被限到 LIMIT_SPEED,即使中继本身很空闲。
资源方面,官方安装页的说法:硬件要求很低,最小配置的云服务器就够,树莓派也行;流量取决于打洞是否成功,走中继时一路连接大约 30 K/s 到 3 M/s(1920x1080 屏幕,取决于分辨率设置和画面变化),纯办公大约 100 K/s。
更新与卸载
官方文档说 Docker 是升级最简单、也最容易回滚的方式,但我没有读到专门的升级步骤,下面是通用做法。
更新:
cd /opt/rustdesk
cp -a data data.bak-$(date +%F) # 先备份密钥和数据库
# 把 compose.yaml 里两处镜像标签改成新版本(先确认标签存在)
docker compose pull
docker compose up -ddata/ 里有 id_ed25519、id_ed25519.pub 和 SQLite 数据库。只要密钥不变,客户端就不用重新配置。
卸载:
cd /opt/rustdesk
docker compose down- 之后再删防火墙里的规则,例如
ufw delete allow 21116/udp,逐条对应你当时开的规则。 - 删除
data/目录就等于丢掉私钥,以后重装会生成新密钥,所有客户端都要换成新的公钥(这是我据官方的密钥说明做的推断)。
踩坑清单
- 21116 要同时开 TCP 和 UDP。 官方强调:UDP 用于 ID 注册和心跳,TCP 用于打洞和连接服务,漏一个都会出问题。
- 最低要开的是 21115 到 21117。 21114 仅 Pro 使用,21118 和 21119 仅网页客户端使用,不用就不要开。
- WebSocket 端口会被伪造 IP。 官方警告:21118/21119 信任未验证的
X-Real-IP/X-Forwarded-For,直接暴露会让别人伪造 IP,绕过限速和封禁。 - 客户端必须填公钥,而且两端都要填 ID Server。 官方原话是 ID Server 要在“本地和远程两边”都填;
Key是id_ed25519.pub里的公钥,不是 Pro 的授权 key。 hbbr默认不校验密钥。 环境变量文档说,hbbr的KEY默认是空,这是有意的,目的是避免密钥配对出错;代价是没有匹配密钥的客户端也能用你的中继,在暴露到公网的服务器上要自己权衡。要开启,需要给hbbr设置和hbbs相同的非空密钥(-k),我没有逐步验证这种配置。- host 网络只在 Linux 上有效。 官方说明
--net=host只在 Linux 生效;有连接问题的平台去掉它,再自己写端口映射。 - 在家里或办公室内网搭,同一局域网内可能连不上自己的公网域名。 官方有一篇 NAT Loopback 文档:服务器放在 NAT 后面时,服务端和客户端要么用内网 IP 互访,要么路由器支持并开启 NAT 回环(hairpin)。解决办法按官方顺序是:路由器开 NAT 回环、局域网内部署 DNS(AdGuard Home 或 Pi-hole)把域名指到内网 IP、或者改 hosts 文件(只适合少数设备,笔记本带到外面就连不上了)。
- 别把官方文档里的
latest当成固定版本。 生产环境建议固定版本。注意文档与版本可能不同步:环境变量文档里提到BIND(指定监听地址)“自 1.1.17 起可用”,而最近的发布是 1.1.16,所以你用 1.1.16 时不要依赖这个变量。 - s6 镜像和普通镜像支持的变量不同。
RELAY、ENCRYPTED_ONLY、KEY_PUB、KEY_PRIV只在rustdesk/rustdesk-server-s6镜像里有效,普通的rustdesk/rustdesk-server镜像会忽略它们;s6 镜像的数据目录是/data,普通镜像文档示例挂的是/root。 RUST_LOG写进.env无效。 环境变量文档明确说它必须在启动前的进程环境里设置。- 别混淆
DB_URL和DATABASE_URL。 官方说明运行时只读DB_URL;仓库.env里的DATABASE_URL只用于编译时检查 SQL,设置了也没用。 - 私钥和数据库要备份。
id_ed25519丢了,所有客户端都要换成新的公钥(据官方密钥说明的推断)。 - 第三方一键脚本要慎用。 官方安装页提到的 install.sh 托管在 Techahold 的仓库,并非 RustDesk 官方仓库;运行任何脚本前先读一遍,这是通用建议。
- AGPL-3.0 对修改后提供网络服务的人有要求。 如果你只是自己用官方镜像,一般不涉及;如果要改源码并对外提供服务,请自己读许可证全文,或咨询懂行的人(通用提醒,不是法律意见)。
出处
- RustDesk 官方文档:Self-host(组成、端口、OSS 与 Pro 对比)
- 官方文档:RustDesk Server OSS
- 官方文档:OSS 安装(防火墙、资源与流量)
- 官方文档:OSS Docker 部署
- 官方文档:客户端配置(ID Server、Key、导入导出、--config)
- 官方文档:NAT Loopback 问题
- 官方文档:Pro FAQ(含 WSS 的 Nginx 示例)
- rustdesk-server 仓库(README、AGPL-3.0)
- rustdesk-server:配置与环境变量文档
- rustdesk-server:官方 docker-compose.yml
- RustDesk 客户端仓库(AGPL-3.0)
有想法或问题?去留言板留言 →