RustDesk 1.1.16 日常运维手册

RustDesk 1.1.16 服务端运维全流程实测手册:日常巡检清单与脚本、停机冷备与校验和一致性验证、恢复演练、探活告警设计、中继扩容缩容、1.1.16↔1.1.15 升降级与回滚、故障排查速查表。

RustDeskRustDesk远程控制自托管2026/10/25

RustDesk 1.1.16 日常运维手册

目标:给已按同专栏部署篇跑起 RustDesk 1.1.16 自建服务端(hbbs ID/Rendezvous 服务器 + hbbr Relay 中继服务器)的运维人员一份可照着执行的日常手册——巡检项与判读标准、停机冷备与一致性校验、恢复演练、探活与告警设计、中继扩容缩容、版本升级与回滚、故障排查速查表。本文全部命令与回显已在 Ubuntu 22.04 + RustDesk 服务端 1.1.16 环境实测通过(实测日期 2026-10-25),参数语义以官方仓库 docs/environment-variables.md 为准。

一、环境信息

  • 操作系统:Ubuntu 22.04.5 LTS(x86_64)
  • RustDesk 服务端版本:1.1.16(2026-07-20 发布,官方最新稳定版,发布信息查询日期 2026-10-25)
  • 部署形态:hbbs + hbbr 双服务分离,编排项目名 rustdesk-1.1.16-stack,部署目录 /opt/rustdesk/(部署过程见同专栏《RustDesk 1.1.16 服务端 Docker Compose 部署指南》)
  • 工作目录与落盘路径(运维重点):
    • hbbs 数据目录:/opt/rustdesk/data/hbbs/(挂载到服务工作目录,含密钥对与 SQLite 数据库)
    • hbbr 数据目录:/opt/rustdesk/data/hbbr/(含密钥文件,未配置 KEY 时为空目录)
  • 端口矩阵:21115/TCP(hbbs NAT 测试)、21116/TCP+UDP(hbbs 注册心跳打洞)、21117/TCP(hbbr 中继)、21118/TCP(hbbs WebSocket)、21119/TCP(hbbr WebSocket)
  • 当前服务端公钥(客户端接入用):tIOS6+HyV3YtZbGh57aTlN5cKrAF2Kg0w2gjWgm2dYY=
  • 参数语义与优先级规则见同专栏《RustDesk 1.1.16 配置参数详解》

二、日常巡检

巡检目标是回答四个问题:服务在不在、端口通不通、密钥还是不是原来那个、数据有没有在长。以下八项按建议执行顺序排列,全部为只读操作,不影响在线会话。

2.1 服务状态

cd /opt/rustdesk
docker compose ps --format 'table {{.Name}}\t{{.Status}}\t{{.Ports}}'

实测输出:

NAME                   STATUS          PORTS
rustdesk-1.1.16-hbbr   Up 18 minutes   0.0.0.0:21117->21117/tcp, [::]:21117->21117/tcp, 0.0.0.0:21119->21119/tcp, [::]:21119->21119/tcp
rustdesk-1.1.16-hbbs   Up 18 minutes   0.0.0.0:21115-21116->21115-21116/tcp, [::]:21115-21116->21115-21116/tcp, 0.0.0.0:21118->21118/tcp, [::]:21118->21118/tcp, 0.0.0.0:21116->21116/udp, [::]:21116->21116/udp

判读标准:

  • 两个服务都应为 Up;STATUS 出现 Restarting、或已重启次数不断增长,说明进程在崩溃重启循环,直接查 2.3 日志
  • PORTS 必须完整覆盖 21115–21119,且 21116 的 UDP 映射单独存在(21116->21116/udp)——缺 UDP 是客户端显示离线的头号原因
  • Up 时长短期骤降说明发生过重启,需对照 2.3 日志确认原因

2.2 端口矩阵

ss -ltn | grep -E '2111[5-9]'

实测输出(TCP):

LISTEN 0      4096         0.0.0.0:21115      0.0.0.0:*          
LISTEN 0      4096         0.0.0.0:21116      0.0.0.0:*          
LISTEN 0      4096         0.0.0.0:21117      0.0.0.0:*          
LISTEN 0      4096         0.0.0.0:21118      0.0.0.0:*          
LISTEN 0      4096         0.0.0.0:21119      0.0.0.0:*          
LISTEN 0      4096            [::]:21115         [::]:*          
LISTEN 0      4096            [::]:21116         [::]:*          
LISTEN 0      4096            [::]:21117         [::]:*          
LISTEN 0      4096            [::]:21118         [::]:*          
LISTEN 0      4096            [::]:21119         [::]:*          
ss -lun | grep 21116

实测输出(UDP):

UNCONN 0      0            0.0.0.0:21116      0.0.0.0:*          
UNCONN 0      0               [::]:21116         [::]:*          

判读标准:五个 TCP 端口必须全部 LISTEN;UDP 21116 必须 UNCONN 存在。少任何一个都定位到具体服务——缺 21115/21116/21118 是 hbbs 问题,缺 21117/21119 是 hbbr 问题。

2.3 启动日志关键行

hbbs 正常启动会打出一组固定关键行,逐条对应配置生效情况:

docker logs --tail 8 rustdesk-1.1.16-hbbs

实测输出:

[2026-10-25 04:34:43.255880 +00:00] INFO [src/rendezvous_server.rs:109] Listening on tcp/udp :21116
[2026-10-25 04:34:43.255882 +00:00] INFO [src/rendezvous_server.rs:110] Listening on tcp :21115, extra port for NAT test
[2026-10-25 04:34:43.255883 +00:00] INFO [src/rendezvous_server.rs:111] Listening on websocket :21118
[2026-10-25 04:34:43.256076 +00:00] INFO [src/rendezvous_server.rs:146] mask: None
[2026-10-25 04:34:43.256092 +00:00] INFO [src/rendezvous_server.rs:147] local-ip: ""
[2026-10-25 04:34:43.256099 +00:00] INFO [src/common.rs:45] relay-servers=[]
[2026-10-25 04:34:43.256177 +00:00] INFO [src/rendezvous_server.rs:161] ALWAYS_USE_RELAY=N
[2026-10-25 04:34:43.256190 +00:00] INFO [src/rendezvous_server.rs:193] Start
关键行正常值异常含义
Listening on tcp/udp :21116端口与规划一致端口被改写/被占用,客户端将连不上
Listening on tcp :21115, extra port for NAT test存在缺此行说明派生端口未绑定
Listening on websocket :21118存在(除非裁掉 Web 客户端)浏览器端无法接入
relay-servers=[]空(同机标准端口)、或期望的地址列表列表非预期说明被 -r/RELAY-SERVERS 覆盖
ALWAYS_USE_RELAY=NN为 Y 表示强制全走中继(带宽成本飙升)
Start末行出现未出现说明启动未完成

hbbr 侧对照启动行(默认 QoS 五项在启动时即打印,可用来核对是否被环境变量改过):

[2026-10-25 03:55:24.692107 +00:00] INFO [src/relay_server.rs:82] Listening on tcp :21117
[2026-10-25 03:55:24.692109 +00:00] INFO [src/relay_server.rs:84] Listening on websocket :21119
[2026-10-25 03:55:24.692114 +00:00] INFO [src/relay_server.rs:87] Start
[2026-10-25 03:55:24.692185 +00:00] INFO [src/relay_server.rs:105] DOWNGRADE_THRESHOLD: 0.66
[2026-10-25 03:55:24.692192 +00:00] INFO [src/relay_server.rs:115] DOWNGRADE_START_CHECK: 1800s
[2026-10-25 03:55:24.692196 +00:00] INFO [src/relay_server.rs:125] LIMIT_SPEED: 32Mb/s
[2026-10-25 03:55:24.692200 +00:00] INFO [src/relay_server.rs:136] TOTAL_BANDWIDTH: 1024Mb/s
[2026-10-25 03:55:24.692201 +00:00] INFO [src/relay_server.rs:146] SINGLE_BANDWIDTH: 128Mb/s

排障可临时提高日志级别(RUST_LOG=debug 必须放在进程环境,写 .env 无效):

cd /opt/rustdesk
RUST_LOG=debug docker compose up -d --force-recreate hbbs

2.4 密钥一致性(最容易踩的巡检项)

密钥对就是这套服务端的身份。巡检两件事:文件内容没变、进程实际加载的是它。

cat /opt/rustdesk/data/hbbs/id_ed25519.pub

实测输出:

tIOS6+HyV3YtZbGh57aTlN5cKrAF2Kg0w2gjWgm2dYY=
docker logs rustdesk-1.1.16-hbbs 2>&1 | grep -m1 'Key:'

实测输出:

[2026-10-25 04:34:43.252673 +00:00] INFO [src/rendezvous_server.rs:1243] Key: tIOS6+HyV3YtZbGh57aTlN5cKrAF2Kg0w2gjWgm2dYY=

判读标准:文件末行(公钥)与日志 Key: 后字符串逐字符一致(含尾部 =)。不一致说明进程用的是另一份密钥(工作目录被换、或数据目录被删后重新生成),此时所有客户端都会连不上。

2.5 数据目录

du -sh /opt/rustdesk/data/hbbs /opt/rustdesk/data/hbbr

实测输出:

88K	/opt/rustdesk/data/hbbs
4.0K	/opt/rustdesk/data/hbbr
ls -l /opt/rustdesk/data/hbbs

实测输出:

total 72
-rw-r--r-- 1 root root 24576 Oct 25 11:54 db_v2.sqlite3
-rw-r--r-- 1 root root 32768 Oct 25 12:34 db_v2.sqlite3-shm
-rw-r--r-- 1 root root     0 Oct 25 12:34 db_v2.sqlite3-wal
-rw-r--r-- 1 root root    88 Oct 25 11:54 id_ed25519
-rw-r--r-- 1 root root    88 Oct 25 11:53 id_ed25519.bak
-rw-r--r-- 1 root root    44 Oct 25 11:54 id_ed25519.pub
-rw-r--r-- 1 root root    44 Oct 25 11:53 id_ed25519.pub.bak

判读标准:

  • id_ed25519(88 字节)、id_ed25519.pub(44 字节)必须存在且大小稳定;.bak 是历史留存副本,保留无妨
  • db_v2.sqlite3 随客户端注册数增长;-wal、-shm 是 SQLite 的 WAL 附属文件,必须与主库一起备份(见第三章)
  • 目录突然变小(特别是 id_ed25519 消失、只剩新生成的)说明数据目录被重建,客户端 Key 全部失效

2.6 数据库健康

数据库为单文件 SQLite(DB_URL 默认 ./db_v2.sqlite3),表结构只有一张 peer 表:

sqlite3 /opt/rustdesk/data/hbbs/db_v2.sqlite3 '.tables'

实测输出:

peer
sqlite3 /opt/rustdesk/data/hbbs/db_v2.sqlite3 'pragma journal_mode;'

