Skip to content

配置 RustDesk Server OSS

目标:在 Ubuntu 上部署 RustDesk Server OSS,运行 hbbshbbr,让客户端通过固定域名接入自建 ID / Relay 服务。

适用范围:

  • 免费开源服务端 RustDesk Server OSS。
  • 使用官方二进制文件和 systemd 管理服务。
  • RustDesk 文件统一放在 /root/rustdesk
  • Nginx 用于可选的 Web Client WSS 反向代理。

RustDesk Server Pro 还包含 Web Console、API、数据库、授权等内容,迁移时不能只复制 OSS 服务端文件。

核心概念

  • hbbs 是 ID / 信令服务器,客户端会不断向它注册自己的 RustDesk ID、当前地址和端口。
  • hbbr 是中继服务器,直连或打洞失败时才走中继。
  • id_ed25519 是服务端私钥,id_ed25519.pub 是给客户端填写的公钥。私钥仅保存在服务端。

客户端最小配置:

text
ID Server: rustdesk.example.com:21116
Relay Server: rustdesk.example.com:21117
Key: id_ed25519.pub 文件内容

Relay Server 可以留空,由 hbbs 返回;使用非默认端口时,显式填写更稳妥。

1. 准备域名和端口

确定三个变量:

bash
RUSTDESK_HOST=rustdesk.example.com
HBBS_PORT=21116
RUSTDESK_DIR=/root/rustdesk

默认端口关系如下:

用途协议默认端口说明
NAT 类型检测TCP21115HBBS_PORT - 1
hbbs 主端口TCP/UDP21116客户端 ID 注册、心跳、打洞
hbbr 主端口TCP21117中继流量
hbbs WebSocketTCP21118Web Client 可选
hbbr WebSocketTCP21119Web Client 可选

DNS 里添加:

  • A 记录:rustdesk.example.com 指向服务器公网 IPv4。
  • 仅使用 IPv4 时,不创建 AAAA 记录。
  • 创建 AAAA 记录时,防火墙和 Nginx 必须同时支持 IPv6。

2. 安装服务端二进制

以下命令默认以 root 执行:

bash
sudo -i

apt update
apt install -y curl unzip

mkdir -p /root/rustdesk
cd /root/rustdesk

TAG=$(curl -fsSL https://api.github.com/repos/rustdesk/rustdesk-server/releases/latest \
  | sed -n 's/.*"tag_name":[[:space:]]*"\([^"]*\)".*/\1/p' \
  | head -n1)

curl -fL -o rustdesk-server-linux-amd64.zip \
  "https://github.com/rustdesk/rustdesk-server/releases/download/${TAG}/rustdesk-server-linux-amd64.zip"

unzip -o rustdesk-server-linux-amd64.zip
chmod 755 ./amd64/hbbs ./amd64/hbbr ./amd64/rustdesk-utils

下载完成后应有:

text
/root/rustdesk/amd64/hbbs
/root/rustdesk/amd64/hbbr
/root/rustdesk/amd64/rustdesk-utils

3. 生成服务端密钥

新服务器第一次部署时生成一对密钥:

bash
cd /root/rustdesk

./amd64/rustdesk-utils genkeypair | awk -F': ' '
/^Public Key:/ {print $2 > "id_ed25519.pub"}
/^Secret Key:/ {print $2 > "id_ed25519"}
'

chmod 600 /root/rustdesk/id_ed25519
chmod 644 /root/rustdesk/id_ed25519.pub

检查公钥:

bash
cat /root/rustdesk/id_ed25519.pub

输出内容填入客户端网络设置里的 Key/root/rustdesk/id_ed25519 是服务端私钥,不填入客户端。

迁移旧服务器时跳过本节密钥生成,直接复制旧服务器的 id_ed25519id_ed25519.pub,操作见“完整迁移到新服务器”。

4. 写入统一环境文件

bash
cat >/root/rustdesk/rustdesk.env <<'EOF'
RUSTDESK_HOST=rustdesk.example.com
HBBS_PORT=21116
HBBS_MAX_PACKET=52428800
EOF

