在远程维护 Windows 主机时,常见方案包括 RustDesk、AnyDesk、直接暴露 RDP、VPN,以及通过 SSH 隧道转发 RDP。

其中一种兼顾安全性、清晰度和使用便利性的方案是:

FRP 负责把远程 Windows 的 SSH 服务映射到公网
SSH 负责建立加密端口转发
RDP 负责提供远程图形桌面
Linux 上使用 KRDC 作为客户端

这种结构不需要把 Windows 的 RDP 端口直接暴露到公网,同时仍然可以获得原生 RDP 较高的画质、较低的带宽占用和良好的剪贴板体验。


一、整体结构

假设存在三台设备:

本地 Linux 工作站
公网中转服务器
远程 Windows 主机

远程 Windows 位于内网,没有公网 IP。Windows 上运行 FRP 客户端,主动连接公网中转服务器上的 FRP 服务端。

FRP 已经建立了一条 SSH 映射:

公网中转服务器:45222
        ↓
远程 Windows:22

因此,在 Linux 上可以通过下面的方式登录远程 Windows:

ssh -p 45222 remoteuser@gateway.example.net

这里连接的虽然是公网中转服务器的地址和端口,但最终进入的是远程 Windows 的 OpenSSH 服务。

在此基础上,再增加一层 SSH 本地端口转发:

Linux 本机 127.0.0.1:14389
        ↓
SSH 加密隧道
        ↓
远程 Windows 127.0.0.1:3389

最终链路如下:

KRDC
  ↓
Linux 127.0.0.1:14389
  ↓
SSH 本地端口转发
  ↓
公网中转服务器:45222
  ↓
FRP
  ↓
Windows OpenSSH
  ↓
Windows 127.0.0.1:3389
  ↓
Windows Remote Desktop Services

需要特别注意:

FRP 映射的仍然只是 SSH,并没有把 RDP 直接暴露到公网。

RDP 流量被封装在 SSH 连接中,由 Windows 的 SSH 服务在远端连接本机的 3389 端口。


二、为什么选择 RDP over SSH

直接将 Windows 的 3389 端口映射到公网虽然简单,但长期使用并不理想。

即使将公网端口改成其他数字,也无法消除以下风险:

  • 自动化端口扫描;
  • 用户名和密码爆破;
  • RDP 服务直接暴露;
  • 防火墙配置错误;
  • 公网端口被遗忘;
  • Windows 服务漏洞带来的攻击面。

通过 SSH 隧道后,公网只保留一个 SSH 入口:

公网可见:
gateway.example.net:45222

公网不可直接访问:
Windows:3389

Linux 上的临时 RDP 入口还可以只绑定回环地址:

127.0.0.1:14389

这意味着只有本机程序可以访问,局域网内其他设备也无法直接连接该端口。


三、Windows 端需要具备的条件

远程 Windows 需要满足以下条件:

  • 使用支持 RDP 服务端的 Windows 版本;
  • OpenSSH Server 正常运行;
  • FRP 客户端可以自动连接公网服务器;
  • Remote Desktop Services 已启用;
  • rdp-tcp 监听器存在;
  • TCP 3389 正在监听。

通常可作为 RDP 服务端的版本包括:

Windows 专业版
Windows 企业版
Windows 教育版

Windows 家庭版一般只能作为 RDP 客户端,不能直接接受标准微软 RDP 登录。


四、通过 SSH 检查 Windows 的 RDP 状态

通过 SSH 登录 Windows 后,默认可能进入 cmd.exe

remoteuser@WIN-REMOTE C:\Users\remoteuser>

此时 PowerShell 命令不能直接执行。

先输入:

powershell

提示符变成:

PS C:\Users\remoteuser>

之后再进行检查。

1. 检查 Windows 版本

Get-CimInstance Win32_OperatingSystem |
    Select-Object Caption, Version, OSArchitecture

2. 检查 RDP 服务

Get-Service TermService |
    Select-Object Status, StartType, Name

正常运行时应显示:

Status : Running
Name   : TermService

3. 检查远程桌面开关

Get-ItemProperty `
    'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server' `
    -Name fDenyTSConnections |
    Select-Object fDenyTSConnections

结果含义:

0:允许远程桌面
1:禁止远程桌面

4. 检查 RDP 监听器

qwinsta

