RustDesk 私有化高可用部署:双信令节点加四层负载均衡落地
【免费下载链接】rustdeskAn open-source remote desktop application designed for self-hosting, as an alternative to TeamViewer.项目地址: https://gitcode.com/GitHub_Trending/ru/rustdesk
凌晨一点,告警群弹出"信令服务器无响应",客户端开始成批报"连接服务器失败"——单台自建 RustDesk 信令/中继服务器宕机,所有远程会话同时断开。本文给出可落地的方案:2 台无状态 RustDesk 信令/中继服务器 + 1 台四层负载均衡,客户端填双 IP 自动切换,从克隆仓库到验证会话约 20 分钟。
部署全景图:信令双节点加四层负载均衡
图 1:客户端首页,ID 由信令服务器签发
[RustDesk 客户端 xN] | 信令 UDP 21116 / TCP 21117,中继 TCP 21118 [ nginx stream 四层负载均衡 ] | | [rustdesk-server A] [rustdesk-server B] [ relay 中继节点(独立,只挂 21118)]客户端负责会话建立与 P2P 打洞;负载均衡层做四层转发,无状态;信令/中继服务器无本地状态,任意一台可承接新会话,这是双机切换的前提;relay 节点独立部署,避免信令故障连带拖死在途流量。
前置准备:2C4G 起与端口清单
- 2 台 2C4G Linux 服务器(Ubuntu 20.04+ 或 Debian 11),1 台 nginx 负载均衡机(可复用其中一台)
- 端口:UDP
21116(信令)、TCP21117(备用信令)、TCP21118(中继转发) - 构建机需要 Rust 工具链、vcpkg 及
libvpx libyuv opus aom编译依赖(见仓库 Dockerfile 的依赖清单) - 客户端版本与服务端版本保持同一主线,跨大版本可能协议不兼容
克隆源码并编译客户端
git clone https://gitcode.com/GitHub_Trending/ru/rustdesk cd rustdesk && cargo build --release--release全量编译约 15~30 分钟- 产物落在
target/release/,供下一步 systemd 路径引用
核心部署步骤:从防火墙到双节点切换
开放信令与中继端口的防火墙配置
服务器防火墙
ufw allow 21116/udp # 信令主通道,P2P 打洞 ufw allow 21117/tcp # 信令备用通道 ufw allow 21118/tcp # 中继转发 ufw enable- UDP
21116不通时打洞协商无法进行 - TCP
21117是 UDP 受阻时的兜底信令 - TCP
21118承载所有 P2P 失败流量的中转
部署 RustDesk 服务单元并开启自动拉起
服务单元模板在res/rustdesk.service,不要整篇照抄——官方模板缺Restart行(⚠️ 进程崩溃后 systemd 默认不会拉起),按下面三处改完再装:
[Service] ExecStart=/opt/rustdesk/rustdesk --server Restart=always RestartSec=3 LimitNOFILE=100000ExecStart指向二进制真实路径,装错路径服务起不来Restart=always+RestartSec=3:异常退出 3 秒后自动拉起LimitNOFILE决定单机可承载的并发会话上限
配置 nginx 四层负载均衡与中继粘滞
编辑 nginx 配置,在events块后加入:
stream { upstream sig_udp { server 10.0.0.11:21116; server 10.0.0.12:21116; } upstream sig_tcp { server 10.0.0.11:21117; server 10.0.0.12:21117; } upstream relay { server 10.0.0.13:21118; server 10.0.0.14:21118; hash $remote_ip consistent; } server { listen 21116 udp; proxy_pass sig_udp; } server { listen 21117; proxy_pass sig_tcp; } server { listen 21118; proxy_pass relay; } }- 信令 UDP/TCP 做普通轮询,连接短命、无状态
- 中继
hash $remote_ip consistent:同一会话必须粘滞在固定节点,漂移即断流 consistent保证节点增减时大部分哈希桶不动,存量会话不迁移
在客户端填入双节点地址完成接入
客户端设置页的"自定义中继服务器"分别填10.0.0.11:21117、10.0.0.12:21117与对应中继地址,IP 列表两个节点都填,客户端会自动完成切换。验证链路:
sudo nginx -s reload systemctl status rustdesk-server ss -lntu | grep -E '2111[6-8]'图 2:远程会话建立后的文件传输页
关键参数深度解读:最容易配错的三处
将 LimitNOFILE 调到 100000 防 fd 耗尽
- 默认值:systemd 默认
1024 - 推荐值:
100000(res/rustdesk.service模板中的取值) - 为什么:每个远程会话占用多个 fd——视频流、音频、剪贴板、文件传输通道各占一份,并发 500 台设备时
1024上限会被快速吃满,新连接在握手阶段就被拒;100000基本不会触发上限。
中继端口 21118 的定位:兜底通道而非主路
- 默认值:relay 监听
21118 - 推荐值:保持不变
- 为什么:P2P 打洞成功时客户端之间直连,中继不走流量;打洞失败才经
21118中转。中继节点带宽按"预期走中继的流量"规划,通常是全量的零头,把它当主路规划会白白多买带宽。
把 Restart 设为 always 并保留 3 秒间隔
- 默认值:systemd
Restart=no - 推荐值:
Restart=always+RestartSec=3 - 为什么:进程被 OOM killer 或段错误杀掉后,
no意味着 systemd 不再拉起,要等人工发现,而会话已经断了;RestartSec=3给 3 秒缓冲,避免进程反复崩溃时的重启风暴。
故障诊断路径:从连接失败现象逐级定位
现象:客户端卡在"正在连接信令服务器"。先查服务是否还活着——systemctl status rustdesk-server,已退出就journalctl -u rustdesk-server -n 50看崩溃前最后几行,OOM 记录里会写明被杀的时机;再查端口是否真的在监听——ss -lntu | grep 21117,端口没起来通常是进程异常退出,端口在但客户端连不上则是网络问题;最后从客户端侧抓包——tcpdump -i any port 21116 or port 21117,包发出去了收不到回应,问题在中间链路(安全组、NAT)把 UDP 丢了,此时改用 TCP 21117 兜底。
现象:信令通了但延迟高、流量走了中继。在 relay 节点上同时抓两个端口:
tcpdump -i any port 21118 or port 21116 -n- 媒体流全在
21118而21116上几乎没有打洞流量,说明 P2P 长期失败 - 常见根因是客户端侧对称型 NAT,打洞成功率极低
- 可在客户端设置里启用
disable-udp让信令强制走 TCP(src/lang/cn.rs中有该选项的说明文案),打洞成功率下降,换的是连接建立的稳定性
生产环境建议:按规模选边界
- 信令双机 + 四层负载均衡:单台宕机时客户端切到另一台,全程不断信;代价是两台都要预留完整会话容量,平时利用率约 50%
- relay 节点独立部署:不要把信令和中继塞进同一个进程或容器,信令挂了不该连带拖死在途流量;代价是多占一台 2C4G
- 客户端填双节点 IP 列表:切换由客户端本地完成,对业务无感;代价是每个节点都要持有完整设备密钥
- 中继带宽按中继流量预留:别按全量买,实际 P2P 成功的会话不经它;代价是 P2P 失败比例突增时会出现排队
这套方案适合几十到几百台被控设备的私有化部署,单机房或双机房都够用;一旦需要账号体系、Web 管理台或多租户隔离,应升级到商业版 Server Pro;再往上按 K8s 加多可用区规划,本文的单机 systemd 方案就不适用了。
【免费下载链接】rustdeskAn open-source remote desktop application designed for self-hosting, as an alternative to TeamViewer.项目地址: https://gitcode.com/GitHub_Trending/ru/rustdesk
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考