按实际情况修改:

  • RUSTDESK_HOST:客户端访问的域名。
  • HBBS_PORThbbs 主端口,默认 21116
  • HBBS_MAX_PACKET:最大包大小,一般保持示例值。

5. 创建 systemd 服务

创建 hbbs 服务:

bash
cat >/etc/systemd/system/rustdesk-hbbs.service <<'EOF'
[Unit]
Description=RustDesk ID/Signal Server (hbbs)
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=root
Group=root
WorkingDirectory=/root/rustdesk
EnvironmentFile=/root/rustdesk/rustdesk.env
ExecStart=/bin/sh -lc 'exec /root/rustdesk/amd64/hbbs -p "${HBBS_PORT}" -r "${RUSTDESK_HOST}:$((HBBS_PORT + 1))" -M "${HBBS_MAX_PACKET}" -k _'
Restart=always
RestartSec=2
LimitNOFILE=100000

[Install]
WantedBy=multi-user.target
EOF

创建 hbbr 服务:

bash
cat >/etc/systemd/system/rustdesk-hbbr.service <<'EOF'
[Unit]
Description=RustDesk Relay Server (hbbr)
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=root
Group=root
WorkingDirectory=/root/rustdesk
EnvironmentFile=/root/rustdesk/rustdesk.env
ExecStart=/bin/sh -lc 'exec /root/rustdesk/amd64/hbbr -p "$((HBBS_PORT + 1))" -k _'
Restart=always
RestartSec=2
LimitNOFILE=100000

[Install]
WantedBy=multi-user.target
EOF

服务关键点:

  • WorkingDirectory=/root/rustdesk 必须指向密钥所在目录,服务会从这里读取 id_ed25519id_ed25519.pub
  • hbbs -r "${RUSTDESK_HOST}:$((HBBS_PORT + 1))" 用于返回中继服务器地址。hbbr 不在默认推导路径上时必须显式配置。
  • -k _ 表示使用工作目录里的服务端密钥文件。

启动服务:

bash
systemctl daemon-reload
systemctl enable --now rustdesk-hbbs rustdesk-hbbr
systemctl status rustdesk-hbbs rustdesk-hbbr --no-pager

6. 放行防火墙端口

原生客户端最小可用端口:

bash
. /root/rustdesk/rustdesk.env

ufw allow $((HBBS_PORT - 1)):$((HBBS_PORT + 1))/tcp
ufw allow ${HBBS_PORT}/udp
ufw --force enable
ufw reload

默认端口对应:

text
21115-21117/tcp
21116/udp

使用 Web Client,并且由同机 Nginx 反向代理 2111821119 时,公网额外放行:

bash
ufw allow 80/tcp
ufw allow 443/tcp
ufw reload

公网无需直接暴露 2111821119

7. 验证服务端

查看监听端口:

bash
. /root/rustdesk/rustdesk.env

ss -lntup | grep -E ":($((HBBS_PORT - 1))|${HBBS_PORT}|$((HBBS_PORT + 1))|$((HBBS_PORT + 2))|$((HBBS_PORT + 3)))\\b"

查看日志:

bash
journalctl -u rustdesk-hbbs -u rustdesk-hbbr -n 100 --no-pager
journalctl -u rustdesk-hbbs -u rustdesk-hbbr -f

从外部机器测试端口:

bash
nc -vz rustdesk.example.com 21115
nc -vz rustdesk.example.com 21116
nc -vz rustdesk.example.com 21117

UDP 端口不能只靠 nc -vz 判断,最终以两台客户端实际接入为准。

8. 配置客户端

在 RustDesk 客户端进入:

text
设置 -> 网络 -> 解锁网络设置

填写:

  • ID Serverrustdesk.example.com:21116
  • Relay Serverrustdesk.example.com:21117
  • API Server:OSS 留空,Pro 才需要。
  • Key/root/rustdesk/id_ed25519.pub 的内容。

控制端和被控端都要填同一组服务器信息。只配置一端是不够的,因为双方都需要向同一个 hbbs 注册。

推荐的客户端安全设置:

  • 设置固定密码,或者使用确认连接。
  • 禁止普通用户修改设备 ID。
  • 关闭不需要的局域网发现。
  • 不需要 IP 直连时关闭 IP 直连访问。

