Manjaro GNOME Headless RDP 配置与 NVIDIA vGPU 远程桌面排障记录

Manjaro GNOME Headless RDP 配置记录

适用于:

  • Manjaro Linux
  • GNOME 50
  • gnome-remote-desktop
  • Wayland
  • NVIDIA vGPU / NVIDIA GPU
  • 通过 SSH 以 root 身份完成配置
  • 目标用户:da

1. 问题背景

最开始使用 GNOME 自带的 Remote Login

RDP Client
   ↓
TCP 3389
   ↓
gnome-remote-desktop --system
   ↓
GDM
   ↓
RDP Server Redirection
   ↓
用户 Wayland Session

RDP 能成功连接,但部分客户端会出现:

黑屏
无法连接到远程电脑,因为未及时提供凭据
错误代码: 0x1f07

服务端日志中能看到:

[RDP] Sending server redirection
ERRINFO_LOGOFF_BY_USER

在 Windows .rdp 文件中增加:

use redirection server name:i:1

后可以正常连接。

这说明:

  • NVIDIA vGPU 并不是主要问题;
  • GDM / GNOME Remote Login 已经能成功创建远程 Wayland Session;
  • 问题主要来自部分 RDP 客户端对 Server Redirection 的处理兼容性。

为了避免每台客户端都要修改 .rdp 文件,最终改为:

GNOME Headless 单用户 RDP

新的连接路径:

RDP Client
   ↓
TCP 3389
   ↓
gnome-remote-desktop-daemon --headless
   ↓
GNOME Headless Wayland Session

不再经过:

GDM
Server Redirection

因此不再需要:

use redirection server name:i:1

2. 最终成功环境

实际成功环境:

gnome-remote-desktop 50.2-1
gnome-shell          50.4
mutter               50.4
pipewire             1.6.8

NVIDIA:

NVIDIA RTXA5500-2Q
NVIDIA Driver 580.159.03

DRM KMS:

cat /sys/module/nvidia_drm/parameters/modeset

输出:

Y

设备:

/dev/dri/card1
/dev/dri/renderD128

成功后:

gnome-headless-session@da.service

状态:

active (running)

以及:

gnome-remote-desktop-headless.service

状态:

active (running)

3389:

LISTEN *:3389

进程:

/usr/bin/gnome-shell --mode=user
/usr/lib/gnome-remote-desktop-daemon --headless

GNOME Remote Desktop 日志:

[HWAccel.CUDA] Initialization of CUDA was successful
RDP server started

3. 重要说明

必须以 root 执行本文脚本

例如:

sudo -i

确认:

whoami

应输出:

root

但是:

grdctl --headless 本身配置的是普通用户 da 的用户级 GNOME Remote Desktop。

因此不能直接在 root 环境中运行:

grdctl --headless ...

否则修改的是 root 自己的配置。

本文脚本会自动使用:

runuser -u da

并正确注入:

XDG_RUNTIME_DIR=/run/user/1000
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus

从而修改 da 用户的配置。


4. 一键配置脚本

建议保存为:

/root/fix-gnome-headless-rdp.sh

完整脚本如下:

#!/usr/bin/env bash
set -Eeuo pipefail

USER_NAME="da"
UID_NUM="$(id -u "$USER_NAME")"
HOME_DIR="$(getent passwd "$USER_NAME" | cut -d: -f6)"

RUNTIME="/run/user/$UID_NUM"
BUS="unix:path=$RUNTIME/bus"

CERT_DIR="$HOME_DIR/.local/share/gnome-remote-desktop"
TLS_KEY="$CERT_DIR/rdp-tls.key"
TLS_CERT="$CERT_DIR/rdp-tls.crt"

if [ "$(id -u)" -ne 0 ]; then
    echo "必须使用 root 执行"
    exit 1
fi

echo
echo "=========================================="
echo " GNOME Headless RDP 修复"
echo " User: $USER_NAME"
echo " UID : $UID_NUM"
echo "=========================================="
echo

read -r -p "RDP 用户名 [da]: " RDP_USER
RDP_USER="${RDP_USER:-da}"

while true; do
    read -r -s -p "请输入 RDP 密码: " RDP_PASS
    echo
    read -r -s -p "再次输入 RDP 密码: " RDP_PASS2
    echo

    if [ -n "$RDP_PASS" ] && [ "$RDP_PASS" = "$RDP_PASS2" ]; then
        break
    fi

    echo "密码不一致,请重新输入。"
done

echo
echo "[1] 关闭原来的 GNOME system Remote Login..."

systemctl disable --now gnome-remote-desktop.service 2>/dev/null || true

echo
echo "[2] 清理旧的 GDM RDP 会话..."

