欢迎光临
我们一直在努力

Ubuntu 无显示器远程桌面完美方案

Ubuntu 无显示器远程桌面完美方案

适用环境:Ubuntu 20.04 + Intel 集成显卡 + GNOME 桌面 + ToDesk / RustDesk 等远程工具

问题描述

Linux 主机不接物理显示器时,远程桌面工具(ToDesk、RustDesk、向日葵等)提示 “No display” 或画面分辨率极低(如 1024×768),无法正常远程操作。

根本原因

Intel 集成显卡在没有物理显示器连接时,所有视频输出口(DP、HDMI)均为 disconnected 状态。X11/GNOME 检测不到任何可用的显示输出,远程桌面工具自然无法捕获屏幕画面。

解决思路

整个方案分为两步:

  • 让虚拟显示器"存在" — 通过内核启动参数强制启用一个 HDMI 输出
  • 让虚拟显示器"好用" — 通过后台服务自动将分辨率设为 1920×1080
  • 第一步:内核参数 — 强制启用虚拟 HDMI 输出

    1.1 确认你的 HDMI 接口名称

    ls /sys/class/drm/

    输出类似:card0-DP-1 card0-DP-2 card0-HDMI-A-1 card0-HDMI-A-2 …

    选一个你不常用的 HDMI 口,比如 HDMI-A-1。

    1.2 修改 GRUB 配置

    sudo cp /etc/default/grub /etc/default/grub.bak
    sudo nano /etc/default/grub

    找到 GRUB_CMDLINE_LINUX_DEFAULT 行,添加 video=HDMI-A-1:1920x1080e:

    GRUB_CMDLINE_LINUX_DEFAULT="quiet splash video=HDMI-A-1:1920x1080e"

    参数说明:HDMI-A-1 是内核中的接口名,1920×1080 是虚拟分辨率,末尾的 e 表示 force enable(强制启用,即使没有接显示器)。

    1.3 更新 GRUB 并重启

    sudo update-grub
    sudo reboot

    1.4 验证

    重启后执行:

    cat /proc/cmdline | grep video
    xrandr | grep HDMI-1

    应该能看到 HDMI-1 connected,即使没接物理显示器。

    第二步:后台服务 — 自动设置 1920×1080 分辨率

    虽然第一步让 HDMI-1 显示为"已连接",但由于没有真实显示器提供 EDID 信息,GNOME 只会给它分配一个极低的默认分辨率(通常 1024×768)。需要一个后台服务来自动修正。

    2.1 创建监听脚本

    sudo nano /usr/local/bin/display-monitor.sh

    写入以下内容(纯 bash,无需 Python):

    #!/bin/bash
    export DISPLAY=:0
    export XAUTHORITY=/run/user/$(id -u)/gdm/Xauthority
    export DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$(id -u)/bus"

    LAST_HANDLE_TIME=0

    # 获取 GNOME 显示配置的完整状态
    get_display_state() {
    gdbus call –session \\
    –dest org.gnome.Mutter.DisplayConfig \\
    –object-path /org/gnome/Mutter/DisplayConfig \\
    –method org.gnome.Mutter.DisplayConfig.GetCurrentState 2>/dev/null
    }

    # 通过 GNOME D-Bus 接口应用显示配置(method=1 临时模式,无需确认)
    apply_config() {
    local serial="$1"
    local monitors="$2"
    gdbus call –session \\
    –dest org.gnome.Mutter.DisplayConfig \\
    –object-path /org/gnome/Mutter/DisplayConfig \\
    –method org.gnome.Mutter.DisplayConfig.ApplyMonitorsConfig \\
    "$serial" 1 "$monitors" "{}" >/dev/null 2>&1
    }

    handle_display_change() {
    # 防抖:5 秒内不重复处理(一次插拔可能触发多个事件)
    local now=$(date +%s)
    if (( now – LAST_HANDLE_TIME < 5 )); then
    return
    fi
    LAST_HANDLE_TIME=$now

    sleep 2

    # 为虚拟 HDMI-1 添加 1920×1080 模式(已存在则忽略)
    xrandr –newmode "1920x1080_60.00" 173.00 1920 2048 2248 2576 \\
    1080 1083 1088 1120 -hsync +vsync 2>/dev/null
    xrandr –addmode HDMI-1 "1920x1080_60.00" 2>/dev/null

    # 检查是否有物理显示器连接(排除虚拟的 HDMI-1)
    PHYSICAL=$(xrandr 2>/dev/null \\
    | grep -E "^(DP-|HDMI-[^1])" \\
    | grep " connected " \\
    | head -1 | awk '{print $1}')

    # 一次 D-Bus 调用获取全部状态,避免重复请求
    STATE=$(get_display_state)
    SERIAL=$(echo "$STATE" | grep -oP '\\(uint32 \\K\\d+')
    [ -z "$SERIAL" ] && return

    if [ -n "$PHYSICAL" ]; then
    # —- 有物理显示器:物理屏做唯一主屏,关闭虚拟屏 —-
    MODE=$(echo "$STATE" \\
    | grep -oP "'${PHYSICAL}'.*?'is-preferred': <true>" \\
    | grep -oP "'\\d+x\\d+@[\\d.]+'" | head -1 | tr -d "'")
    [ -z "$MODE" ] && return
    apply_config "$SERIAL" \\
    "[(0, 0, 1.0, 0, true, [('${PHYSICAL}', '${MODE}', {})])]"
    else
    # —- 无物理显示器:虚拟屏做唯一主屏 —-
    CURRENT_RES=$(xrandr 2>/dev/null \\
    | grep "HDMI-1 connected" | grep -oP "\\d+x\\d+")

    if [ -n "
    $CURRENT_RES" ] && [ "$CURRENT_RES" != "1920×1080" ]; then
    apply_config "
    $SERIAL" \\
    "
    [(0, 0, 1.0, 0, true, [('HDMI-1', '1920×1080@59.962844848632812', {})])]"
    fi
    fi
    }

    # 启动时先执行一次,处理开机就没接物理显示器的情况
    handle_display_change

    # 然后持续监听热插拔事件
    udevadm monitor –kernel –subsystem-match=drm 2>/dev/null | while read line; do
    if echo "$line" | grep -q "change"; then
    handle_display_change
    fi
    done

    sudo chmod +x /usr/local/bin/display-monitor.sh

    2.2 创建 systemd 服务

    sudo nano /etc/systemd/system/fix-virtual-display.service

    写入:

    [Unit]
    Description=Auto fix virtual display on monitor hotplug
    After=gdm.service graphical.target

    [Service]
    Type=simple
    User=你的用户名
    ExecStart=/usr/local/bin/display-monitor.sh
    Restart=always
    RestartSec=5

    [Install]
    WantedBy=graphical.target

    将 User=你的用户名 替换为你的实际用户名。

    2.3 启用服务

    sudo systemctl daemon-reload
    sudo systemctl enable fix-virtual-display.service
    sudo systemctl start fix-virtual-display.service

    验证运行状态:

    sudo systemctl status fix-virtual-display.service

    最终效果

    场景行为
    接了物理显示器 纯物理屏,无虚拟屏干扰
    拔掉物理显示器 约 2 秒后自动切换为 1920×1080 虚拟屏
    换了一个物理接口 自动识别新接口并设为主屏
    重启(无物理显示器) 开机后自动启用 1920×1080 虚拟屏

    全程无需手动操作。

    技术要点

    为什么不能只用 xrandr?

    GNOME 的窗口管理器 Mutter 会覆盖 xrandr 的设置。必须通过 Mutter 的 D-Bus 接口 org.gnome.Mutter.DisplayConfig.ApplyMonitorsConfig 来配置,GNOME 才会认可。

    为什么用 method=1(临时模式)?

    D-Bus 的 ApplyMonitorsConfig 有两种模式:

    • method=1(临时):立即生效,无需确认
    • method=2(持久):弹出确认对话框,20 秒不点击会自动回退

    必须用临时模式,原因有二:

  • 持久模式会弹确认框。切换发生在无物理显示器时(人不在电脑前),没人能点确认,20 秒后就会回退。
  • 临时模式不影响可靠性。虽然叫"临时",只是说不写入 GNOME 的持久配置文件,但我们的后台服务常驻运行,每次开机、每次热插拔都会自动重新设置,效果等同于持久。
  • 为什么内核参数不可省略?

    没有 video=HDMI-A-1:1920x1080e,HDMI-1 在无显示器时状态为 disconnected,GNOME 根本不会把它视为一个可用的显示输出,后续所有操作都无从谈起。

    故障排除

    虚拟屏分辨率不对:

    # 手动触发修复
    xrandr –newmode "1920x1080_60.00" 173.00 1920 2048 2248 2576 1080 1083 1088 1120 -hsync +vsync
    xrandr –addmode HDMI-1 "1920x1080_60.00"
    # 然后通过 D-Bus 应用(参考脚本中的 gdbus 部分)

    服务未运行:

    sudo systemctl restart fix-virtual-display.service
    journalctl -u fix-virtual-display.service -f

    想恢复原状:

    sudo systemctl disable –now fix-virtual-display.service
    sudo rm /usr/local/bin/display-monitor.sh
    sudo rm /etc/systemd/system/fix-virtual-display.service
    sudo cp /etc/default/grub.bak /etc/default/grub
    sudo update-grub
    sudo reboot

    赞(0)
    未经允许不得转载:171主机测评 » Ubuntu 无显示器远程桌面完美方案
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址