推荐的客户端网络设置:

  • 开启 UDP 打洞。
  • 网络支持 IPv6 时开启 IPv6 P2P。

9. 可选:配置 Web Client

OSS 服务端没有自带 Web 前端。浏览器访问的是 RustDesk 官方 Web Client:

text
https://rustdesk.com/web

使用 Web Client 前,先在页面右上角菜单里配置自建服务器的 ID ServerKey。未配置时会连接 RustDesk 公共服务器。

Web Client 还需要通过 HTTPS 访问自建服务器的 WebSocket:

  • wss://rustdesk.example.com/ws/id -> 本机 21118
  • wss://rustdesk.example.com/ws/relay -> 本机 21119

安装 Nginx 和 Certbot:

bash
apt update
apt install -y nginx certbot python3-certbot-nginx
ufw allow 80/tcp
ufw allow 443/tcp
ufw reload

先创建用于签证书的 HTTP 配置:

bash
cat >/etc/nginx/sites-available/rustdesk-wss.conf <<'EOF'
server {
    listen 80;
    listen [::]:80;
    server_name rustdesk.example.com;

    location / {
        default_type text/plain;
        return 200 "rustdesk-wss\n";
    }
}
EOF

rm -f /etc/nginx/sites-enabled/default
ln -sf /etc/nginx/sites-available/rustdesk-wss.conf /etc/nginx/sites-enabled/rustdesk-wss.conf
nginx -t
systemctl reload nginx
certbot --nginx -d rustdesk.example.com

证书签发后,把配置替换为 WSS 反向代理:

bash
cat >/etc/nginx/sites-available/rustdesk-wss.conf <<'EOF'
server {
    listen 80;
    listen [::]:80;
    server_name rustdesk.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name rustdesk.example.com;

    ssl_certificate /etc/letsencrypt/live/rustdesk.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/rustdesk.example.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    location / {
        if ($http_origin ~* (https?://(www\.)?rustdesk\.com)) {
            add_header Access-Control-Allow-Origin "$http_origin" always;
            add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, PATCH, OPTIONS" always;
            add_header Access-Control-Allow-Headers "Origin, Content-Type, Accept, Authorization" always;
            add_header Access-Control-Allow-Credentials "true" always;
        }

        if ($request_method = OPTIONS) {
            add_header Access-Control-Allow-Origin "$http_origin" always;
            add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, PATCH, OPTIONS" always;
            add_header Access-Control-Allow-Headers "Origin, Content-Type, Accept, Authorization" always;
            add_header Access-Control-Allow-Credentials "true" always;
            add_header Content-Length 0;
            return 204;
        }

        default_type text/plain;
        return 200 "rustdesk-wss\n";
    }

    location /ws/id {
        proxy_pass http://127.0.0.1:21118;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 120s;
    }

    location /ws/relay {
        proxy_pass http://127.0.0.1:21119;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 120s;
    }
}
EOF

HBBS_PORT 变更时,这里的 2111821119 同步改成 HBBS_PORT + 2HBBS_PORT + 3

验证:

bash
nginx -t
systemctl reload nginx
curl -I https://rustdesk.example.com/

10. 完整迁移到新服务器

OSS 服务端迁移的核心是保持“同域名、同端口、同密钥对”。满足这些条件后,客户端网络配置可以保持不变。

迁移条件:

  • 客户端配置的是域名,例如 rustdesk.example.com:21116,不是旧服务器 IP。
  • 新旧服务器使用同一对 id_ed25519id_ed25519.pub
  • 新服务器开放相同端口。
  • hbbs-r 返回相同域名和中继端口。
  • DNS 最终指向新服务器。

迁移影响:

  • 正在进行的远控会话可能中断。
  • DNS 缓存未过期前,部分客户端可能还连到旧服务器。
  • 新旧服务器同时在线时,客户端可能分散注册到两边,彼此短时间内看不到。迁移窗口内降低 DNS TTL,并在切换后停止旧服务器,可以减少分裂注册。

10.1 迁移前准备

提前一天把 DNS TTL 调低,例如 60300 秒。递归 DNS 不一定严格遵守 TTL,低 TTL 只能降低切换时间,不能保证即时生效。

在旧服务器 A 上确认文件:

bash
cd /root/rustdesk
ls -l id_ed25519 id_ed25519.pub rustdesk.env
sha256sum id_ed25519 id_ed25519.pub

打包需要迁移的核心文件:

bash
tar -C /root -czf /root/rustdesk-migrate.tgz \
  rustdesk/id_ed25519 \
  rustdesk/id_ed25519.pub \
  rustdesk/rustdesk.env

Web Client 场景还需要迁移或重建:

  • /etc/nginx/sites-available/rustdesk-wss.conf
  • HTTPS 证书,或者在 B 上用 DNS-01 / 切换后 HTTP-01 重新签发。
  • ufw 或云厂商安全组相关的端口规则。

10.2 在新服务器 B 上安装服务

在 B 上执行“安装服务端二进制”,跳过“生成服务端密钥”。

把 A 的迁移包复制到 B:

bash
scp root@A_IP:/root/rustdesk-migrate.tgz /root/

mkdir -p /root/rustdesk
tar -C /root -xzf /root/rustdesk-migrate.tgz
chmod 600 /root/rustdesk/id_ed25519
chmod 644 /root/rustdesk/id_ed25519.pub

在 B 上创建与 A 相同的 systemd 服务并启动:

bash
systemctl daemon-reload
systemctl enable --now rustdesk-hbbs rustdesk-hbbr
journalctl -u rustdesk-hbbs -u rustdesk-hbbr -n 100 --no-pager

确认 B 上公钥与 A 一致:

bash
sha256sum /root/rustdesk/id_ed25519 /root/rustdesk/id_ed25519.pub
cat /root/rustdesk/id_ed25519.pub

B 不得生成新密钥。新密钥会导致客户端原来的 Key 不匹配,连接时报 Key mismatch

10.3 切换 DNS

确认 B 的端口已开放:

bash
nc -vz B_IP 21115
nc -vz B_IP 21116
nc -vz B_IP 21117

rustdesk.example.comA / AAAA 记录改到 B。

切换后检查解析:

bash
dig +short rustdesk.example.com @1.1.1.1
dig +short rustdesk.example.com @8.8.8.8

DNS 切换后停止 A,减少“部分客户端注册到 A、部分客户端注册到 B”的分裂状态:

bash
systemctl stop rustdesk-hbbs rustdesk-hbbr

停止 A 后,仍缓存旧 IP 的客户端会短暂离线,并在 DNS 更新后集中注册到 B。保留 A 继续运行便于回滚,代价是迁移窗口内容易出现客户端分散注册。

10.4 回滚

B 连接异常时:

  1. DNS 改回 A。
  2. 启动 A 的 rustdesk-hbbsrustdesk-hbbr
  3. 停止 B 的服务,避免继续分裂注册。

A 和 B 使用同一对服务端密钥,回滚时客户端无需修改 Key

11. 常见问题

Key mismatch

客户端里的 Key 和服务器当前使用的公钥不一致。

检查:

bash
cat /root/rustdesk/id_ed25519.pub

客户端 Key 必须使用该文件内容。迁移时同时确认 B 使用的是 A 的 id_ed25519 私钥,不能只复制 .pub 公钥。

Failed to connect to relay server

确认 hbbr 正在运行:

bash
systemctl status rustdesk-hbbr --no-pager
journalctl -u rustdesk-hbbr -n 100 --no-pager

确认 hbbs-r 指向正确的中继地址:

text
rustdesk.example.com:21117

hbbr 不在 hbbs 同机,或者不是默认 21117 时,必须在 hbbs -r 中显式声明。

域名解析正常但客户端离线

检查这些点:

  • DNS 是否同时存在旧 AAAA 记录。
  • 云厂商安全组是否放行了 21115-21117/tcp21116/udp
  • 本机 ufw 是否放行。
  • 客户端两端是否都配置了同一个 ID ServerKey

参考资料

基于 MIT 许可发布

加载中...