while read -r session uid user rest; do
    [ "$user" = "$USER_NAME" ] || continue

    service="$(loginctl show-session "$session" -p Service --value 2>/dev/null || true)"
    type="$(loginctl show-session "$session" -p Type --value 2>/dev/null || true)"
    remote="$(loginctl show-session "$session" -p Remote --value 2>/dev/null || true)"

    if [ "$service" = "gdm-password" ] &&
       [ "$type" = "wayland" ] &&
       [ "$remote" = "yes" ]; then

        echo "终止旧 RDP 图形会话: $session"
        loginctl terminate-session "$session" || true
    fi
done < <(loginctl list-sessions --no-legend)

sleep 2

echo
echo "[3] 启用 da 用户 linger 和 user manager..."

loginctl enable-linger "$USER_NAME"
systemctl start "user@$UID_NUM.service"

for x in $(seq 1 20); do
    [ -S "$RUNTIME/bus" ] && break
    sleep 1
done

if [ ! -S "$RUNTIME/bus" ]; then
    echo "错误:用户 D-Bus 没有启动"
    systemctl status "user@$UID_NUM.service" --no-pager
    exit 1
fi

as_da() {
    runuser -u "$USER_NAME" -- env \
        HOME="$HOME_DIR" \
        USER="$USER_NAME" \
        LOGNAME="$USER_NAME" \
        XDG_RUNTIME_DIR="$RUNTIME" \
        DBUS_SESSION_BUS_ADDRESS="$BUS" \
        "$@"
}

echo
echo "[4] 关闭普通 Desktop Sharing..."

as_da systemctl --user disable --now \
    gnome-remote-desktop.service 2>/dev/null || true

echo
echo "[5] 检查/创建 TLS 证书..."

install -d \
    -o "$USER_NAME" \
    -g "$USER_NAME" \
    -m 700 \
    "$CERT_DIR"

if [ ! -s "$TLS_KEY" ] || [ ! -s "$TLS_CERT" ]; then

    echo "重新创建证书..."

    rm -f "$TLS_KEY" "$TLS_CERT"

    runuser -u "$USER_NAME" -- \
        openssl req \
        -new \
        -newkey rsa:4096 \
        -nodes \
        -x509 \
        -days 3650 \
        -subj "/CN=da-manjaro" \
        -keyout "$TLS_KEY" \
        -out "$TLS_CERT"
fi

chown "$USER_NAME:$USER_NAME" \
    "$TLS_KEY" "$TLS_CERT"

chmod 600 "$TLS_KEY"
chmod 644 "$TLS_CERT"

echo
echo "[6] 写入 Headless RDP 配置..."

as_da grdctl --headless rdp disable 2>/dev/null || true

as_da grdctl --headless rdp set-tls-key \
    "$TLS_KEY"

as_da grdctl --headless rdp set-tls-cert \
    "$TLS_CERT"

as_da grdctl --headless rdp set-auth-methods \
    credentials

echo
echo "写入 RDP 用户名/密码..."

# 注意:
# GNOME Remote Desktop 50.x 支持直接使用:
# grdctl --headless rdp set-credentials USERNAME PASSWORD
#
# 不要使用 stdin 管道模拟输入。
# 某些版本中可能导致 grdctl 段错误。
as_da grdctl --headless rdp set-credentials \
    "$RDP_USER" "$RDP_PASS"

as_da grdctl --headless rdp disable-view-only

as_da grdctl --headless rdp enable

unset RDP_PASS
unset RDP_PASS2

echo
echo "[7] 启动 GNOME Headless 图形 Session..."

if systemctl cat gnome-headless-session@.service >/dev/null 2>&1; then

    echo "发现 gnome-headless-session@.service"

    systemctl enable --now \
        "gnome-headless-session@$USER_NAME.service"

else
    echo "没有发现 gnome-headless-session@.service,跳过。"
fi

sleep 3

echo
echo "[8] 启动 GNOME Remote Desktop Headless..."

as_da systemctl --user daemon-reload

as_da systemctl --user enable --now \
    gnome-remote-desktop-headless.service

sleep 2

as_da systemctl --user restart \
    gnome-remote-desktop-headless.service

echo
echo "[9] 等待 RDP 端口..."

for x in $(seq 1 20); do

    if ss -lnt | grep -qE ':3389[[:space:]]'; then
        break
    fi

    sleep 1
done

echo
echo
echo "============== GRD STATUS =============="
as_da grdctl --headless status || true

echo
echo
echo "============== RDP PORT ================"

if ss -lntp | grep -E ':3389[[:space:]]'; then

    echo
    echo "✅ 3389 已监听"

else

    echo
    echo "❌ 3389 尚未监听"
fi

echo
echo
echo "============== PROCESS ================"

ps -ef | grep -E \
'gnome-shell|gnome-remote-desktop-daemon' \
| grep -v grep || true