正常情况下应出现:

rdp-tcp    65536    侦听

如果输出中只有:

services
console

而没有 rdp-tcp,说明 RDP 监听器没有建立。

5. 检查 3389 端口

Get-NetTCPConnection `
    -LocalPort 3389 `
    -State Listen `
    -ErrorAction SilentlyContinue |
    Select-Object LocalAddress, LocalPort, State, OwningProcess

正常状态通常会出现:

0.0.0.0    3389    Listen
::         3389    Listen

6. 从 Windows 本机测试 RDP

Test-NetConnection 127.0.0.1 -Port 3389 |
    Select-Object ComputerName, RemotePort, TcpTestSucceeded

只有出现下面的结果,SSH 隧道才可能成功:

TcpTestSucceeded : True

五、启用 Windows RDP

如果 RDP 原本关闭,可以在管理员 PowerShell 中执行:

Set-ItemProperty `
    -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server' `
    -Name fDenyTSConnections `
    -Value 0

Start-Service TermService

还可以检查 RDP-Tcp 监听器配置:

$rdpPath =
'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp'

Get-ItemProperty $rdpPath |
    Select-Object PortNumber,
                  fEnableWinStation,
                  fLogonDisabled,
                  UserAuthentication

常见有效值为:

PortNumber          3389
fEnableWinStation   1
fLogonDisabled      0

需要注意,修改监听器注册表后,正在运行的 TermService 不一定立即重新加载配置。

可能出现这样的状态:

TermService 已经运行
fDenyTSConnections 已经是 0
但 rdp-tcp 仍不存在
3389 仍未监听

如果远程主机正在运行重要计算任务,不应为了恢复 RDP 而强行重启。应优先保护任务,等待合适的维护窗口。

某些情况下,只有 Windows 完整重启后,RDP-Tcp 监听器才会重新建立。


六、在 Linux 上建立 SSH 隧道

假设公网 SSH 入口为:

gateway.example.net:45222

Windows SSH 用户为:

remoteuser

Linux 本地临时 RDP 端口为:

14389

执行:

ssh -N \
  -L 127.0.0.1:14389:127.0.0.1:3389 \
  -p 45222 \
  -o ExitOnForwardFailure=yes \
  -o ServerAliveInterval=60 \
  -o ServerAliveCountMax=3 \
  remoteuser@gateway.example.net

执行成功后,终端不会返回 Shell 提示符,也通常没有任何输出。这是正常状态。

该终端需要保持打开。


七、SSH 本地端口转发的参数含义

核心参数是:

-L 127.0.0.1:14389:127.0.0.1:3389

格式为:

-L 本地监听地址:本地监听端口:远程目标地址:远程目标端口

本例表示:

在 Linux 本机监听 127.0.0.1:14389
收到连接后,通过 SSH 发送到远程 Windows
再由 Windows 的 SSH 服务连接 Windows 本机的 127.0.0.1:3389

其中两个 127.0.0.1 分别属于不同的主机:

第一个 127.0.0.1:Linux 本机
第二个 127.0.0.1:远程 Windows

-N

不打开远程命令行,只维持端口转发

ExitOnForwardFailure=yes

如果本地端口无法监听,例如端口已经被占用,SSH 会立即退出。

否则可能出现 SSH 看起来正常运行,但实际端口转发没有建立的情况。

ServerAliveInterval=60

每隔一段时间发送 SSH 保活消息,降低连接被中间设备因空闲而断开的概率。

ServerAliveCountMax=3

连续多次保活失败后结束连接,避免产生已经失效但仍然残留的隧道进程。


八、普通 SSH 和 RDP 隧道可以同时使用

同一个公网 SSH 端口可以同时接受多个独立 TCP 连接。

例如:

连接 A:普通 SSH 管理
连接 B:RDP SSH 隧道
连接 C:SFTP 文件传输

普通 SSH:

ssh -p 45222 remoteuser@gateway.example.net

RDP 隧道:

ssh -N \
  -L 127.0.0.1:14389:127.0.0.1:3389 \
  -p 45222 \
  remoteuser@gateway.example.net

两者是不同的 SSH 会话,不会互相冲突。

关闭其中一个连接,也不会自动关闭另一个连接。


九、检查 Linux 本地隧道

1. 查看监听状态

ss -lntp | grep ':14389'

正常情况下会看到:

LISTEN 0 128 127.0.0.1:14389 0.0.0.0:* users:(("ssh",pid=12345,fd=4))

这说明 Linux 本地的 SSH 进程已经监听端口。

2. 使用 netcat 测试

nc -vz 127.0.0.1 14389

成功时会显示:

Connection to 127.0.0.1 14389 port [tcp/*] succeeded

但这里有一个容易误解的地方。

nc 成功只说明:

Linux 本地能够连接到 SSH 创建的监听端口

它不能单独证明:

远程 Windows 的 3389 一定正常

完整判断应同时满足:

Linux 14389 正在监听
Windows 3389 正在监听
Windows 本机测试 3389 为 True
qwinsta 中存在 rdp-tcp 侦听

十、在 KRDC 中连接

在 KDE Plasma 中打开:

krdc

连接地址填写:

rdp://127.0.0.1:14389

不要填写:

gateway.example.net:45222

因为公网端口是 SSH 入口,不是 RDP 服务。

KRDC 实际连接的是 Linux 本机:

127.0.0.1:14389

SSH 客户端会自动把这条连接送到远程 Windows。


十一、KRDC 的认证信息

假设远程 Windows 信息如下:

Windows 用户名:remoteuser
Windows 计算机名:WIN-REMOTE

KRDC 可填写:

Username: remoteuser
Domain: WIN-REMOTE
Password: Windows 账户密码

另一种写法是:

Username: WIN-REMOTE\remoteuser
Domain: 留空
Password: Windows 账户密码

这里必须使用 Windows 账户密码,而不是:

  • Windows Hello PIN;
  • SSH 私钥密码;
  • FRP 认证密钥;
  • Linux 用户密码;
  • KDE Wallet 密码。

KRDC 中的密码可以交给 KDE Wallet 保存。


十二、制作便捷启动脚本

为了避免每次手动输入完整命令,可以建立一个简单脚本。

例如:

~/bin/start-windows-rdp

内容如下:

#!/usr/bin/env bash

exec ssh -N \
  -L 127.0.0.1:14389:127.0.0.1:3389 \
  -p 45222 \
  -o ExitOnForwardFailure=yes \
  -o ServerAliveInterval=60 \
  -o ServerAliveCountMax=3 \
  remoteuser@gateway.example.net

创建方法:

mkdir -p ~/bin

cat > ~/bin/start-windows-rdp <<'EOF'
#!/usr/bin/env bash

exec ssh -N \
  -L 127.0.0.1:14389:127.0.0.1:3389 \
  -p 45222 \
  -o ExitOnForwardFailure=yes \
  -o ServerAliveInterval=60 \
  -o ServerAliveCountMax=3 \
  remoteuser@gateway.example.net
EOF

chmod +x ~/bin/start-windows-rdp

以后只需要执行:

start-windows-rdp

然后在 KRDC 中打开已经保存的连接:

rdp://127.0.0.1:14389

关闭时在脚本终端按:

Ctrl+C

这只会关闭 SSH 隧道,不会影响:

  • Windows 上正在运行的任务;
  • Windows OpenSSH;
  • FRP 客户端;
  • 普通 SSH 会话;
  • 其他网络连接。

十三、使用 SSH 配置别名

也可以在 Linux 的 SSH 配置中定义别名:

Host office-windows
    HostName gateway.example.net
    Port 45222
    User remoteuser
    ExitOnForwardFailure yes
    ServerAliveInterval 60
    ServerAliveCountMax 3

普通 SSH 可以简化为:

ssh office-windows

RDP 隧道可以简化为:

ssh -N \
  -L 127.0.0.1:14389:127.0.0.1:3389 \
  office-windows

需要注意,如果脚本中写了:

ssh office-windows

但 SSH 配置中没有定义这个别名,就会出现:

Could not resolve hostname office-windows:
Name or service not known

此时系统会把 office-windows 当成真实域名解析,而不是 SSH 别名。

不希望依赖 SSH 配置时,应直接在脚本中写完整主机地址和端口。


十四、让连接更加自动化

可以进一步制作一个启动脚本,先检查端口,再建立隧道。

#!/usr/bin/env bash

set -u

LOCAL_PORT=14389
REMOTE_HOST='gateway.example.net'
REMOTE_PORT=45222
REMOTE_USER='remoteuser'

if ss -lnt | grep -q "127.0.0.1:${LOCAL_PORT}"; then
    echo "RDP 隧道已经存在:127.0.0.1:${LOCAL_PORT}"
    exit 0
fi

exec ssh -N \
  -L "127.0.0.1:${LOCAL_PORT}:127.0.0.1:3389" \
  -p "${REMOTE_PORT}" \
  -o ExitOnForwardFailure=yes \
  -o ServerAliveInterval=60 \
  -o ServerAliveCountMax=3 \
  "${REMOTE_USER}@${REMOTE_HOST}"

这样可以避免重复运行后出现:

bind: Address already in use

还可以建立 KDE 应用菜单启动项,分别执行:

启动 SSH 隧道
打开 KRDC

不过不建议把隧道做成完全无人值守的永久后台服务,除非确实需要持续使用。

临时启动、用完关闭,更容易理解和控制连接状态。


十五、剪贴板与文件传输

RDP 原生支持剪贴板重定向。

常见效果包括:

Linux 复制文字 → Windows 粘贴
Windows 复制文字 → Linux 粘贴

部分客户端还可以支持:

  • 图片复制;
  • 文件复制粘贴;
  • 本地磁盘映射;
  • 音频重定向;
  • 打印机重定向。

KRDC 中应检查是否启用了:

Clipboard
Clipboard redirection

对于大文件,不建议长期依赖剪贴板。

更稳定的方式包括:

SFTP
SCP
SMB
RDP 磁盘重定向
文件同步工具

十六、RDP 与 RustDesk 的画质差异

RustDesk 更接近传统远程控制软件:

捕获远程电脑当前屏幕
        ↓
编码为连续图像或视频流
        ↓
通过网络发送
        ↓
客户端解码并缩放

这种方式适合查看远程电脑实体屏幕,也适合作为紧急救援工具。

但在高分辨率桌面上,容易出现:

  • 字体边缘模糊;
  • 窗口边框不够锐利;
  • 快速滚动时出现压缩痕迹;
  • 网络波动时降低画质;
  • 客户端窗口和远程显示器分辨率不匹配。

RDP 的工作方式不同。

RDP 更接近为远程客户端创建一套远程桌面显示环境,并针对桌面界面进行优化:

  • 只传输发生变化的区域;
  • 对图形内容进行缓存;
  • 针对文字和窗口元素优化;
  • 静止桌面时流量很低;
  • 分辨率可以配合客户端窗口;
  • 剪贴板、音频和磁盘属于协议功能。

对于以下工作,RDP 通常明显优于 RustDesk:

PowerShell
终端
文件管理器
文本编辑器
Excel
系统设置
任务管理器
后台任务监控

相同带宽下,RDP 通常能够提供:

更清晰的文字
更锐利的界面
更低的静态流量
更自然的窗口缩放

十七、RDP 是否一定更省带宽

对于办公桌面和文字界面,通常是。

静止桌面时,RDP 基本只需要发送少量保活和状态数据。

移动窗口、编辑文字或查看任务状态时,只需传输变化部分。

RustDesk 等工具则更依赖屏幕图像编码。即使使用高效视频编码,也通常需要在画质、帧率和带宽之间进行取舍。

但在以下场景中,RDP 的优势会缩小:

  • 播放视频;
  • 运行高帧率动画;
  • 显示大量动态图像;
  • 快速滚动图片网页;
  • 3D 图形;
  • 游戏。

这些内容本身接近视频流,RDP 也需要使用图形或视频编码。


十八、SSH 隧道只转发 TCP

SSH 的 -L 本地端口转发承载的是 TCP。

现代 RDP 在某些环境下也可以使用 UDP,以改善:

  • 高延迟;
  • 丢包;
  • 音频;
  • 动态画面;
  • 快速交互。

通过 SSH 本地端口转发时,RDP 通常只能使用 TCP 通道。

因此这种方案特别适合:

办公桌面
文字操作
系统维护
文件管理
计算任务监控
轻度图形界面

不适合追求:

云游戏
高帧率视频
低延迟音视频制作
大型 3D 应用

十九、RDP 会话和远程电脑实体屏幕

RustDesk 通常连接的是远程电脑当前正在显示的实体桌面。

RDP 则可能建立或切换到远程会话。

连接后可能出现:

  • 远程 Windows 实体屏幕锁定;
  • 控制台用户被切换;
  • 远程桌面和实体桌面不能同时操作同一会话。

但正常情况下,RDP 连接本身不会自动停止:

  • Windows 服务;
  • 后台计算任务;
  • 计划任务;
  • 正确独立运行的程序;
  • 系统级进程。

结束使用时,建议在 KRDC 中选择:

Disconnect
断开连接

不要误选:

Sign out
注销

注销会结束 Windows 用户会话,可能同时关闭该会话中运行的应用程序。


二十、故障排查顺序

遇到 KRDC 连接失败时,建议按照从外到内的顺序排查。

1. 检查公网 SSH

ssh -p 45222 remoteuser@gateway.example.net

如果普通 SSH 无法登录,问题可能位于:

  • FRPS;
  • FRPC;
  • 公网防火墙;
  • Windows OpenSSH;
  • DNS;
  • 网络连接。

2. 检查 Linux 隧道

ss -lntp | grep ':14389'

如果没有输出,说明隧道没有建立。

3. 检查本地端口

nc -vz 127.0.0.1 14389

4. 检查 Windows RDP 服务

Get-Service TermService

5. 检查 RDP 开关

Get-ItemProperty `
  'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server' `
  -Name fDenyTSConnections

6. 检查监听器

qwinsta

必须出现:

rdp-tcp    侦听

7. 检查 Windows 3389

Test-NetConnection 127.0.0.1 -Port 3389

必须出现:

TcpTestSucceeded : True

8. 检查 KRDC 地址

必须连接:

rdp://127.0.0.1:14389

不能连接公网 SSH 端口。

9. 检查认证信息

确认:

用户名正确
域名或计算机名正确
使用的是 Windows 账户密码

二十一、常见报错

Could not resolve hostname

Could not resolve hostname office-windows

原因通常是 SSH 别名没有定义,或者主机名拼写错误。

Address already in use

bind: Address already in use

本地端口已经被其他进程占用。

检查:

ss -lntp | grep ':14389'

Connection refused

如果 SSH 隧道终端出现:

channel open failed: connect failed: Connection refused

通常说明:

SSH 已经连接到 Windows
但 Windows 的 127.0.0.1:3389 没有服务监听

KRDC 认证失败

可以尝试:

Username: remoteuser
Domain: WIN-REMOTE

或:

Username: WIN-REMOTE\remoteuser
Domain: 留空

二十二、安全建议

长期使用时建议保持以下原则:

  • SSH 优先使用密钥认证;
  • Windows 账户不要使用弱密码;
  • 公网 FRP 端口尽量限制来源地址;
  • 不直接暴露 RDP 3389;
  • Linux 本地端口只绑定 127.0.0.1
  • 不使用 0.0.0.0:14389,除非确实需要共享;
  • 不使用长期无人值守的隧道,除非有明确需求;
  • 修改 Windows 注册表前先备份;
  • 重要任务运行期间不要随意重启 Windows;
  • 保留一种独立于 SSH 和 RDP 的应急控制方式。

二十三、推荐的远程管理层次

比较合理的长期结构是:

第一层:SSH
用于命令行、任务管理、脚本和服务检查

第二层:RDP over SSH
用于图形桌面、文件管理和 Windows 应用

第三层:RustDesk
用于 SSH、FRP 或 RDP 失效时的紧急救援

这种组合兼顾了:

  • 安全性;
  • 画质;
  • 带宽效率;
  • 操作便利性;
  • 故障恢复能力。

结语

FRP、SSH 和 RDP 并不是三个互相替代的工具,而是可以组成一条层次清晰的远程访问链路。

FRP 解决内网主机无法被公网直接访问的问题,SSH 提供安全的远程入口和端口转发,RDP 则提供高质量的 Windows 图形桌面体验。

整个方案的核心是:

公网只开放 SSH
RDP 不直接暴露
Linux 本地临时创建 RDP 入口
用完后关闭 SSH 隧道

对于需要长期运行计算任务、偶尔进入 Windows 图形界面检查状态的远程主机,这种方式通常比长期依赖屏幕捕获型远程控制软件更清晰、更节省带宽,也更适合作为日常主力方案。

Leave a Reply

Your email address will not be published. Required fields are marked *