实测输出:

wal
sqlite3 /opt/rustdesk/data/hbbs/db_v2.sqlite3 'select count(*) from peer;'

实测输出(新装未接入客户端时):

0

peer 表结构(实测 .schema 输出):

CREATE TABLE peer (
                guid blob primary key not null,
                id varchar(100) not null,
                uuid blob not null,
                pk blob not null,
                created_at datetime not null default(current_timestamp),
                user blob,
                status tinyint,
                note varchar(300),
                info text not null
            ) without rowid;
CREATE UNIQUE INDEX index_peer_id on peer (id);
CREATE INDEX index_peer_user on peer (user);
CREATE INDEX index_peer_created_at on peer (created_at);
CREATE INDEX index_peer_status on peer (status);

⚠️ 注意:巡检只做只读查询。不要在服务运行时用外部 sqlite3 执行 VACUUM、ALTER、DELETE 等写操作,会与进程的连接池(MAX_DATABASE_CONNECTIONS 默认 1)争用并可能触发锁等待。

2.7 运行时控制台状态查询

hbbs / hbbr 内置 loopback 控制台:来自 127.0.0.1 的 TCP 连接被当作一条命令执行。服务运行在独立网络命名空间里,宿主机直接 nc 127.0.0.1 打不到,需要加入该服务的网络命名空间再发命令:

docker run --rm --network container:rustdesk-1.1.16-hbbr alpine:3 sh -c "printf 'tb' | nc 127.0.0.1 21117"

实测输出:

1024Mb/s

hbbs 控制台在 PORT-1(默认 21115):

docker run --rm --network container:rustdesk-1.1.16-hbbs alpine:3 sh -c "printf 'aur' | nc 127.0.0.1 21115"

实测输出:

ALWAYS_USE_RELAY: false
docker run --rm --network container:rustdesk-1.1.16-hbbs alpine:3 sh -c "printf 'rs' | nc 127.0.0.1 21115"

实测输出(未配置 -r、中继与 ID 服务器同机同标准端口时为空,属于正常):

2.8 每日巡检清单与脚本

#巡检项命令/位置正常判据频率
1服务状态docker compose ps双服务 Up,PORTS 含 UDP 21116每日
2TCP 端口ss -ltn | grep -E '2111[5-9]'5 个端口全 LISTEN每日
3UDP 端口ss -lun | grep 21116存在 UNCONN每日
4启动关键行docker logs --tail 8 rustdesk-1.1.16-hbbs见 2.3 表每日
5密钥一致cat id_ed25519.pub + 日志 Key:逐字符一致每日(变更后立即)
6数据目录du -sh、ls -l主库在增长、密钥文件大小稳定每周
7数据库count(*) from peer与客户端实际接入量趋势一致每周
8控制台态tb/aur/rs与配置期望一致每周
9磁盘水位df -h /opt/rustdesk剩余 > 20%每周
10备份产物备份目录 ls -lh当日备份存在且大小合理每日(看备份任务结果)

可直接落成脚本(只读、不改任何状态):

#!/usr/bin/env bash
# /opt/rustdesk/bin/check.sh —— RustDesk 服务端每日巡检
set -uo pipefail
cd /opt/rustdesk || exit 1
fail=0

echo "== 1. 服务状态 =="
docker compose ps --format 'table {{.Name}}\t{{.Status}}' | grep -q 'Up' || { echo "FAIL: 服务未运行"; fail=1; }

echo "== 2/3. 端口 =="
for p in 21115 21116 21117 21118 21119; do
  ss -ltn | grep -q ":$p " || { echo "FAIL: TCP $p 未监听"; fail=1; }
done
ss -lun | grep -q ':21116 ' || { echo "FAIL: UDP 21116 未监听"; fail=1; }

echo "== 5. 密钥一致 =="
pub=$(tail -n1 /opt/rustdesk/data/hbbs/id_ed25519.pub)
log=$(docker logs rustdesk-1.1.16-hbbs 2>&1 | grep -m1 'Key:' | awk '{print $NF}')
[ "$pub" = "$log" ] || { echo "FAIL: 公钥与进程加载密钥不一致 pub=$pub log=$log"; fail=1; }

echo "== 9. 磁盘 =="
df -h /opt/rustdesk | awk 'NR==2 {print "used="$5" avail="$4}'

[ $fail -eq 0 ] && echo "RESULT: OK" || echo "RESULT: FAIL"
exit $fail

三、备份

3.1 备份对象

hbbs 数据目录是全部有状态内容,hbbr 数据目录在未配置 KEY 时几乎为空:

文件作用丢失后果
id_ed25519私钥,用于签名无法恢复服务端身份
id_ed25519.pub公钥,客户端接入要填的 Key同上
db_v2.sqlite3peer 表主库(客户端 ID 注册记录)已注册客户端需重新注册
db_v2.sqlite3-wal / -shmWAL 附属文件单备份主库可能丢失最新写入
.config/rustdesk/RustDesk.toml运行期配置残留一般无影响,一并备份最稳

⚠️ 结论:密钥对是第一优先级,数据库是第二优先级。密钥丢失等于整套服务端身份丢失,所有客户端必须改 Key。

3.2 停机冷备流程(实测)

WAL 模式数据库在服务运行时直接 tar 有拿到半写状态的风险,最稳的是短暂停服后整体打包。停机窗口通常 1 秒内完成,对在线会话影响极小(已建立的会话在恢复后需重连)。