echo
echo
echo "============== USER SERVICE ================"

as_da systemctl --user status \
    gnome-remote-desktop-headless.service \
    --no-pager -l || true

echo
echo
echo "============== HEADLESS SESSION ================"

systemctl status \
    "gnome-headless-session@$USER_NAME.service" \
    --no-pager -l 2>/dev/null || true

echo
echo
echo "============== GRD LOG ================"

as_da journalctl --user \
    -u gnome-remote-desktop-headless.service \
    -b -n 80 \
    --no-pager || true

echo
echo
echo "=========================================="

if ss -lnt | grep -qE ':3389[[:space:]]'; then

    echo "✅ GNOME Headless RDP 配置完成"
    echo
    echo "地址:服务器IP:3389"
    echo "用户:$RDP_USER"
    echo
    echo "现在不经过 GDM Remote Login"
    echo "也不需要:"
    echo "use redirection server name:i:1"

else

    echo "⚠️ 配置已经写入,但 3389 没有启动。"
    echo "上面的 GRD LOG / HEADLESS SESSION 会显示具体原因。"
fi

echo "=========================================="

5. 使用方法

第一步:进入 root

sudo -i

第二步:创建脚本

例如:

nano /root/fix-gnome-headless-rdp.sh

粘贴上面的脚本。

保存后:

chmod 700 /root/fix-gnome-headless-rdp.sh

第三步:执行

/root/fix-gnome-headless-rdp.sh

脚本会询问:

RDP 用户名 [da]:
请输入 RDP 密码:
再次输入 RDP 密码:

用户名直接回车即可使用:

da

6. 成功标准

执行:

ss -lntp | grep :3389

应该能看到:

LISTEN ... *:3389 ...

检查 Headless GNOME:

systemctl status gnome-headless-session@da.service

应该:

Active: active (running)

检查用户 GRD:

runuser -u da -- env \
HOME=/home/da \
XDG_RUNTIME_DIR=/run/user/1000 \
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus \
systemctl --user status gnome-remote-desktop-headless.service

应该:

Active: active (running)

7. 查看 Headless RDP 配置

因为当前管理终端通常是 root SSH,因此不要直接:

grdctl --headless status

应该执行:

runuser -u da -- env \
HOME=/home/da \
XDG_RUNTIME_DIR=/run/user/1000 \
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus \
grdctl --headless status

正常:

Overall:
        Unit status: active

RDP:
        Status: enabled
        Port: 3389
        Authentication methods: credentials
        TLS certificate: /home/da/.local/share/gnome-remote-desktop/rdp-tls.crt
        TLS key: /home/da/.local/share/gnome-remote-desktop/rdp-tls.key
        Username: (hidden)
        Password: (hidden)

8. RDP 客户端连接

直接:

服务器IP:3389

用户名:

da

密码:

脚本配置的 RDP 密码

不需要:

use redirection server name:i:1

9. 重启后验证

推荐最终执行:

reboot

服务器启动后,不要先登录图形桌面,也不需要先 SSH。

直接在客户端测试:

服务器IP:3389

如果仍然可以正常进入 GNOME 桌面,说明自动启动已经完整生效。


10. 常用诊断命令

检查 3389

ss -lntp | grep :3389

检查进程

ps -ef | grep -E \
'gnome-shell|gnome-remote-desktop-daemon' \
| grep -v grep

正常至少应该包含:

gnome-shell --mode=user
gnome-remote-desktop-daemon --headless

检查 GNOME Headless Session

systemctl status gnome-headless-session@da.service \
--no-pager -l

检查 Headless GRD 服务

runuser -u da -- env \
HOME=/home/da \
XDG_RUNTIME_DIR=/run/user/1000 \
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus \
systemctl --user status \
gnome-remote-desktop-headless.service \
--no-pager -l

查看 GRD 日志

runuser -u da -- env \
HOME=/home/da \
XDG_RUNTIME_DIR=/run/user/1000 \
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus \
journalctl --user \
-u gnome-remote-desktop-headless.service \
-b \
--no-pager

只看最近 100 行:

runuser -u da -- env \
HOME=/home/da \
XDG_RUNTIME_DIR=/run/user/1000 \
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus \
journalctl --user \
-u gnome-remote-desktop-headless.service \
-b -n 100 \
--no-pager

11. NVIDIA 检查

DRM KMS

cat /sys/module/nvidia_drm/parameters/modeset

正常:

Y

NVIDIA GPU

nvidia-smi

正常情况下可以看到:

gnome-shell
gnome-remote-desktop-daemon

占用 GPU。


DRM 设备

ls -l /dev/dri/

例如:

card1
renderD128

12. MESA-EGL warning 是否需要处理?

实际成功日志中可能出现:

MESA-EGL: warning: pci id for fd ... driver (null)
MESA-EGL: warning: egl: failed to create dri2 screen

但是后面如果紧接着:

[HWAccel.CUDA] Initialization of CUDA was successful
RDP server started

并且:

ss -lntp | grep :3389

能够看到监听,同时客户端 RDP 能正常连接,那么这些 warning 当前可以忽略。

尤其在:

NVIDIA vGPU
NVIDIA 官方/自定义驱动
GNOME Wayland

组合下,Mesa 探测 NVIDIA DRM 设备时出现 warning 并不一定意味着 GRD 启动失败。


13. TPM 警告

可能反复看到:

Init TPM credentials failed because No TPM device found,
using GKeyFile as fallback.

这不是故障。

在 Proxmox VM 没有配置虚拟 TPM 时:

TPM 不存在
↓
GNOME Remote Desktop 检测失败
↓
自动 fallback 到 GKeyFile

因此可以忽略。


14. 常见错误:Cannot autolaunch D-Bus

如果直接在 root SSH 中执行:

systemctl --user ...

可能出现:

Failed to connect to user scope bus
$DBUS_SESSION_BUS_ADDRESS and $XDG_RUNTIME_DIR not defined

原因:

root SSH shell

不是:

da 的 user systemd session

必须使用:

runuser -u da -- env \
HOME=/home/da \
XDG_RUNTIME_DIR=/run/user/1000 \
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus \
systemctl --user ...

15. 常见错误:RDP server certificate is invalid

如果 root 下直接:

grdctl --headless status

出现:

RDP server certificate is invalid

通常不是 da 配置坏了。

因为此时检查的是:

root 的 headless GRD 配置

而不是:

da 的配置

正确方式:

runuser -u da -- env \
HOME=/home/da \
XDG_RUNTIME_DIR=/run/user/1000 \
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus \
grdctl --headless status

16. set-credentials 段错误

曾经使用:

printf '%s\n%s\n' "$RDP_USER" "$RDP_PASS" | \
grdctl --headless rdp set-credentials

结果:

段错误 (核心已转储)

当前版本建议直接:

grdctl --headless rdp set-credentials USERNAME PASSWORD

脚本已经使用:

as_da grdctl --headless rdp set-credentials \
    "$RDP_USER" "$RDP_PASS"

不要再用 stdin 管道模拟交互输入。


17. 原始 GNOME Remote Login 与 Headless 的区别

原 Remote Login

客户端
   ↓
3389
   ↓
gnome-remote-desktop --system
   ↓
GDM
   ↓
创建用户 Session
   ↓
Server Redirection
   ↓
gnome-remote-desktop --handover

优点:

  • 支持类似登录管理器的体验;
  • 可以先看到 GDM;
  • 理论上适合多用户。

缺点:

  • 部分 RDP 客户端对 Server Redirection 兼容不好;
  • 可能需要:
use redirection server name:i:1

Headless 单用户模式

客户端
   ↓
3389
   ↓
da 用户 Headless GRD
   ↓
GNOME Headless Session

优点:

  • 不经过 GDM;
  • 不需要 Server Redirection;
  • 不需要每台客户端修改 .rdp
  • 适合单用户远程工作站;
  • VM 重启后可自动启动;
  • Wayland 原生;
  • NVIDIA GPU / vGPU 可继续使用。

缺点:

  • 固定为指定用户;
  • 不提供传统 GDM 登录界面;
  • 多用户场景不如 system Remote Login 灵活。

18. 恢复到原来的 GNOME Remote Login

如果未来想撤销 Headless 模式:

先进入 root:

sudo -i

关闭 Headless Session:

systemctl disable --now \
gnome-headless-session@da.service

关闭用户 Headless GRD:

runuser -u da -- env \
HOME=/home/da \
XDG_RUNTIME_DIR=/run/user/1000 \
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus \
systemctl --user disable --now \
gnome-remote-desktop-headless.service

然后重新开启 system Remote Login:

systemctl enable --now \
gnome-remote-desktop.service

检查:

ss -lntp | grep :3389

此时重新回到:

system GRD
↓
GDM
↓
Server Redirection

客户端如果再次黑屏,则 .rdp 文件需要:

use redirection server name:i:1

19. 最终结果

最终成功状态:

GNOME Headless Session       ✅
GNOME Remote Desktop         ✅
RDP TCP 3389                 ✅
TLS                           ✅
Credentials                   ✅
GNOME Shell                   ✅
Wayland                       ✅
NVIDIA CUDA acceleration      ✅
Server Redirection            不再需要
.rdp 手工修改                 不再需要

最终客户端只需要:

服务器IP:3389

即可连接。


记录日期

2026-09-15

TAG:Linux, Manjaro

发表新评论