cd /opt/rustdesk
docker compose stop hbbs
mkdir -p /opt/rustdesk-backup
tar -czf /opt/rustdesk-backup/rustdesk-hbbs-$(date +%Y%m%d).tgz -C data/hbbs .
docker compose start hbbs

实测输出(tar 静默成功无输出,仅停/启有回显):

 Container rustdesk-1.1.16-hbbs Stopping 
 Container rustdesk-1.1.16-hbbs Stopped 
 Container rustdesk-1.1.16-hbbs Starting 
 Container rustdesk-1.1.16-hbbs Started 

备份产物(实测):

ls -lh /opt/rustdesk-backup/
total 4.0K
-rw-r--r-- 1 root root 1.5K Oct 25 12:53 rustdesk-hbbs-20261025.tgz

归档内容(实测 tar -tzf):

./
./id_ed25519.bak
./id_ed25519.pub
./db_v2.sqlite3-shm
./db_v2.sqlite3
./id_ed25519
./id_ed25519.pub.bak
./.config/
./.config/rustdesk/
./.config/rustdesk/RustDesk.toml
./db_v2.sqlite3-wal

确认打包后服务已恢复监听:

docker logs --tail 3 rustdesk-1.1.16-hbbs

3.3 备份一致性校验

每个备份生成后立刻比对校验和,确认归档与现网数据同源:

sha256sum /opt/rustdesk-backup/rustdesk-hbbs-20261025.tgz

实测输出:

27d52d061dbbb3ba4bf4302d3aa8f45f978d4bb35aba2dab653bdb3c5448e33a  /opt/rustdesk-backup/rustdesk-hbbs-20261025.tgz

解包后与现网主库比对:

mkdir -p /tmp/verify && tar -xzf /opt/rustdesk-backup/rustdesk-hbbs-20261025.tgz -C /tmp/verify
sha256sum /tmp/verify/db_v2.sqlite3 /opt/rustdesk/data/hbbs/db_v2.sqlite3

实测输出(两者一致,说明备份取的是干净快照):

7b8fd91b4b21e380687d60c2905258f47086d85e1e45889c7e8757ab22ef901e  /tmp/verify/db_v2.sqlite3
7b8fd91b4b21e380687d60c2905258f47086d85e1e45889c7e8757ab22ef901e  /opt/rustdesk/data/hbbs/db_v2.sqlite3

💡 说明:hBbs 启动后 db_v2.sqlite3-wal 会被重新创建(实测复启后 -wal 变为 0 字节),比对主库哈希即可;确认键值以 主库哈希一致 + 密钥文件哈希一致 为准。

3.4 备份策略建议

项建议理由
频率每日一次 + 变更前必做(升级、改端口、换密钥、迁机)数据库增量小(本例 24 KB),成本可忽略;变更前备份是回滚底线
保留本地 7 份 + 异地/对象存储 30 份覆盖误删与宿主机故障两种场景
异地推送到另一台机器或对象存储密钥与数据库必须能脱离宿主恢复
校验每次生成后记录 sha256;每月抽一份做恢复演练无演练的备份不可信
权限chmod 600 备份产物(含私钥)私钥泄露等于服务端身份泄露
chmod 600 /opt/rustdesk-backup/*.tgz

3.5 不停机备份(无停机窗口时)

单靠 cp 主库仍可能拿到不一致快照;SQLite 官方推荐的在线备份方式是在同目录执行 .backup(或 VACUUM INTO),由 SQLite 自身保证一致性:

sqlite3 /opt/rustdesk/data/hbbs/db_v2.sqlite3 ".backup '/opt/rustdesk-backup/db_v2-$(date +%Y%m%d).sqlite3'"
tar -czf /opt/rustdesk-backup/rustdesk-keys-$(date +%Y%m%d).tgz -C /opt/rustdesk/data/hbbs id_ed25519 id_ed25519.pub

备份产物分成「库」与「密钥」两个文件,恢复时分别放回数据目录即可。

四、恢复

4.1 恢复场景

场景恢复目标需要的备份
误删数据目录 / 换盘原位恢复密钥对 + 数据库
宿主机宕机重建换机恢复密钥对 + 数据库
升级/改配置后出错回滚到变更前状态变更前全量备份
定期演练验证备份可用任意最近一份

4.2 恢复演练(实测,不影响现网)

演练原则:先在与现网隔离的非标准端口上验证,再动现网。以下用 22116 作为演练端口(现网 hbbs 占用 21116)。

第一步,解包到独立目录:

mkdir -p /opt/rustdesk-restore-test
tar -xzf /opt/rustdesk-backup/rustdesk-hbbs-20261025.tgz -C /opt/rustdesk-restore-test
ls -l /opt/rustdesk-restore-test

实测输出:

total 72
-rw-r--r-- 1 root root 24576 Oct 25 11:54 db_v2.sqlite3
-rw-r--r-- 1 root root 32768 Oct 25 12:53 db_v2.sqlite3-shm
-rw-r--r-- 1 root root     0 Oct 25 12:53 db_v2.sqlite3-wal
-rw-r--r-- 1 root root    88 Oct 25 11:54 id_ed25519
-rw-r--r-- 1 root root    88 Oct 25 11:53 id_ed25519.bak
-rw-r--r-- 1 root root    44 Oct 25 11:54 id_ed25519.pub
-rw-r--r-- 1 root root    44 Oct 25 11:53 id_ed25519.pub.bak

第二步,用恢复数据在 22116 起一个临时实例验证:

docker run -d --name rustdesk-restore-test \
  -p 22116:22116 -p 22116:22116/udp -p 22118:22118 \
  -v /opt/rustdesk-restore-test:/root \
  rustdesk/rustdesk-server:1.1.16 hbbs -p 22116

实测输出:

542b14954739b31396fe77017653208b0bae03a08a2abe7caf56f8f444008b86

第三步,校验日志(关键看 Private key comes from id_ed25519、Key: 与监听端口):

docker logs rustdesk-restore-test

实测输出:

[2026-10-25 04:54:11.767023 +00:00] INFO [src/common.rs:121] Private key comes from id_ed25519
[2026-10-25 04:54:11.767044 +00:00] INFO [src/rendezvous_server.rs:1243] Key: tIOS6+HyV3YtZbGh57aTlN5cKrAF2Kg0w2gjWgm2dYY=
[2026-10-25 04:54:11.767048 +00:00] INFO [src/peer.rs:84] DB_URL=./db_v2.sqlite3
[2026-10-25 04:54:11.769031 +00:00] INFO [src/rendezvous_server.rs:107] serial=0
[2026-10-25 04:54:11.769050 +00:00] INFO [src/common.rs:45] rendezvous-servers=[]
[2026-10-25 04:54:11.769052 +00:00] INFO [src/rendezvous_server.rs:109] Listening on tcp/udp :22116
[2026-10-25 04:54:11.769053 +00:00] INFO [src/rendezvous_server.rs:110] Listening on tcp :22115, extra port for NAT test
[2026-10-25 04:54:11.769054 +00:00] INFO [src/rendezvous_server.rs:111] Listening on websocket :22118
[2026-10-25 04:54:11.769093 +00:00] INFO [src/rendezvous_server.rs:146] mask: None
[2026-10-25 04:54:11.769094 +00:00] INFO [src/rendezvous_server.rs:147] local-ip: ""
[2026-10-25 04:54:11.769097 +00:00] INFO [src/common.rs:45] relay-servers=[]
[2026-10-25 04:54:11.769126 +00:00] INFO [src/rendezvous_server.rs:161] ALWAYS_USE_RELAY=N
[2026-10-25 04:54:11.769133 +00:00] INFO [src/rendezvous_server.rs:193] Start

关键判读:

  • Private key comes from id_ed25519:用的是备份里的私钥文件,不是新生成的
  • Key: tIOS6+HyV3YtZbGh57aTlN5cKrAF2Kg0w2gjWgm2dYY=:与现网公钥一致 → 客户端无需改任何配置
  • DB_URL=./db_v2.sqlite3 后无建库报错:数据库可被正常打开

第四步,恢复数据库完整性校验:

sqlite3 /opt/rustdesk-restore-test/db_v2.sqlite3 '.tables'
sqlite3 /opt/rustdesk-restore-test/db_v2.sqlite3 'select count(*) from peer;'
sqlite3 /opt/rustdesk-restore-test/db_v2.sqlite3 'pragma journal_mode;'

实测输出:

peer
0
wal

第五步,控制台连通性验证(临时实例的 hbbs 控制台在 PORT-1 = 22115):

docker run --rm --network container:rustdesk-restore-test alpine:3 sh -c "printf 'aur' | nc 127.0.0.1 22115"

实测输出:

ALWAYS_USE_RELAY: false

第六步,清理演练实例:

docker rm -f rustdesk-restore-test
rm -rf /opt/rustdesk-restore-test

4.3 恢复检查清单

#检查项通过标准
1私钥来源日志出现 Private key comes from id_ed25519
2公钥一致日志 Key: 与变更前公钥逐字符一致
3数据库可读.tables 输出 peer,count(*) 与预期量级一致(行为 0 也属正常,表示尚未有客户端注册)
4端口监听Listening on tcp/udp :<端口> 与规划一致
5控制台可用aur 返回 ALWAYS_USE_RELAY: false(或配置值)
6客户端实测用一台客户端填「ID 服务器 + 公钥」接入,ID 能获取、能发起会话

4.4 正式恢复步骤(原位 / 换机)

原位恢复(数据目录被误删、宿主机仍在):

cd /opt/rustdesk
docker compose stop hbbs
rm -rf data/hbbs
mkdir -p data/hbbs
tar -xzf /opt/rustdesk-backup/rustdesk-hbbs-20261025.tgz -C data/hbbs
docker compose start hbbs
docker logs --tail 5 rustdesk-1.1.16-hbbs

换机恢复(新宿主机重建):

  1. 新机按部署篇装好运行环境与编排文件,创建同一网络与端口映射
  2. 把最新的 *.tgz 拷到新机,解包进 data/hbbs
  3. 起服务后按 4.3 清单逐项核验
  4. 若服务端地址变化,客户端「ID 服务器」需改成新地址;Key 不用改(密钥对来自备份)

⚠️ 注意:恢复时切勿"先起服务再放数据"。hbbs 首次启动若发现工作目录没有密钥对会立即生成新的(日志 Private/public key written to id_ed25519/id_ed25519.pub),此时再拷入旧密钥可能导致进程已按新密钥对外服务,客户端批量失联。正确顺序永远是先放数据、后起服务。

五、监控与告警

5.1 没有内置指标端点

实测 1.1.16 两个进程只监听 21115–21119 这五个业务端口(见 2.2),没有 Prometheus /metrics 之类的指标接口:开源版服务端不提供结构化监控端点(PORT_FOR_API / KEY_FOR_API 只属于商业版 Pro)。因此监控体系由三块拼成:

  1. 端口探活(外部主动探测,判断进程是否在)
  2. 日志关键字(判断启动是否正常、有无异常)
  3. 控制台查询(判断运行期业务状态:带宽、中继列表、强制中继开关)

5.2 端口探活

for port in 21115 21116 21117 21118; do
  nc -z -w 2 127.0.0.1 $port && echo "OK   $port/tcp" || echo "FAIL $port/tcp"
done

💡 说明:UDP 端口无法用 TCP 探活判断。UDP 21116 的可用性只能通过「服务端 ss -lun 有监听 + 客户端实际能注册」两段验证;外部监控不要对 UDP 21116 做盲目探活,否则容易误报。

告警建议:

探测项阈值级别
TCP 21115 / 21116 / 21117 / 21118连续 2 次失败P1(服务不可用)
TCP 21119(若启用 Web 客户端)连续 3 次失败P2
宿主机磁盘剩余< 20%P2
服务重启次数增长1 小时内 ≥ 2 次P1(崩溃循环)

5.3 日志关键字告警

采集服务日志并按关键字告警,可覆盖「端口通但服务异常」这类探活发现不了的情况:

docker logs --since 10m rustdesk-1.1.16-hbbs 2>&1 | grep -cE 'Listening on tcp/udp'
docker logs --since 10m rustdesk-1.1.16-hbbr 2>&1 | grep -cE 'Start'
关键字含义处置
Private/public key written to id_ed25519/id_ed25519.pub密钥被重新生成(数据目录丢过)立即 P1 告警 + 按 4.4 恢复备份
signal terminate进程收到终止信号属正常停机;非计划内的出现需查上游
Address already in use 之类绑定失败端口冲突查 ss -ltn 占用方
ERROR任何 ERROR 行逐条排查,配合 RUST_LOG=debug 复现

5.4 控制台业务指标

控制台能查到的运行期状态(hbbr 在 21117,hbbs 在 21115):

命令端口返回值含义采集建议
tb21117当前总带宽上限5 分钟一次,与配置期望值比对(可发现配置漂移)
sb21117单连接带宽上限同上
ls21117降级限速值同上
dt / t21117降级阈值 / 起始检查秒数同上
u21117中继用量(无流量时空)观察趋势
rs21115当前下发的中继列表与期望列表比对(可发现中继漏配)
aur21115强制中继开关期望 false,变 true 需告警

采集示例(写入时序库或落盘留痕):

docker run --rm --network container:rustdesk-1.1.16-hbbr alpine:3 sh -c "
printf 'tb' | nc 127.0.0.1 21117; echo
printf 'sb' | nc 127.0.0.1 21117; echo
printf 'ls' | nc 127.0.0.1 21117; echo
"

实测输出:

1024Mb/s
128Mb/s
32Mb/s

六、扩容与缩容

6.1 垂直扩容:调中继带宽(优先做)

中继带宽不够时,先调 hbbr 的 QoS 上限,不必加机器。两项可调:

# docker-compose.yml 的 hbbr 服务 environment 段
    environment:
      - SINGLE_BANDWIDTH=256
      - TOTAL_BANDWIDTH=2048

改完重建生效:

cd /opt/rustdesk
docker compose up -d hbbr
docker logs --tail 6 rustdesk-1.1.16-hbbr

生效判据:启动日志的 SINGLE_BANDWIDTH / TOTAL_BANDWIDTH 变为新值(默认值见 2.3)。

临时调整(不停服) 用控制台热改,实测:

docker run --rm --network container:rustdesk-1.1.16-hbbr alpine:3 sh -c "
echo -n 'before: '; printf 'sb' | nc 127.0.0.1 21117; echo
printf 'sb 256' | nc 127.0.0.1 21117
echo -n 'after : '; printf 'sb' | nc 127.0.0.1 21117; echo
printf 'sb 128' | nc 127.0.0.1 21117
"

实测输出:

before: 128Mb/s
after : 256Mb/s

⚠️ 注意:控制台改动只存在于当前进程内存,重启即回到编排/环境变量的值。要固化必须改配置,控制台只用于临时救急。改写命令本身无回显,需再查一次确认。

6.2 水平扩容:增加中继实例

单个 hbbr 的总带宽受 TOTAL_BANDWIDTH 与出口带宽限制时,加第二个中继实例分摊。这里最容易踩的坑是端口与下发列表——新实例必须用不同宿主端口,并显式加入 hbbs 的 relay-servers,否则客户端永远推不到它。

实测:在原栈之外再起一个中继实例,宿主 21217(对应服务内 21117):

docker run -d --name rustdesk-1.1.16-hbbr2 \
  -p 21217:21117 -p 21219:21119 \
  -v /opt/rustdesk/data/hbbr2:/root \
  rustdesk/rustdesk-server:1.1.16 hbbr

实测启动日志(新实例默认 QoS 与主实例一致):

[2026-10-25 04:54:37.780176 +00:00] INFO [src/relay_server.rs:61] #blacklist(blacklist.txt): 0
[2026-10-25 04:54:37.780186 +00:00] INFO [src/relay_server.rs:76] #blocklist(blocklist.txt): 0
[2026-10-25 04:54:37.780188 +00:00] INFO [src/relay_server.rs:82] Listening on tcp :21117
[2026-10-25 04:54:37.780190 +00:00] INFO [src/relay_server.rs:84] Listening on websocket :21119

把两个中继写进 hbbs 的下发列表——运行期可先用控制台 rs 热验证(实测):

docker run --rm --network container:rustdesk-1.1.16-hbbs alpine:3 sh -c "
printf 'rs 192.168.146.128:21117,192.168.146.128:21217' | nc 127.0.0.1 21115
printf 'rs' | nc 127.0.0.1 21115
"

实测输出(下发列表已生效为两条):

192.168.146.128:21117
192.168.146.128:21217

两个中继端口连通性实测:

relay1 21117 reachable
relay2 21217 reachable

固化写法(hbbs 启动参数):

# docker-compose.yml 的 hbbs 服务
    command: hbbs -r 192.168.146.128:21117,192.168.146.128:21217

要点:

  • 列表元素支持 host 或 host:port;非标准端口必须带端口
  • 中继在不同主机时填各自的公网地址
  • 加完中继后务必复核:hbbs 日志的 relay-servers= 行内容与客户端实际可用中继一致
  • 新中继的 21117/21119 同样要放通防火墙与安全组

6.3 多 ID 服务器(rendezvous 互联)

hbbs 支持用 -R, --rendezvous-servers 指定多个 rendezvous 服务器做互联(单机部署留空,日志显示 rendezvous-servers=[])。注意 peer 数据库是各 hbbs 本地 SQLite,多 hbbs 不做共享存储,规划多 ID 服务器前要先确定客户端 ID 归属策略。

6.4 缩容步骤

缩容顺序与扩容相反——先摘下发列表,再停实例,否则客户端会拿到已下线的中继地址反复重试:

  1. 从 hbbs 的 relay-servers 中移除待下线地址(控制台 rs 热改验证 → 固化到 command: hbbs -r <保留的中继地址>)
  2. 观察一个会话周期(建议 ≥ 30 分钟),确认无客户端仍在用该中继
  3. 停并移除被下线的中继实例及其端口映射
  4. 收尾清理:宿主端口从防火墙/安全组撤掉,数据目录保留一份备查

七、升级与回滚

7.1 升级前检查

  1. 备份现网数据(第三章,必做)
  2. 记录当前公钥:cat /opt/rustdesk/data/hbbs/id_ed25519.pub
  3. 确认新版本已发布并读取发布说明:官方 Releases 页 https://github.com/rustdesk/rustdesk-server/releases
  4. 确认可回滚:本地保留旧版本编排文件与旧版本运行包

7.2 升级流程(实测)

编排中只改 image 标签(示例由 1.1.15 升到 1.1.16),然后重建:

cd /opt/rustdesk
docker compose up -d

实测输出:

 Container rustdesk-1.1.16-hbbr Recreate 
 Container rustdesk-1.1.16-hbbs Recreate 
 Container rustdesk-1.1.16-hbbr Recreated 
 Container rustdesk-1.1.16-hbbs Recreated 
 Container rustdesk-1.1.16-hbbs Starting 
 Container rustdesk-1.1.16-hbbr Starting 
 Container rustdesk-1.1.16-hbbs Started 
 Container rustdesk-1.1.16-hbbr Started 

升级后核验(版本 + 公钥 + 端口):

docker compose ps --format 'table {{.Name}}\t{{.Image}}\t{{.Status}}'

实测输出:

NAME                   IMAGE                             STATUS
rustdesk-1.1.16-hbbr   rustdesk/rustdesk-server:1.1.16   Up Less than a second
rustdesk-1.1.16-hbbs   rustdesk/rustdesk-server:1.1.16   Up Less than a second
docker logs rustdesk-1.1.16-hbbs 2>&1 | grep -m1 'Key:'

实测输出:

[2026-10-25 04:34:43.252673 +00:00] INFO [src/rendezvous_server.rs:1243] Key: tIOS6+HyV3YtZbGh57aTlN5cKrAF2Kg0w2gjWgm2dYY=

7.3 回滚流程(实测)

把 image 标签改回旧版本,同样 docker compose up -d 重建。实测由 1.1.16 回滚到 1.1.15:

docker compose ps --format 'table {{.Name}}\t{{.Image}}\t{{.Status}}'

实测输出:

NAME                   IMAGE                             STATUS
rustdesk-1.1.16-hbbr   rustdesk/rustdesk-server:1.1.15   Up Less than a second
rustdesk-1.1.16-hbbs   rustdesk/rustdesk-server:1.1.15   Up Less than a second

回滚后公钥一致(注意日志中的源码行号从 1.1.16 的 rendezvous_server.rs:1243 变为 1.1.15 的 1251,这本身就是版本已切换的旁证):

[2026-10-25 04:34:32.803690 +00:00] INFO [src/rendezvous_server.rs:1251] Key: tIOS6+HyV3YtZbGh57aTlN5cKrAF2Kg0w2gjWgm2dYY=

hbbr 回滚后启动即打印 QoS 默认值,可用于确认配置未被版本变更带走:

[2026-10-25 04:34:33.000984 +00:00] INFO [src/relay_server.rs:87] Start
[2026-10-25 04:34:33.001078 +00:00] INFO [src/relay_server.rs:105] DOWNGRADE_THRESHOLD: 0.66
[2026-10-25 04:34:33.001081 +00:00] INFO [src/relay_server.rs:115] DOWNGRADE_START_CHECK: 1800s
[2026-10-25 04:34:33.001082 +00:00] INFO [src/relay_server.rs:125] LIMIT_SPEED: 32Mb/s
[2026-10-25 04:34:33.001084 +00:00] INFO [src/relay_server.rs:136] TOTAL_BANDWIDTH: 1024Mb/s
[2026-10-25 04:34:33.001086 +00:00] INFO [src/relay_server.rs:146] SINGLE_BANDWIDTH: 128Mb/s

7.4 版本兼容性结论(实测)

  • 密钥不变:1.1.16 → 1.1.15 → 1.1.16 双向切换后,Key: 全程为同一值,客户端无需改 Key
  • 数据库可双向读写:同一份 db_v2.sqlite3 在 1.1.15 与 1.1.16 间切换启动均无建库报错、peer 表可正常查询
  • 配置语义未变:hbbr 的 QoS 五项与 hbbs 的派生端口规则在 1.1.15/1.1.16 一致
  • 回滚边界:本结论仅覆盖 1.1.15 ↔ 1.1.16;跨大版本或跨大跨度回滚(尤其涉及数据库结构变更的版本)必须先在小环境做恢复演练,不要直接对生产回滚

7.5 升级最佳实践

  1. 挑窗口期:升级会重建服务,在线会话会中断
  2. 先升 hbbr(中继),验证无异常再升 hbbs(ID 服务器)——这样 ID 注册面始终有一个健康实例
  3. 每次只升一个版本台阶,不跨多版本跳跃
  4. 升级后按 4.3 清单核验,重点看公钥是否不变(若变了,说明数据目录出了问题,应立即回滚并恢复备份)

八、故障排查速查表

现象首要排查定位命令常见处置
客户端显示离线 / 未就绪UDP 21116 未通ss -lun | grep 21116;安全组/防火墙规则放通 UDP 21116(TCP 放通但漏 UDP 是最常见根因)
客户端提示 Key 错误客户端 Key 与服务端公钥不一致cat data/hbbs/id_ed25519.pub 与 2.4 的日志比对逐字符改为一致(含尾部 =)
全部客户端突然连不上、Key 全错数据目录被重建,密钥被重新生成日志搜 Private/public key written to立即按 4.4 恢复备份,先放数据后起服务
所有会话都走中继、打洞失败强制中继被打开 / 对称 NATprintf 'aur' | nc 127.0.0.1 21115always-use-relay N 恢复直连;对称 NAT 属正常兜底
中继带宽打满、画面卡顿单连接被降级 / 总带宽上限tb、sb、ls、dt 控制台查询调 SINGLE_BANDWIDTH/TOTAL_BANDWIDTH;确认不是 ALWAYS_USE_RELAY=Y 把流量全压到中继
单条大流量长连接被限速(中继其它空闲)降级机制按连接独立判定dt=0.66、t=1800s、ls=32Mb/s属设计行为;需要时调高 SINGLE_BANDWIDTH 或 LIMIT_SPEED
某 IP 疯狂重连/恶意中继黑/白名单printf 'B' | nc 127.0.0.1 21117blocklist-add <ip> 在线封禁;固化写 blocklist.txt
服务反复重启端口冲突 / 数据目录权限docker compose ps、docker logs --tail 50释放占用端口;修正目录属主权限
进不去服务内部调试极简运行包无 shell—属正常形态;治理走日志 + loopback 控制台
磁盘持续增长数据库/日志增长du -sh data/hbbs、count(*) from peer数据库增长属正常(每客户端一条记录);日志按采集侧策略轮转
Web 客户端连不上21118/21119 未放通ss -ltn | grep -E '2111[89]'放通两个 WebSocket 端口;确认客户端填了 ID 服务器 + Key

排障通用姿势:先用 RUST_LOG=debug 重建服务抓一次全量日志(命令见 2.3),对照 2.3 的关键行表逐项排除;参数语义不清时回查同专栏《RustDesk 1.1.16 配置参数详解》。

九、常见问题

Q1:日常运维需要停服吗? A:巡检、控制台查询、日志查看全部只读,不停服;只有冷备打包和升级回滚需要短暂停服(实测停/启各在秒级)。不停机的备份方式见 3.5。

Q2:备份只备数据库行不行? A:不行。密钥对(id_ed25519 + id_ed25519.pub)才是服务端身份,丢了等于整套服务重建、所有客户端改 Key;数据库丢了只是客户端需重新注册。至少两者都要备。

Q3:可以直接 cp db_v2.sqlite3 当备份吗? A:不建议。数据库处于 WAL 模式,运行中单拷主库可能缺失最新写入。要么停服后整目录打包(3.2),要么用 sqlite3 .backup(3.5)。

Q4:恢复后客户端要不要重新配置? A:密钥对没变(备份就是原密钥),客户端无需改任何配置;只有服务端 IP/域名变了才需要客户端改「ID 服务器」地址。

Q5:docker logs 打不到控制台命令怎么办? A:控制台只接受来自 127.0.0.1 的连接,且服务在独立网络命名空间里。用 --network container:<服务名> 加入其命名空间后再 nc 127.0.0.1 <控制台端口>,见 2.7。

Q6:控制台改的带宽值重启后为什么又回去了? A:控制台改动只在进程内存,重启即恢复编排/环境变量的值。临时救急用控制台,固化必须改配置,见 6.1。

Q7:监控能接 Prometheus 吗? A:开源版 1.1.16 没有指标端点(实测仅监听 21115–21119 业务端口)。可自建探活 + 日志告警 + 控制台拉取三件套(第五章),或用外部脚本把控制台查询结果转成时序数据。

Q8:升级把公钥弄变了怎么办? A:说明数据目录在升级中被替换/重建。立即回滚到旧版本并先恢复备份数据再起服务(顺序见 4.4 注意事项),核验 Key: 与升级前一致后再对外。

十、参考链接