GenStudio 推出 Infini 编码套餐(Coding Plan)GenStudio 推出 Infini 编码套餐(Coding Plan) ,接入多家顶尖厂商的主流编程模型了解更多
Skip to content
回到全部文章

在容器化 Ubuntu 上安装 XFCE4 并配置生产就绪 VNC 环境

本教程将指导您在容器化 Ubuntu 系统上以无头模式安装 XFCE4 桌面环境,利用 GPU 加速的 Xorg 并通过 VNC 启用安全远程访问,同时将 Google Chrome 设置为默认浏览器。这个生产就绪版本包含了全面的调试措施、监控工具和防空闲解决方案,用于防止和排除 VNC 无响应问题。

应对环境限制的特殊配置

AIStudio 开发机/极值算力实例通常运行在平台托管的容器化 Ubuntu 环境中。为保障安全与一致性,平台会对网络暴露、权限、初始化系统等做限制。如果您在普通虚拟机或物理机上部署桌面环境,很多步骤会更简单。

为了在上述限制下稳定运行 GPU 加速桌面,本教程特别针对以下限制设计了“适配/绕过”方案:

  1. 仅 SSH 可达(不直接暴露 VNC 端口)

    • 限制:容器端口通常不会直接对外开放。
    • 对策:VNC 服务仅监听 localhostx11vnc -localhost),并通过 SSH 端口转发访问(见 Step 8)。
  2. 无 Systemd(服务不会自动自启动)

    • 限制:PID 1 不是 systemdsystemctl 不可用于管理桌面/VNC;安装 cron 也不一定会自动启动。
    • 对策:用 start-vnc-desktop.sh 统一编排启动顺序,并使用 vnc-recovery-loop.sh 代替 systemd/cron 做周期性自愈。
  3. 无头 + 无物理输入设备

    • 限制:没有显示器/键盘/鼠标,/dev/input 可能为空。
    • 对策:使用专门的 headless xorg.confAllowEmptyInputAutoAddDevices=false),并启用 XTEST 让 VNC 可以注入输入事件。
  4. Vulkan 应用(Isaac Sim/OmniGibson)需要额外验证

    • 限制glxinfo 只能验证 OpenGL;不少 3D 应用更依赖 Vulkan。
    • 对策:建议在安装后运行 vulkaninfo --summary,确认 GPU0 为 NVIDIA(不是 llvmpipe)。如遇问题,可参考 开发机常见问题排查指南 中的 “Vulkan 找不到 GPU(仅识别到 llvmpipe / CPU)”。
  5. NVENC 可用性提示(影响高性能串流方案)

    • 限制:在部分容器环境中,即使 ffmpeg -encoders 显示 h264_nvenc,硬件编码仍可能不可用。

    • 原因(平台侧)h264_nvenc 只代表用户态编码库存在;NVENC 真正可用还需要平台把视频编码相关的 NVIDIA 设备能力暴露给容器(常见体现为 /dev/nvidia-caps/* 等设备节点可用,且运行时开启了 video 驱动能力)。在“仅挂载 GPU 计算能力、未开放视频能力”的容器环境里,ffmpeg 会在创建 NVENC 编码会话阶段失败,因此表现为“看起来有 nvenc,但实际用不了”。

    • 对策:本教程的 VNC 方案不依赖 NVENC;如果您计划使用依赖 NVENC 的串流方案(例如部分 WebRTC/DCV 配置),请先用以下命令自检:

      bash
      ffmpeg -hide_banner -loglevel error -f lavfi -i testsrc=duration=1:size=1280x720:rate=30 -c:v h264_nvenc -f null -

      如果出现 unsupported device/No capable devices found,表示当前环境可能无法使用 NVENC。

(可选)环境自检:确认您处在受限容器化 Ubuntu 环境

下面命令不是必需的,主要用于排查问题时快速确认“平台约束”是否存在。部分命令(例如 pgrep)来自 Step 1 安装的软件包;如果提示 command not found,请先完成 Step 1 再回来验证。

  • 无头配置:没有物理显示器或输入设备(如键盘、鼠标)。

    bash
    # 验证无头设置
    ls /dev/input/          # 应显示最少或无输入设备
    echo $DISPLAY           # 应显示 :0 或类似的 X 显示
    who                     # 应显示无物理控制台用户
  • GPU 访问:容器通过 NVIDIA Container Toolkit 具有 NVIDIA GPU 访问权限。

    bash
    # 验证 GPU 访问
    nvidia-smi              # 应显示 GPU 信息
    ls /dev/nvidia*         # 应显示 NVIDIA 设备文件
    lsmod | grep nvidia     # 应显示已加载的 NVIDIA 内核模块
  • 非特权模式:容器不能在特权模式下运行。

    bash
    # 验证非特权模式
    cat /proc/1/status | grep CapEff    # 应显示有限的功能
    ls /sys/fs/cgroup/                  # 应显示 cgroup 限制
    mount | grep "type cgroup"          # 应显示 cgroup 挂载
  • 非 Systemd 初始化:使用 runsvdir(来自 runit),而不是 systemd

    bash
    # 验证初始化系统
    ps aux | head -2              # 应显示 runsvdir 或类似的 PID 1
    ls -la /proc/1/exe            # 应指向 runsvdir 或 runit
    pgrep -f "runsvdir\|runsv"    # 应显示 runit 进程
  • 精简镜像:预安装的软件包有限。

    bash
    # 验证精简安装
    dpkg -l | wc -l                    # 应显示相对较少的软件包
    which firefox || echo "Not found"  # 应显示 Firefox 未安装
    which code || echo "Not found"     # 应显示 VS Code 未安装
    which libreoffice || echo "Not found"  # 应显示 LibreOffice 未安装
  • VNC 密码要求:必须通过密码进行安全访问。

    bash
    # 验证 VNC 密码设置
    ls ~/.vnc/passwd         # 应显示 VNC 密码文件
    file ~/.vnc/passwd       # 应显示 "data" 指示加密密码
    x11vnc -help | grep auth # 应显示认证选项
  • XFCE4 无头问题:某些插件(如电源管理器)可能由于缺少硬件或依赖项而失败。

    bash
    # 验证硬件设备限制
    ls /sys/class/power_supply/  # 应显示无或最少的电源设备
    ls /sys/class/backlight/     # 应显示无背光设备
    dmesg | grep -i "power\|acpi" # 应显示有限的电源管理
  • ⚠️ VNC 输入响应性:VNC 会话在空闲期间可能停止响应鼠标点击,可能是由于屏幕保护程序或服务器设置导致的。本教程为此问题提供了全面的解决方案。

    bash
    # 验证屏幕保护程序和电源管理设置
    export DISPLAY=:0
    xset q | grep -A3 "Screen Saver"  # 应显示屏幕保护程序设置
    xset q | grep -A3 "DPMS"          # 应显示电源管理设置
  • Snap 限制:由于 squashfs 挂载限制,不支持 Snap 软件包(如 Firefox)。

    bash
    # 验证 snap 限制
    snap list 2>/dev/null || echo "Snap not available"
    mount | grep squashfs || echo "No squashfs mounts"
    ls /snap 2>/dev/null || echo "Snap directory not available"

理解生产就绪系统架构

在深入脚本之前,让我们了解此生产就绪教程提供的内容以及各组件如何协同工作。

脚本概述和用途

此教程创建了多个脚本,它们协同工作以提供健壮的自愈 VNC 桌面环境:

脚本用途运行时机是否必需?
start-vnc-desktop.sh主要启动协调器您手动运行
anti-idle.sh防止 VNC 无响应在后台自动运行
vnc-monitor.sh系统健康监控在后台自动运行📊 调试
vnc-recovery.sh一次性健康检查与修复手动运行或由恢复循环调用🔧 恢复
vnc-recovery-loop.sh自动恢复循环(自愈)由启动脚本启动,后台每 2 分钟运行一次推荐
vnc-health-check.sh手动故障排除工具需要调试时运行🩺 手动
start-ibus.sh中文输入法设置(IBus + 候选框)CHINESE_IME_BACKEND=ibus 时随桌面启动(可禁用)默认启用
create-ibus-script.shIBus 脚本生成器CHINESE_IME_BACKEND=ibus 时使用(脚本缺失时兜底创建)默认启用

系统架构图

仅需基本使用的用户

如果您只想要一个工作的 VNC 桌面,而不需要所有监控复杂性,您只需要:

  1. 遵循 Step 1-6(软件包安装、Xorg 配置、脚本创建、VNC 配置、浏览器配置)
  2. 遵循 Step 7-8,启动生产就绪的 VNC 桌面系统,并从本地连接到 VNC 桌面系统

需要完整监控和恢复的用户

  1. 遵循 Step 1-6(软件包安装、Xorg 配置、脚本创建、VNC 配置、浏览器配置)
  2. 遵循 Step 7-8,启动生产就绪的 VNC 桌面系统,并从本地连接到 VNC 桌面系统
  3. 遵循故障排除和监控中的步骤,获取全面的日志记录,掌握手动恢复功能。

前提条件

  • 已挂载 GPU 的 Ubuntu 容器(例如 AIStudio 开发机或极值算力实例)。

Step 1 安装必要的软件包(生产就绪版)

更新软件包列表并安装 XFCE4、Xorg、VNC、实用工具以及 Google Chrome 作为网页浏览器所需的软件包。包含 fonts-noto-cjk 软件包以支持 CJK 语言,安装 fonts-liberation 以满足 Chrome 的依赖关系。还包含了额外的调试工具。

bash
apt-get update && apt-get install -y \
    fonts-noto-cjk \
    fonts-liberation \
    xfce4 xfce4-goodies \
    xorg \
    x11vnc \
    mesa-utils \
    vulkan-tools \
    x11-utils \
    xfonts-base xfonts-100dpi xfonts-75dpi xfonts-cyrillic \
    wget \
    desktop-file-utils \
    xdotool \
    net-tools \
    procps \
    psmisc \
    usbutils \
    pciutils \
    kmod \
    ibus \
    ibus-pinyin \
    ibus-libpinyin \
    dbus-x11 \
    fcitx5 \
    fcitx5-chinese-addons \
    fcitx5-frontend-gtk3 \
    fcitx5-config-qt \
    && wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb \
    && dpkg -i google-chrome-stable_current_amd64.deb \
    && apt-get install -f \
    && apt-get clean && rm -rf /var/lib/apt/lists/* google-chrome-stable_current_amd64.deb

软件包说明

  • 核心软件包

    • fonts-noto-cjk:添加对中文、日文和韩文字符的支持,确保在各应用程序中正确渲染 CJK 文本
    • fonts-liberation:Google Chrome 正常运行所需的依赖项
    • xfce4xfce4-goodies:核心桌面环境和实用工具(如 thunarxfce4-terminal
    • xorg:用于图形输出的 X 服务器
    • x11vnc:用于远程访问的 VNC 服务器
    • mesa-utils:包含 glxinfo 以验证 GPU 加速
    • vulkan-tools:包含 vulkaninfo 以验证 Vulkan GPU 设备(对 Isaac Sim/OmniGibson 等 Vulkan 应用很重要)
    • xfonts-*:字体包,防止 Xorg 日志中出现字体相关警告
    • wget:用于下载 Chrome .deb 软件包
    • desktop-file-utils:确保正确处理桌面文件更新
  • 增强调试软件包

    • xdotool防空闲功能的关键组件 - 提供 X11 自动化工具,用于发送虚假鼠标移动和键盘事件,防止系统检测到可能触发电源管理或屏幕锁定的空闲状态
    • net-tools网络连接调试 - 包含 netstat,用于监控 VNC 端口可用性和网络连接,对于诊断 VNC 连接问题至关重要
    • x11-utilsX11 诊断工具 - 提供 xdpyinfo 等命令,用于脚本化检测 X 服务器是否响应、扩展是否可用(例如 XTEST)
    • procps进程与资源工具 - 提供 pgrep/pkill/free/uptime 等命令,供监控与恢复脚本使用
    • psmisc补充进程工具 - 提供 killallpstree 等(可选,但排查问题时很有用)
    • usbutilsUSB 设备检查 - 提供 lsusb 命令用于列出 USB 设备,并在容器化环境中调试与 USB 相关的问题
    • pciutilsPCI 设备检查 - 提供 lspci 命令用于列出 PCI 设备,对于 GPU Bus ID 检测和硬件故障排除至关重要
    • kmod内核模块管理 - 提供 lsmod 命令用于列出已加载的内核模块,对于验证 NVIDIA 驱动程序和其他内核模块状态很有用
  • 中文输入法软件包(可选,用于全面的中文输入支持):

    • ibus主要输入法框架 - 管理输入法切换的主要 IBus 守护进程,为中文输入提供基础
    • ibus-pinyin拼音输入引擎 - 提供基于拼音的中文字符输入和智能转换
    • ibus-libpinyin增强拼音库 - 更先进的拼音处理,具有更好的候选词建议算法
    • dbus-x11DBus 会话支持 - 在 X11 环境中进程间 IBus 通信的必需组件,是正确 IME 功能所必需的
    • fcitx5替代 IME 框架 - 轻量级输入法框架,systemd 依赖较少,如果 IBus 失败可作为备用
    • fcitx5-chinese-addonsfcitx5 的中文输入引擎 - 为 fcitx5 提供拼音和其他中文输入法
    • fcitx5-frontend-gtk3GTK3 集成 - 在基于 GTK3 的应用程序中启用中文输入
    • fcitx5-config-qt配置工具 - 基于 Qt 的 fcitx5 配置界面

Step 2 更新字体缓存

安装字体后,更新字体缓存以确保系统识别新的 CJK 字体:

bash
sudo fc-cache -fv

Step 3 为无头 GPU 加速操作配置 Xorg(生产就绪版)

创建优化的 xorg.conf 文件,以便在无头模式下使用 NVIDIA GPU 加速运行 Xorg,明确启用 XTEST 扩展以处理 VNC 输入,同时添加额外的防空闲 GPU 设置

创建生产就绪版 xorg.conf

bash
echo 'Section "ServerLayout"
    Identifier "Layout0"
    Screen 0 "Screen0"
    Option "AutoAddDevices" "false"
    Option "AllowEmptyInput" "true"
EndSection

Section "Device"
    Identifier "NVIDIA Card"
    Driver "nvidia"
    # 注意:在使用 NVIDIA Container Toolkit 的容器环境中,通常不需要指定 BusID
    # NVIDIA 驱动会自动选择容器可访问的 GPU(通过 nvidia-smi -L 可见的 GPU)
    # BusID "PCI:65:0:0"  # 仅在多 GPU 环境中需要指定特定 GPU 的 BusID
    Option "UseDisplayDevice" "none"
    Option "ConnectedMonitor" "DFP-0"
    Option "ModeValidation" "NoEdidModes"
    Option "RegistryDwords" "PowerMizerEnable=0x1; PerfLevelSrc=0x2222; PowerMizerDefault=0x1; PowerMizerDefaultAC=0x1"
    Option "TripleBuffer" "True"
    Option "OnDemandVBlankInterrupts" "True"
    Option "AllowIndirectGLXProtocol" "false"
EndSection

Section "Screen"
    Identifier "Screen0"
    Device "NVIDIA Card"
    Monitor "Monitor0"
    SubSection "Display"
        Depth 24
        Modes "1920x1080"
        Virtual 1920 1080
    EndSubSection
EndSection

Section "Monitor"
    Identifier "Monitor0"
EndSection

Section "Extensions"
    Option "XTEST" "Enable"
EndSection' > /etc/X11/xorg.conf

Xorg 配置说明

  • 生产就绪设备选项

    • ConnectedMonitor "DFP-0"正确分辨率的关键设置 - 强制 NVIDIA 驱动程序识别虚拟显示连接,防止在未检测到物理显示器时默认为 640x480 分辨率
    • ModeValidation "NoEdidModes"绕过硬件检测 - 防止驱动程序尝试查询显示器 EDID 数据,允许系统使用配置中指定的自定义分辨率
    • Virtual 1920 1080强制帧缓冲区大小 - 在指定的确切分辨率下创建虚拟帧缓冲区,确保不管驱动程序检测逻辑如何都能一致地渲染 1920x1080
    • RegistryDwords防止 GPU 省电模式 - 禁用可能在空闲期间导致 VNC 渲染问题的 PowerMizer 电源管理
    • TripleBuffer提高渲染稳定性 - 启用三重缓冲以获得更流畅的图形和减少显示损坏
    • OnDemandVBlankInterrupts更好的中断处理 - 为无头操作优化垂直消隐中断
    • AllowIndirectGLXProtocol减少潜在的 GL 冲突 - 防止容器化环境中的 OpenGL 冲突

容器化环境中的 GPU 选择说明

在使用 NVIDIA Container Toolkit 的容器环境中,通常不需要在 Xorg 配置文件中手动指定 BusID,因为:

  1. 容器级 GPU 隔离

    bash
    # 容器内只能看到分配给它的 GPU
    nvidia-smi -L
    # 输出示例:GPU 0: NVIDIA GeForce RTX 4090 (UUID: GPU-7a0896ba-54d3-2dc7-d793-83dfd98c7d13)
    
    # 主机层面显示所有 GPU(但容器无法访问)
    lspci | grep -i "VGA compatible controller: NVIDIA"
    # 输出示例:显示 8 个 GPU,但容器只能使用其中 1 个
  2. 自动 GPU 检测:NVIDIA 驱动具有内置智能,能够:

    • 自动扫描 PCI 总线寻找可用的 NVIDIA GPU
    • 当指定 Driver "nvidia" 时,自动选择第一个可用 GPU
    • 在容器环境中,"第一个可用 GPU" 就是 nvidia-smi -L 显示的唯一 GPU

何时需要指定 BusID(可选)

仅在以下情况下需要手动指定 BusID

  • 多 GPU 容器环境:容器分配了多个 GPU 且需要指定使用特定 GPU
  • 故障排除:自动检测失败时作为调试手段
  • 特殊配置要求:应用明确要求使用特定 GPU

找到正确的 GPU BusID(高级用法)

如果确实需要指定 BusID,请使用以下过程:

  1. 从 nvidia-smi 获取 Bus ID(主要方法)

    bash
    nvidia-smi -q | grep "Bus Id"

    示例输出:

    Bus Id                            : 00000000:41:00.0
  2. 使用 lspci 验证(确认方法)

    bash
    lspci | grep NVIDIA

    示例输出:

    41:00.0 VGA compatible controller: NVIDIA Corporation Device 2684 (rev a1)
    61:00.0 VGA compatible controller: NVIDIA Corporation Device 2684 (rev a1)
    81:00.0 VGA compatible controller: NVIDIA Corporation Device 2684 (rev a1)
  3. 转换为 Xorg BusID 格式

    1. 从 nvidia-smi 提取总线部分41:00.0(删除 00000000: 域前缀)

    2. 使用此一行命令直接转换(在 Bash 环境中可移植):

      bash
      # 将 PCI 地址从十六进制转换为十进制格式
      echo "41:00.0" | { IFS=':.' read -r bus dev func; printf "%d:%d:%d\n" "0x$bus" "0x$dev" "0x$func"; }
      # 输出:65:0:0
    3. 为 Xorg 格式化PCI:65:0:0

      其他示例:

      bash
      # 对于 lspci 输出中的其他 GPU 地址
      echo "a1:00.0" | { IFS=':.' read -r bus dev func; printf "%d:%d:%d\n" "0x$bus" "0x$dev" "0x$func"; }
      # 输出:161:0:0 → BusID "PCI:161:0:0"
      
      echo "c1:00.0" | { IFS=':.' read -r bus dev func; printf "%d:%d:%d\n" "0x$bus" "0x$dev" "0x$func"; }
      # 输出:193:0:0 → BusID "PCI:193:0:0"
  4. 取消注释并更新 xorg.conf 中的 BusID 行:

    bash
    # 将注释行改为:
    BusID "PCI:65:0:0"  # 使用您的转换值

Step 4 创建调试和监控脚本

在启动桌面服务之前,设置全面的监控和恢复工具。

创建 VNC 监控脚本

bash
cat > /usr/local/bin/vnc-monitor.sh << 'EOF'
#!/bin/bash

LOG_FILE="/tmp/vnc-monitor.log"
ENV_FILE="/tmp/vnc-desktop.env"
echo "=== VNC 监控器启动:$(date) ===" >> $LOG_FILE

while true; do
    # 重新加载环境(尤其是 IME/DBus 变量可能在启动后才写入)
    if [ -f "$ENV_FILE" ]; then
        # shellcheck disable=SC1090
        . "$ENV_FILE"
    fi
    export DISPLAY=${DISPLAY:-:0}

    echo "--- $(date) ---" >> $LOG_FILE
    
    # 检查进程是否正在运行
    if ! pgrep Xorg > /dev/null; then
        echo "❌ Xorg 未运行" >> $LOG_FILE
    else
        echo "✅ Xorg 正在运行 (PID: $(pgrep Xorg))" >> $LOG_FILE
    fi
    
    if ! pgrep x11vnc > /dev/null; then
        echo "❌ x11vnc 未运行" >> $LOG_FILE
    else
        echo "✅ x11vnc 正在运行 (PID: $(pgrep x11vnc))" >> $LOG_FILE
    fi
    
    if ! pgrep xfce4-session > /dev/null; then
        echo "❌ XFCE4 会话未运行" >> $LOG_FILE
    else
        echo "✅ XFCE4 会话正在运行" >> $LOG_FILE
    fi
    
    # 检查 IBus 状态
    if ! pgrep ibus-daemon > /dev/null; then
        echo "❌ IBus 守护进程未运行" >> $LOG_FILE
    else
        echo "✅ IBus 守护进程正在运行 (PID: $(pgrep ibus-daemon))" >> $LOG_FILE
    fi
    
    # 检查 fcitx5 状态
    if ! pgrep fcitx5 > /dev/null; then
        echo "❌ fcitx5 未运行" >> $LOG_FILE
    else
        echo "✅ fcitx5 正在运行 (PID: $(pgrep fcitx5))" >> $LOG_FILE
    fi
    
    # 检查 DBus 会话(仅在启用 IME 时有意义)
    if [ "${ENABLE_CHINESE_IME:-false}" = "true" ]; then
        if [ -n "${DBUS_SESSION_BUS_ADDRESS:-}" ]; then
            echo "✅ DBus 会话活跃:$DBUS_SESSION_BUS_ADDRESS" >> $LOG_FILE
        else
            echo "❌ DBus 会话未活跃(IME 可能无法工作)" >> $LOG_FILE
        fi
    else
        echo "ℹ️  未启用中文 IME:跳过 DBus 会话检查" >> $LOG_FILE
    fi
    
    # 检查 DPMS 状态
    DPMS_STATUS=$(timeout 5 xset q 2>/dev/null | grep -A3 "DPMS" || echo "DPMS 查询失败")
    echo "DPMS 状态:$DPMS_STATUS" >> $LOG_FILE
    
    # 检查 X 服务器响应性
    if timeout 5 xdpyinfo >/dev/null 2>&1; then
        echo "✅ X 服务器正在响应" >> $LOG_FILE
    else
        echo "❌ X 服务器未响应" >> $LOG_FILE
    fi
    
    # 内存和 CPU 使用情况
    echo "内存:$(free -h | grep Mem:)" >> $LOG_FILE
    echo "负载:$(uptime | awk -F'load average:' '{print $2}')" >> $LOG_FILE
    
    echo "" >> $LOG_FILE
    sleep 30  # 每 30 秒检查一次
done
EOF

chmod +x /usr/local/bin/vnc-monitor.sh

VNC 监控脚本说明

  • 监控架构:此脚本在后台持续运行,每 30 秒检查一次系统健康状况

  • 日志文件结构:在 /tmp/vnc-monitor.log 中使用带时间戳的条目,便于调试和问题跟踪

  • 进程监控逻辑

    • pgrep Xorg:通过搜索 Xorg 进程来检查 X 服务器是否正在运行
    • pgrep x11vnc:验证 VNC 服务器是否活跃并接受连接
    • pgrep xfce4-session:确认桌面环境会话管理器正在运行
    • pgrep ibus-daemon:监控中文输入法守护进程(如果启用)
    • pgrep fcitx5:检查替代中文输入法
  • 系统响应性测试

    • timeout 5 xdpyinfo:测试 X 服务器是否在 5 秒内响应查询,对于检测挂起的 X 会话至关重要
    • DPMS 状态检查:监控显示电源管理信号,确保电源管理不会干扰
  • 资源监控:跟踪内存使用情况和系统负载,以识别资源耗尽问题

  • DBus 会话验证:确保中文 IME 所需的会话总线处于活跃状态且可访问

创建防空闲脚本

bash
cat > /usr/local/bin/anti-idle.sh << 'EOF'
#!/bin/bash

export DISPLAY=:0

echo "设置积极的防空闲措施..."

# 禁用所有电源管理
xset s off                    # 禁用屏幕保护程序
xset s noblank               # 禁用屏幕变黑
xset -dpms                   # 禁用显示电源管理信号
xset s 0 0                   # 将屏幕保护程序超时设置为 0

# 禁用 X 服务器的内置屏幕保护程序
xset -b                      # 禁用响铃

echo "$(date):防空闲措施已激活" >> /tmp/anti-idle.log

# 设置虚假活动以防止空闲检测
# 这会每 5 分钟创建一次微小的鼠标移动
while true; do
    sleep 300  # 5 分钟
    
    # 检查 X 服务器是否仍然响应
    if timeout 3 xdpyinfo >/dev/null 2>&1; then
        # 发送微小的鼠标移动以防止空闲
        xdotool mousemove_relative 1 1
        xdotool mousemove_relative -- -1 -1
        echo "$(date):防空闲鼠标轻微移动已发送" >> /tmp/anti-idle.log
    else
        echo "$(date):X 服务器未响应 - 跳过防空闲" >> /tmp/anti-idle.log
    fi
done &
EOF

chmod +x /usr/local/bin/anti-idle.sh

防空闲脚本说明

  • 电源管理禁用策略

    • xset s off禁用 X11 屏幕保护程序 - 防止 X 服务器的内置屏幕保护程序激活,这可能导致 VNC 会话变得无响应
    • xset s noblank防止屏幕变黑 - 阻止显示器因不活动而变黑,对于无头设置至关重要,因为"变黑"可能会破坏 VNC 渲染
    • xset -dpms禁用 DPMS - 关闭显示电源管理信号,防止 GPU 进入可能导致显示问题的省电模式
    • xset s 0 0将屏幕保护程序超时设置为零 - 确保不管其他设置如何都不会激活屏幕保护程序
    • xset -b禁用系统响铃 - 防止可能干扰无头操作的音频响铃事件
  • 防空闲机制设计

    • 5 分钟间隔:在防止空闲检测和最小化系统影响之间取得平衡
    • 响应性检查:在发送鼠标事件之前使用 timeout 3 xdpyinfo 验证 X 服务器是否响应
    • 最小鼠标移动xdotool mousemove_relative 1 1 后跟 xdotool mousemove_relative -- -1 -1 创建返回原始位置的微小移动
    • 优雅的故障处理:如果 X 服务器不响应,跳过鼠标移动并记录问题,而不是挂起
  • 日志策略:所有防空闲活动都以时间戳记录到 /tmp/anti-idle.log,用于排除空闲相关问题

创建恢复脚本

bash
cat > /usr/local/bin/vnc-recovery.sh << 'EOF'
#!/bin/bash

ENV_FILE="/tmp/vnc-desktop.env"
if [ -f "$ENV_FILE" ]; then
    # shellcheck disable=SC1090
    . "$ENV_FILE"
fi
export DISPLAY=${DISPLAY:-:0}
export CHINESE_IME_BACKEND=${CHINESE_IME_BACKEND:-ibus}

echo "$(date):检查 VNC 健康状况..." >> /tmp/vnc-recovery.log

# 重启中文 IME 的函数
restart_ime() {
    echo "$(date):重启中文 IME..." >> /tmp/vnc-recovery.log
    
    # 终止现有的 IME 进程
    pkill ibus-daemon
    pkill fcitx5
    
    sleep 2
    
    # 如果需要,重启 DBus
    if [ -z "$DBUS_SESSION_BUS_ADDRESS" ]; then
        eval $(dbus-launch --sh-syntax)
        export DBUS_SESSION_BUS_ADDRESS
        echo "$(date):DBus 会话已重启" >> /tmp/vnc-recovery.log
    fi
    
    if [ "$ENABLE_CHINESE_IME" = "true" ]; then
        if [ "$CHINESE_IME_BACKEND" = "fcitx5" ]; then
            echo "$(date):使用 fcitx5 重启中文 IME..." >> /tmp/vnc-recovery.log

            export XDG_RUNTIME_DIR=${XDG_RUNTIME_DIR:-/tmp/xdg-runtime-root}
            mkdir -p "$XDG_RUNTIME_DIR"
            chmod 700 "$XDG_RUNTIME_DIR"

            # 预置 profile:默认启用拼音 + 英文键盘
            mkdir -p ~/.config/fcitx5
            cat > ~/.config/fcitx5/profile << 'FCITX_PROFILE_EOF'
[Groups/0]
Name=Default
Default Layout=us
DefaultIM=pinyin

[Groups/0/Items/0]
Name=pinyin
Layout=

[Groups/0/Items/1]
Name=keyboard-us
Layout=

[GroupOrder]
0=Default
FCITX_PROFILE_EOF
            chmod 600 ~/.config/fcitx5/profile

            pkill fcitx5 2>/dev/null || true
            nohup fcitx5 -d --replace >> /tmp/fcitx5.log 2>&1 &
            sleep 2
            echo "$(date):fcitx5 已重启" >> /tmp/vnc-recovery.log
        else
            # 默认 IBus
            if [ -f "/usr/local/bin/start-ibus.sh" ]; then
                /usr/local/bin/start-ibus.sh &
                echo "$(date):IBus 已重启" >> /tmp/vnc-recovery.log
            fi
        fi
    fi
    
    echo "$(date):中文 IME 重启完成" >> /tmp/vnc-recovery.log
}

# 重启所有组件的函数
restart_vnc_stack() {
    echo "$(date):重启 VNC 堆栈..." >> /tmp/vnc-recovery.log
    
    # 终止现有进程
    pkill x11vnc
    pkill startxfce4
    pkill xfce4-session
    pkill xfce4-panel
    pkill xfdesktop
    pkill xfwm4
    pkill xfconfd
    pkill -f '[x]fce4-screensaver'
    pkill Xorg
    pkill ibus-daemon
    pkill fcitx5
    pkill -f "anti-idle.sh"
    
    sleep 3
    
    # 清理可能阻止 Xorg 重启的锁文件
    rm -f /tmp/.X0-lock /tmp/.X11-unix/X0

    # 重启 Xorg
    nohup Xorg :0 -config /etc/X11/xorg.conf >/tmp/xorg-stdout.log 2>&1 &
    sleep 5
    
    # 重启防空闲措施
    nohup /usr/local/bin/anti-idle.sh >/dev/null 2>&1 &
    
    # 如果启用,重启中文 IME
    if [ "$ENABLE_CHINESE_IME" = "true" ]; then
        restart_ime
        sleep 2
    fi
    
    # 使用生产就绪设置重启 x11vnc
    x11vnc -display :0 -localhost -xkb -noxrecord -noxfixes -noxdamage -rfbauth ~/.vnc/passwd -forever -norepeat -nonap -wait 20 -defer 1 -speeds modem -threads -bg -o /tmp/x11vnc.log
    
    sleep 3
    
    # 如果启用,使用 IME 环境重启 XFCE4
    if [ "$ENABLE_CHINESE_IME" = "true" ]; then
        if [ "$CHINESE_IME_BACKEND" = "fcitx5" ]; then
            export GTK_IM_MODULE=fcitx
            export XMODIFIERS=@im=fcitx
            export QT_IM_MODULE=fcitx
            export SDL_IM_MODULE=fcitx
            export XDG_RUNTIME_DIR=${XDG_RUNTIME_DIR:-/tmp/xdg-runtime-root}
        else
            export GTK_IM_MODULE=ibus
            export XMODIFIERS=@im=ibus
            export QT_IM_MODULE=ibus
        fi
    fi
    nohup startxfce4 >/tmp/xfce4.log 2>&1 &
    
    echo "$(date):VNC 堆栈重启完成" >> /tmp/vnc-recovery.log
}

# 检查 X 服务器是否响应
if ! timeout 5 xdpyinfo >/dev/null 2>&1; then
    echo "$(date):X 服务器未响应 - 触发重启" >> /tmp/vnc-recovery.log
    restart_vnc_stack
    exit 0
fi

# 检查 x11vnc 是否正在运行并响应
if ! pgrep x11vnc > /dev/null; then
    echo "$(date):x11vnc 未运行 - 触发重启" >> /tmp/vnc-recovery.log
    restart_vnc_stack
    exit 0
fi

# 检查是否可以连接到 VNC 端口
if ! netstat -tuln | grep :5900 > /dev/null; then
    echo "$(date):VNC 端口未监听 - 触发重启" >> /tmp/vnc-recovery.log
    restart_vnc_stack
    exit 0
fi

# 如果启用,检查中文 IME
if [ "$ENABLE_CHINESE_IME" = "true" ]; then
    if [ "$CHINESE_IME_BACKEND" = "fcitx5" ]; then
        if ! pgrep fcitx5 > /dev/null; then
            echo "$(date):fcitx5 未运行 - 触发 IME 重启" >> /tmp/vnc-recovery.log
            restart_ime
        fi
    else
        if ! pgrep ibus-daemon > /dev/null; then
            echo "$(date):IBus 未运行 - 触发 IME 重启" >> /tmp/vnc-recovery.log
            restart_ime
        fi
    fi
    
    # 检查 IME 的 DBus 会话
    if [ -z "$DBUS_SESSION_BUS_ADDRESS" ]; then
        echo "$(date):IME 缺少 DBus 会话 - 触发 IME 重启" >> /tmp/vnc-recovery.log
        restart_ime
    fi
fi

echo "$(date):所有检查通过" >> /tmp/vnc-recovery.log
EOF

chmod +x /usr/local/bin/vnc-recovery.sh

创建自动恢复循环脚本(替代 cron)

在容器环境中通常没有 systemd,并且像 cron 这类服务不会自动启动(即使您安装了它)。为了获得同样的“每 2 分钟自愈一次”的效果,我们使用一个轻量的循环脚本来周期性调用 vnc-recovery.sh

bash
cat > /usr/local/bin/vnc-recovery-loop.sh << 'EOF'
#!/bin/bash

export DISPLAY=:0

# 默认每 120 秒运行一次;可通过环境变量覆盖
INTERVAL_SECONDS="${VNC_RECOVERY_INTERVAL_SECONDS:-120}"

echo "=== VNC 恢复循环启动:$(date) (interval=${INTERVAL_SECONDS}s) ===" >> /tmp/vnc-recovery.log

while true; do
    /usr/local/bin/vnc-recovery.sh
    sleep "$INTERVAL_SECONDS"
done
EOF

chmod +x /usr/local/bin/vnc-recovery-loop.sh

恢复脚本说明

  • 多层恢复架构

    • restart_ime()中文 IME 专用恢复 - 独立处理 IBus 和 fcitx5 故障,确保即使其他服务正常工作,中文输入也能保持功能
    • restart_vnc_stack()完整系统恢复 - 当多个服务失败或变得无响应时执行所有组件的完全重启
  • 恢复过程逻辑

    • 优雅终止:使用 pkill 而不是 killall -9,允许进程正确清理
    • 启动顺序:遵循正确的顺序(Xorg → 防空闲 → IME → VNC → XFCE4),并适当延迟以进行初始化
    • 环境保持:在重启过程中维护 IME 环境变量(根据 CHINESE_IME_BACKEND 选择 IBus 或 fcitx5),以实现无缝的中文输入集成
  • 增强的 x11vnc 启动参数

    • -display :0目标显示 - 连接到主 X 显示
    • -xkb键盘处理 - 确保正确的键盘布局和输入法支持
    • -noxrecord禁用 X 记录扩展 - 防止可能导致输入延迟或崩溃的冲突
    • -noxfixes禁用 X 修复扩展 - 避免与无头设置的潜在兼容性问题
    • -noxdamage禁用 X 损坏扩展 - 减少可能导致显示损坏的渲染冲突
    • -rfbauth ~/.vnc/passwd密码认证 - 使用存储的密码强制安全访问
    • -forever持久操作 - 在客户端断开连接后保持服务器运行
    • -norepeat禁用按键重复 - 防止可能通过 VNC 导致输入问题的按键重复事件
    • -nonap禁用休眠 - 防止服务器在低活动期间"休眠",对于保持 VNC 响应性和防止空闲无响应至关重要
    • -wait 20客户端检测超时 - 等待 20ms 进行客户端连接,优化响应性
    • -defer 1屏幕轮询延迟 - 屏幕轮询之间 1ms 延迟,平衡性能和资源使用
    • -speeds modem保守速度设置 - 使用适合各种网络条件的带宽保守设置
    • -threads多线程 - 启用线程操作以获得更好的性能和响应性
    • -bg后台操作 - 作为守护进程运行
    • -o /tmp/x11vnc.log日志输出 - 捕获所有 VNC 服务器消息以进行调试
  • 健康检查触发器:脚本在以下情况下激活恢复:

    • X 服务器变得无响应(xdpyinfo 测试失败)
    • VNC 服务器进程死亡
    • VNC 端口 5900 停止监听
    • 中文 IME 进程失败(启用时)
    • DBus 会话变得不可用(启用 IME 时)

创建完整启动脚本

bash
cat > /usr/local/bin/start-vnc-desktop.sh << 'EOF'
#!/bin/bash

export DISPLAY=:0

# 设置为 "true" 以启用中文 IME 支持
# 中文输入默认开启;如不需要可在运行前设置 ENABLE_CHINESE_IME=false
export ENABLE_CHINESE_IME=${ENABLE_CHINESE_IME:-true}
# 中文 IME 后端:ibus(默认)或 fcitx5
export CHINESE_IME_BACKEND=${CHINESE_IME_BACKEND:-ibus}
# 设置为 "false" 可禁用自动恢复循环
export ENABLE_AUTO_RECOVERY=${ENABLE_AUTO_RECOVERY:-true}

ENV_FILE="/tmp/vnc-desktop.env"

echo "启动带调试功能的增强 VNC 桌面..."
if [ "$ENABLE_CHINESE_IME" = "true" ]; then
    echo "中文 IME 支持已启用 (backend=${CHINESE_IME_BACKEND})"
fi

# 写入共享环境文件,供监控/恢复脚本读取
cat > "$ENV_FILE" << ENV_EOF
export DISPLAY=:0
export ENABLE_CHINESE_IME=$ENABLE_CHINESE_IME
export CHINESE_IME_BACKEND=$CHINESE_IME_BACKEND
export ENABLE_AUTO_RECOVERY=$ENABLE_AUTO_RECOVERY
ENV_EOF
chmod 600 "$ENV_FILE"

# 启动系统 DBus(可选但推荐):减少 XFCE4 在容器中的告警噪音
if [ ! -S /run/dbus/system_bus_socket ]; then
    mkdir -p /run/dbus
    dbus-daemon --system --fork --nopidfile --nosyslog
fi

# 终止任何现有进程
pkill x11vnc 2>/dev/null
pkill startxfce4 2>/dev/null  
pkill xfce4-session 2>/dev/null
pkill xfce4-panel 2>/dev/null
pkill xfdesktop 2>/dev/null
pkill xfwm4 2>/dev/null
pkill xfconfd 2>/dev/null
pkill Xorg 2>/dev/null
pkill ibus-daemon 2>/dev/null
pkill fcitx5 2>/dev/null
pkill -f "anti-idle.sh" 2>/dev/null
pkill -f "vnc-monitor.sh" 2>/dev/null
pkill -f "vnc-recovery-loop.sh" 2>/dev/null
sleep 3

# 清理可能阻止 Xorg 重启的锁文件
rm -f /tmp/.X0-lock /tmp/.X11-unix/X0

# 启动 Xorg
nohup Xorg :0 -config /etc/X11/xorg.conf >/tmp/xorg-stdout.log 2>&1 &
sleep 5

# 启动监控
nohup /usr/local/bin/vnc-monitor.sh >/dev/null 2>&1 &

# 启动防空闲措施
nohup /usr/local/bin/anti-idle.sh >/dev/null 2>&1 &

# 如果启用,启动中文 IME
if [ "$ENABLE_CHINESE_IME" = "true" ]; then
    echo "设置中文 IME..."
    
    # 如果需要,启动 DBus 会话
    if [ -z "$DBUS_SESSION_BUS_ADDRESS" ]; then
        eval $(dbus-launch --sh-syntax)
        export DBUS_SESSION_BUS_ADDRESS
    fi

    if [ "$CHINESE_IME_BACKEND" = "fcitx5" ]; then
        echo "使用 fcitx5 作为中文输入后端..."

        # 为 fcitx5 准备运行目录(部分组件会依赖 XDG_RUNTIME_DIR)
        export XDG_RUNTIME_DIR=${XDG_RUNTIME_DIR:-/tmp/xdg-runtime-root}
        mkdir -p "$XDG_RUNTIME_DIR"
        chmod 700 "$XDG_RUNTIME_DIR"

        # 设置 fcitx5 环境变量(务必在启动桌面前设置,保证应用能继承)
        export GTK_IM_MODULE=fcitx
        export XMODIFIERS=@im=fcitx
        export QT_IM_MODULE=fcitx
        export SDL_IM_MODULE=fcitx

        # 预置 fcitx5 profile:默认启用拼音(pinyin)+ 英文键盘(keyboard-us)
        mkdir -p ~/.config/fcitx5
        cat > ~/.config/fcitx5/profile << 'FCITX_PROFILE_EOF'
[Groups/0]
Name=Default
Default Layout=us
DefaultIM=pinyin

[Groups/0/Items/0]
Name=pinyin
Layout=

[Groups/0/Items/1]
Name=keyboard-us
Layout=

[GroupOrder]
0=Default
FCITX_PROFILE_EOF
        chmod 600 ~/.config/fcitx5/profile

        # 停止 IBus,避免输入法框架冲突
        pkill ibus-daemon 2>/dev/null || true

        # 启动 fcitx5(日志写入 /tmp/fcitx5.log)
        pkill fcitx5 2>/dev/null || true
        nohup fcitx5 -d --replace >> /tmp/fcitx5.log 2>&1 &
        sleep 2

        # 将 IME/DBus 变量写入共享环境文件,便于恢复脚本在“非交互环境”下读取
        cat >> "$ENV_FILE" << ENV_IME_EOF
export DBUS_SESSION_BUS_ADDRESS='$DBUS_SESSION_BUS_ADDRESS'
export XDG_RUNTIME_DIR='$XDG_RUNTIME_DIR'
export GTK_IM_MODULE=fcitx
export XMODIFIERS=@im=fcitx
export QT_IM_MODULE=fcitx
export SDL_IM_MODULE=fcitx
ENV_IME_EOF
    else
        echo "使用 IBus 作为中文输入后端..."

        # 如果不存在,创建 IBus 启动脚本
        if [ ! -f "/usr/local/bin/start-ibus.sh" ]; then
            /usr/local/bin/create-ibus-script.sh
        fi

        # 启动 IBus
        /usr/local/bin/start-ibus.sh &
        sleep 3

        # 设置 IME 环境变量
        export GTK_IM_MODULE=ibus
        export XMODIFIERS=@im=ibus
        export QT_IM_MODULE=ibus

        # 将 IME/DBus 变量写入共享环境文件,便于恢复脚本在“非交互环境”下读取
        cat >> "$ENV_FILE" << ENV_IME_EOF
export DBUS_SESSION_BUS_ADDRESS='$DBUS_SESSION_BUS_ADDRESS'
export GTK_IM_MODULE=ibus
export XMODIFIERS=@im=ibus
export QT_IM_MODULE=ibus
ENV_IME_EOF
    fi

    echo "中文 IME 设置完成 (backend=${CHINESE_IME_BACKEND})"
fi

# 使用生产就绪设置启动 x11vnc
x11vnc -display :0 -localhost -xkb -noxrecord -noxfixes -noxdamage -rfbauth ~/.vnc/passwd -forever -norepeat -nonap -wait 20 -defer 1 -speeds modem -threads -bg -o /tmp/x11vnc.log

sleep 3

# 启动 XFCE4
nohup startxfce4 >/tmp/xfce4.log 2>&1 &

# 禁用/退出屏幕保护(避免“画面显示但无法点击/键盘”)
if command -v xfce4-screensaver-command >/dev/null 2>&1; then
    xfce4-screensaver-command --deactivate 2>/dev/null || true
    xfce4-screensaver-command --exit 2>/dev/null || true
fi
pkill -f '[x]fce4-screensaver' 2>/dev/null || true

# 启动自动恢复循环(每 2 分钟)
if [ "$ENABLE_AUTO_RECOVERY" = "true" ]; then
    nohup /usr/local/bin/vnc-recovery-loop.sh >/dev/null 2>&1 &
fi

echo "启用调试功能的 VNC 桌面启动完成"
echo "监控日志:tail -f /tmp/vnc-monitor.log"
echo "防空闲日志:tail -f /tmp/anti-idle.log"
echo "VNC 日志:tail -f /tmp/x11vnc.log"
echo "恢复日志:tail -f /tmp/vnc-recovery.log"
echo "XFCE4 日志:tail -f /tmp/xfce4.log"
if [ "$ENABLE_CHINESE_IME" = "true" ]; then
    if [ "$CHINESE_IME_BACKEND" = "fcitx5" ]; then
        echo "中文 IME 日志:tail -f /tmp/fcitx5.log"
    else
        echo "中文 IME 日志:tail -f /tmp/ibus.log"
    fi
fi
EOF

chmod +x /usr/local/bin/start-vnc-desktop.sh

启动脚本说明

  • 环境变量控制

    • ENABLE_CHINESE_IME=${ENABLE_CHINESE_IME:-true}默认行为 - 默认启用中文 IME(含候选框)。如不需要,可在运行前显式禁用:ENABLE_CHINESE_IME=false /usr/local/bin/start-vnc-desktop.sh
    • CHINESE_IME_BACKEND=${CHINESE_IME_BACKEND:-ibus}后端选择 - ibus(默认)或 fcitx5。例如:CHINESE_IME_BACKEND=fcitx5 /usr/local/bin/start-vnc-desktop.sh
  • 启动序列优化

    • 进程清理:使用 pkill 优雅终止,然后 3 秒延迟,确保在启动新实例之前干净地关闭进程
    • Xorg 初始化:5 秒延迟允许 Xorg 完全初始化 GPU 连接和 X 服务器,然后再启动依赖服务
    • 服务分层:监控(vnc-monitor.sh)和防空闲(anti-idle.sh)在 VNC 之前启动,确保它们在 VNC 变为活跃时准备就绪
    • 中文 IME 集成:支持 ibus(默认)与 fcitx5 两种后端,并进行 DBus 会话管理(也可通过 ENABLE_CHINESE_IME=false 关闭)
    • 环境传播:在启动 XFCE4 之前设置 IME 环境变量,以实现无缝的中文输入集成
  • 中文 IME 启动逻辑

    • DBus 会话管理:如果 DBUS_SESSION_BUS_ADDRESS 未设置,使用 dbus-launch --sh-syntax 创建 DBus 会话,然后导出地址以进行适当的环境变量管理
    • 后端:IBus(默认)
      • 脚本自动创建:如果 IBus 启动脚本缺失,调用 create-ibus-script.sh
      • 守护进程启动:启动 start-ibus.sh 并等待初始化完成,然后设置 GTK_IM_MODULE=ibusXMODIFIERS=@im=ibusQT_IM_MODULE=ibus
    • 后端:fcitx5
      • 运行目录:准备 XDG_RUNTIME_DIR(容器/无 systemd 环境下部分组件依赖)
      • profile 预置:写入 ~/.config/fcitx5/profile(默认 pinyin + keyboard-us
      • 守护进程启动:停止 IBus 以避免冲突,然后启动 fcitx5 -d --replace(日志写入 /tmp/fcitx5.log),并设置 GTK_IM_MODULE/QT_IM_MODULE/XMODIFIERS/SDL_IM_MODULE
  • 增强的 x11vnc 配置(与恢复脚本中相同的详细参数):

    • 使用与恢复脚本相同的优化标志,以确保一致的行为和最大稳定性
    • 后台操作-bg 标志确保脚本在 VNC 运行后继续执行以启动 XFCE4
    • 全面日志记录-o /tmp/x11vnc.log 捕获所有 VNC 服务器事件以进行调试

创建中文输入法脚本

为中文输入法支持创建必要的脚本,包括调试功能。

创建带调试功能的 IBus 设置脚本

bash
cat > /usr/local/bin/start-ibus.sh << 'EOF'
#!/bin/bash

LOG_FILE="/tmp/ibus.log"
echo "=== IBus 设置开始:$(date) ===" >> $LOG_FILE

# 设置显示
export DISPLAY=:0

# 手动启动 DBus 会话(因为 systemd 不可用)
if [ -z "$DBUS_SESSION_BUS_ADDRESS" ]; then
    echo "启动 DBus 会话..." >> $LOG_FILE
    eval $(dbus-launch --sh-syntax)
    export DBUS_SESSION_BUS_ADDRESS
    echo "DBus 会话已启动:$DBUS_SESSION_BUS_ADDRESS" >> $LOG_FILE
else
    echo "DBus 会话已激活:$DBUS_SESSION_BUS_ADDRESS" >> $LOG_FILE
fi

# 设置 IBus 环境变量
export GTK_IM_MODULE=ibus
export XMODIFIERS=@im=ibus
export QT_IM_MODULE=ibus

echo "IBus 环境变量已设置" >> $LOG_FILE

# 启动 IBus 守护进程
# 说明:候选词窗口/状态栏等 UI 由 ibus 面板进程(通常是 ibus-ui-gtk3)提供;
# 在 VNC 桌面场景下**不要**使用 --panel=disable,否则会出现“能打中文但不显示候选框”的问题。
ibus-daemon -drx >> $LOG_FILE 2>&1 &
IBUS_PID=$!

# 等待 IBus 初始化
sleep 3

# 验证 IBus 是否正在运行
if pgrep ibus-daemon > /dev/null; then
    echo "✅ IBus 守护进程启动成功 (PID: $(pgrep ibus-daemon))" >> $LOG_FILE
else
    echo "❌ IBus 守护进程启动失败" >> $LOG_FILE
    exit 1
fi

# 配置默认输入法
ibus engine pinyin 2>/dev/null || true
echo "默认输入法已配置" >> $LOG_FILE

echo "IBus 设置完成。使用 Ctrl+Space 切换输入法。" >> $LOG_FILE
echo "=== IBus 设置完成:$(date) ===" >> $LOG_FILE
EOF

chmod +x /usr/local/bin/start-ibus.sh

创建 IBus 脚本生成器

bash
cat > /usr/local/bin/create-ibus-script.sh << 'EOF'
#!/bin/bash

echo "创建 IBus 启动脚本..."

# 如果 start-ibus.sh 不存在,此脚本由主启动脚本调用
if [ ! -f "/usr/local/bin/start-ibus.sh" ]; then
    echo "未找到 IBus 脚本,正在创建..."
    cat > /usr/local/bin/start-ibus.sh << 'INNER_EOF'
#!/bin/bash
export DISPLAY=:0
if [ -z "$DBUS_SESSION_BUS_ADDRESS" ]; then
    eval $(dbus-launch --sh-syntax)
    export DBUS_SESSION_BUS_ADDRESS
fi
export GTK_IM_MODULE=ibus
export XMODIFIERS=@im=ibus
export QT_IM_MODULE=ibus
ibus-daemon -drx &
sleep 3
ibus engine pinyin 2>/dev/null || true
echo "IBus 设置完成。使用 Ctrl+Space 切换输入法。"
INNER_EOF
    chmod +x /usr/local/bin/start-ibus.sh
    echo "IBus 脚本创建成功"
else
    echo "IBus 脚本已存在"
fi
EOF

chmod +x /usr/local/bin/create-ibus-script.sh

中文输入法脚本说明

  • 增强的 IBus 日志架构

    • LOG_FILE="/tmp/ibus.log"专用 IME 日志 - IBus 特定活动的独立日志文件,使中文输入故障排除独立于通用 VNC 调试
    • 时间戳条目:每个日志条目都包含日期/时间,便于与其他系统日志和问题跟踪进行关联
  • 带调试的 DBus 会话管理

    • 条件 DBus 启动:在创建新会话之前检查 DBUS_SESSION_BUS_ADDRESS,防止与现有会话冲突
    • eval $(dbus-launch --sh-syntax)正确的环境导出 - 使用 --sh-syntax 生成 shell 兼容的导出语句
    • 地址日志记录:记录 DBus 会话地址以排除连接问题
  • IBus 守护进程启动

    • ibus-daemon -drx推荐(VNC 桌面可见候选框)
      • -d守护进程模式 - 将 IBus 作为后台服务运行
      • -r替换现有 - 替换任何现有的 IBus 守护进程以确保干净启动
      • -xX11 集成 - 启用 X11 输入法集成

    提示

    如果您在极端精简/纯无头环境里运行(没有任何桌面 UI),面板进程可能无法启动;此时可改用 ibus-daemon -drx --panel=disable 以避免报错,但候选词窗口也会随之不可用

  • 脚本生成器功能

    • 后备创建:如果主 IBus 脚本缺失,create-ibus-script.sh 自动创建简化版本
    • 容器重启弹性:确保在容器重启后中文输入法脚本可用

Step 5 设置生产就绪配置的 VNC

配置 x11vnc 以进行安全远程访问,并使用生产就绪设置来防止空闲问题。

创建 VNC 密码

bash
x11vnc -storepasswd

配置 XFCE4 会话设置

bash
# 创建 XFCE4 配置以防止会话超时
mkdir -p ~/.config/xfce4/xfconf/xfce-perchannel-xml

cat > ~/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-session.xml << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<channel name="xfce4-session" version="1.0">
  <property name="general" type="empty">
    <property name="SaveOnExit" type="bool" value="false"/>
    <property name="SessionName" type="string" value="Default"/>
    <property name="AutoSave" type="bool" value="false"/>
    <property name="PromptOnLogout" type="bool" value="false"/>
    <property name="LockCommand" type="string" value=""/>
  </property>
  <property name="shutdown" type="empty">
    <property name="LockScreen" type="bool" value="false"/>
  </property>
</channel>
EOF

# 禁用电源管理器
cat > ~/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-power-manager.xml << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<channel name="xfce4-power-manager" version="1.0">
  <property name="xfce4-power-manager" type="empty">
    <property name="power-button-action" type="uint" value="0"/>
    <property name="inactivity-sleep-mode-on-ac" type="uint" value="0"/>
  </property>
</channel>
EOF

(强烈推荐)禁用屏幕保护/锁屏(避免“画面显示但无法点击/键盘”)

在容器化 VNC 桌面里,xfce4-screensaver 很容易出现“黑屏/遮罩仍在,但画面看起来还在”的情况,表现为:

  • 桌面能显示
  • 鼠标/键盘输入完全无效

因此建议直接禁用其自启动

bash
mkdir -p ~/.config/autostart

cat > ~/.config/autostart/xfce4-screensaver.desktop << 'EOF'
[Desktop Entry]
Type=Application
Name=xfce4-screensaver (disabled for headless VNC)
Hidden=true
X-GNOME-Autostart-enabled=false
EOF

提示

如果您已经遇到“画面显示但无法点击/键盘”,可通过 SSH 在容器内执行以下命令立即解除:

bash
export DISPLAY=:0
xfce4-screensaver-command --deactivate || true
xfce4-screensaver-command --exit || true
pkill -f '[x]fce4-screensaver' 2>/dev/null || true

XFCE4 会话设置说明

  • XFCE4 会话配置优化

    • SaveOnExit=false防止会话保存 - 禁用退出时自动保存会话状态,这可能在无头环境中引起问题,因为适当的退出序列不会发生
    • AutoSave=false禁用自动会话保存 - 防止 XFCE4 在运行时自动保存会话状态,这可能干扰脚本化重启
    • PromptOnLogout=false消除退出提示 - 确保干净关机而无需用户交互提示,这些提示在无头环境中会挂起
    • LockScreen=false防止自动屏幕锁定 - 确保桌面永远不会自动锁定,这会使 VNC 会话无法访问
  • 无头操作的电源管理器配置

    • 按钮动作设置为 0:所有电源按钮(电源、睡眠、休眠)都被禁用(value="0"),以防止在容器化环境中意外的系统状态更改
    • 睡眠模式禁用:电池和 AC 睡眠模式都设置为 0,确保系统永远不会尝试睡眠

Step 6 将 Google Chrome 配置为默认网页浏览器

将 Google Chrome 设置为默认浏览器,并确保它在 root 用户上下文中正确启动。

将 Chrome 设置为默认浏览器

bash
xdg-settings set default-web-browser google-chrome.desktop

Step 7 启动生产就绪的 VNC 桌面系统

使用全面的启动脚本启动一切,并启用调试功能:

bash
# 直接启动(默认启用中文输入法;后端默认 IBus)
/usr/local/bin/start-vnc-desktop.sh

# 切换到 fcitx5 后端(可选):
# CHINESE_IME_BACKEND=fcitx5 /usr/local/bin/start-vnc-desktop.sh

# 如不需要中文输入,可显式禁用:
# ENABLE_CHINESE_IME=false /usr/local/bin/start-vnc-desktop.sh

警告

重新运行 start-vnc-desktop.sh 的副作用(重要)

该脚本的设计目标是“稳定地恢复/切换桌面栈”,因此 每次运行都会执行一次完整的桌面重启

  • 会断开 VNC 连接x11vncXorg 会被停止并重启,VNC 客户端需要稍后重新连接。
  • 会结束所有 GUI 进程xfce4-session/xfce4-panel/xfdesktop/xfwm4 等会被 pkill 终止;所有在桌面里打开的应用(包括编辑器/浏览器/终端)都会被关闭,未保存内容会丢失
  • 可能影响在桌面终端里启动的任务:如果您在 xfce4-terminal 里跑了长任务,终端被关闭时任务可能随会话一起退出;建议用独立 SSH 会话运行,或使用 nohup/后台方式。
  • 会重建会话环境/tmp/vnc-desktop.env 会被覆盖,DBus 会话可能重建;CHINESE_IME_BACKEND 的切换也因此能被新启动的桌面与应用完整继承。

(推荐)验证 GPU 渲染(OpenGL / Vulkan)

如果您计划运行 3D GUI 应用(例如 NVIDIA Isaac Sim / OmniGibson),建议同时验证 OpenGLVulkan 是否都在使用 NVIDIA GPU(而不是 CPU 软件渲染 llvmpipe)。

bash
export DISPLAY=:0

# 1) OpenGL(桌面渲染)
glxinfo -B | grep -E "OpenGL vendor|OpenGL renderer"

# 2) Vulkan(Isaac Sim/OmniGibson 等常用)
vulkaninfo --summary

预期现象:

  • glxinfoOpenGL renderer string 应显示类似 NVIDIA GeForce RTX 4090/...
  • vulkaninfo --summaryDevices 段落中应看到 GPU0: deviceName = NVIDIA ...deviceType = PHYSICAL_DEVICE_TYPE_DISCRETE_GPU

vulkaninfo 只识别到 llvmpipe,请参考 开发机常见问题排查指南 中的 “Vulkan 找不到 GPU(仅识别到 llvmpipe / CPU)”。

Step 8:连接到 VNC

您需要通过 SSH 端口转发,将 VNC 端口转发到本地(假设为 5900 端口),然后使用 VNC 客户端连接到 VNC 端口。

  1. 本地执行 SSH 端口转发命令(以下以 42832 为例,请替换为您的 SSH 端口),将 VNC 端口转发到本地 5900 端口:

    bash
    ssh -N -f -L 5900:localhost:5900 -p 42832 root@guangdong-b-is.cloud.infini-ai.com
  2. 使用 VNC 客户端连接(MacOS 可使用自带的 VNC Viewer 连接, Windows 可使用第三方 VNC 客户端,如:RealVNC、TightVNC 等)。

    • 地址:localhost:5900(因为端口已通过 SSH 转发到本地)
    • 输入在 Step 5 中创建的密码
  3. 验证功能。

    • XFCE4 桌面应该出现

    • Google Chrome 应该能够启动(root 环境通常需要 --no-sandbox;如果点击面板“网页浏览器”图标提示 failed to execute default Web browser / input-output error,见下文“修复面板网页浏览器图标”一节)

    • 如果启用,中文输入法应该可以工作

修复面板“网页浏览器”图标无法启动 Chrome(input/output error)

在容器化的 VNC 桌面里,XFCE4 往往以 root 用户运行。此时如果直接启动 Chrome(未附加任何额外参数),Chrome 会因为 Linux 沙箱限制而拒绝启动,典型报错为:

Running as root without --no-sandbox is not supported.

而面板图标通常使用 exo-open 启动浏览器(例如 exo-open --launch WebBrowser %u)。exo-open 走的是 XFCE 的 “helper/首选应用” 机制,它在失败时经常只弹出一个比较泛的提示(例如 failed to execute default Web browser / input-output error),但根因仍是上面的沙箱限制。

方法 A:直接改面板图标命令(最直观)

  1. 右键单击 XFCE4 面板上的“网页浏览器”图标,选择“属性”
  2. 将命令更改为:/usr/bin/google-chrome-stable --no-sandbox
  3. 保存更改

方法 B:命令行全局修复(推荐,不用改图标)

exo-open --launch WebBrowser %u 会读取 ~/.config/xfce4/helpers.rc 中的 WebBrowser= 配置并执行它,因此可以把 WebBrowser 指向一个 wrapper,让它自动追加 --no-sandbox

bash
# 1) 创建 wrapper:统一追加 --no-sandbox
cat > /usr/local/bin/google-chrome-no-sandbox <<'EOF'
#!/bin/sh
if [ "$(id -u)" = "0" ]; then
  exec /usr/bin/google-chrome-stable --no-sandbox "$@"
else
  exec /usr/bin/google-chrome-stable "$@"
fi
EOF
chmod +x /usr/local/bin/google-chrome-no-sandbox

# 2) 配置 XFCE 的 WebBrowser helper(exo-open 会读取这里)
mkdir -p ~/.config/xfce4
cat > ~/.config/xfce4/helpers.rc <<'EOF'
WebBrowser=/usr/local/bin/google-chrome-no-sandbox
EOF

# 3) 可选:重启面板让图标立即生效
xfce4-panel -r 2>/dev/null || true

警告

--no-sandbox 会禁用浏览器沙箱,安全性会降低。该做法适用于隔离的容器 VNC 桌面(例如仅用于开发/下载依赖),不建议用它浏览不可信网站或打开不可信文件。更安全的方式是创建非 root 用户并以非 root 运行桌面/浏览器(在受管容器环境中不一定总能做到)。

Chrome DevTools Protocol (CDP) 远程调试与自动化(可选)

Chrome DevTools Protocol(CDP)允许您通过 HTTP/WebSocket 远程控制 Chrome:打开页面、执行脚本、抓取 DOM、做自动化测试等。在“仅 SSH 可达”的容器开发机环境里,CDP + SSH 端口转发是一个非常实用的远程自动化方案。

使用场景

  • 远程自动化:在开发机容器里运行爬虫/回归测试,但在本地通过 CDP 观察与调试
  • 无可视化也能跑:使用 headless Chrome 时不会出现任何 VNC 窗口,但依旧可完整访问网页
  • DevTools 远程调试:把 DevTools UI 跑在本地浏览器里,调试远端的页面

开始之前

  • 安全默认:CDP 端口请只绑定到 127.0.0.1,并通过 SSH 转发访问(不要监听 0.0.0.0)。
  • root 环境:在本教程的桌面环境中通常以 root 运行,因此启动 Chrome 时建议带 --no-sandbox(原因见上文)。
  • 推荐 tmux:CDP 服务是长驻进程,建议放在 tmux 会话中运行,避免 SSH 断开后退出。

Step 0 在远端启动一个 CDP Chrome(Headless)

在远端开发机里执行(推荐在 tmux 中运行):

bash
# 进入 tmux(如果已在 tmux 里,可跳过)
tmux new -s chrome-cdp-9222

PORT=9222
INFO=/tmp/chrome-cdp-$PORT.info
LOG=/tmp/chrome-cdp-$PORT.log

# 使用独立 profile,避免与桌面 Chrome/profile 冲突
DIR=$(mktemp -d /tmp/chrome-cdp-profile.$PORT.XXXXXX)

# 记录关键信息,便于后续清理/排错
printf 'port=%s\nprofile_dir=%s\nlog=%s\n' "$PORT" "$DIR" "$LOG" | tee "$INFO"

# 启动 headless Chrome,并把 CDP 端口绑定到 localhost
google-chrome-stable \
  --headless=new \
  --no-sandbox \
  --disable-gpu \
  --disable-dev-shm-usage \
  --no-first-run \
  --no-default-browser-check \
  --remote-debugging-address=127.0.0.1 \
  --remote-debugging-port="$PORT" \
  --user-data-dir="$DIR" \
  about:blank \
  2>&1 | tee -a "$LOG"

注意

Headless Chrome 不会在 VNC 桌面里出现窗口,这是预期行为;CDP 是通过端口提供远程控制能力。

Step 1 将 CDP 端口转发到本地

在本地执行(以下仍以 42832 为例):

bash
ssh -N -L 9222:localhost:9222 -p 42832 root@guangdong-b-is.cloud.infini-ai.com

然后在本地浏览器打开 http://127.0.0.1:9222/json/version,应能看到类似 Browser: Chrome/... 的 JSON 输出。

注意

上面的 ssh -N -L ... 会保持前台运行以维持隧道连接;请保持该终端窗口打开。若希望后台运行,可加 -f(例如 ssh -N -f -L ...)。

Step 2 用 CDP 让浏览器访问一个网页(验证“可操作”)

Chrome 新版本(例如 144)对 json/newjson/close 这类“有副作用”的接口要求使用 PUT。如果您用 GET 访问出现 HTTP 405 Method Not Allowed,请改用 PUT。

下面示例会让 headless Chrome 打开 https://example.com/,等待标题出现,然后关闭页面:

bash
python3 - <<'PY'
import json, time, urllib.parse, urllib.request

BASE = "http://127.0.0.1:9222"
URL = "https://example.com/"

# 1) 新建一个 tab(PUT /json/new)
req = urllib.request.Request(
    BASE + "/json/new?" + urllib.parse.quote(URL, safe=":/?&=#"),
    method="PUT",
)
created = json.load(urllib.request.urlopen(req, timeout=10))
tid = created["id"]
print("created id:", tid)

# 2) 轮询 /json/list,直到页面 title 可用
for _ in range(80):
    targets = json.load(urllib.request.urlopen(BASE + "/json/list", timeout=10))
    t = next((x for x in targets if x.get("id") == tid), None)
    if t and t.get("title"):
        print("url:", t.get("url"))
        print("title:", t.get("title"))
        break
    time.sleep(0.25)
else:
    raise SystemExit("page did not finish loading in time")

# 3) 关闭 tab(PUT /json/close/<id>)
urllib.request.urlopen(urllib.request.Request(BASE + "/json/close/" + tid, method="PUT"), timeout=10)
print("closed")
PY

若输出包含 title: Example Domain,即表示 CDP 可用且能够驱动浏览器访问网页

Step 3 打开 DevTools UI(可选)

  1. 打开 http://127.0.0.1:9222/json/list
  2. 找到目标页面的 devtoolsFrontendUrl 并在本地浏览器打开

或使用本地 Chrome:

  • 打开 chrome://inspect/#devices
  • 点击 “Configure...” 添加 localhost:9222
  • 在列表中点击 “Inspect”

停止与清理

在远端的 tmux 会话中按 Ctrl+C 停止 Chrome,随后可删除临时 profile:

bash
DIR=$(sed -n 's/^profile_dir=//p' /tmp/chrome-cdp-9222.info)
[ -n "$DIR" ] && rm -rf "$DIR"

警告

CDP 等价于“远程控制浏览器”。请务必只绑定 127.0.0.1 并通过 SSH 转发访问,不要把 9222 端口直接暴露到公网或内网其他用户可访问的网络中。

故障排除和监控

实时监控

查看实时日志以监控系统健康状况:

bash
# VNC 服务器状态
tail -f /tmp/x11vnc.log

# 系统监控
tail -f /tmp/vnc-monitor.log

# 防空闲活动
tail -f /tmp/anti-idle.log

# 恢复操作
tail -f /tmp/vnc-recovery.log

# 中文 IME(如果启用)
tail -f /tmp/ibus.log
tail -f /tmp/fcitx5.log

手动恢复

如果遇到问题,可以手动触发恢复:

bash
# 运行健康检查和恢复
/usr/local/bin/vnc-recovery.sh

# 完全重启 VNC 桌面
/usr/local/bin/start-vnc-desktop.sh

自动化监控

本教程默认使用 vnc-recovery-loop.sh 实现“每 2 分钟自愈一次”的自动恢复(无需 cron)。

bash
# `start-vnc-desktop.sh` 已会自动启动恢复循环。
# 如果您只想单独启动恢复循环(可选):
VNC_RECOVERY_INTERVAL_SECONDS=120 /usr/local/bin/vnc-recovery-loop.sh &

中文输入法(默认启用)与替代方案

由于 IBus 脚本已在 Step 4 中创建,以下是额外的中文输入替代方案。

基于网页的中文输入(备用方法)

对于即时中文输入需求,使用基于网页的解决方案:

  1. Google 输入工具

    • 在 VNC 会话中打开 Google Chrome
    • 访问 Google 输入工具
    • 选择中文(简体或繁体)
    • 输入拼音生成中文字符
  2. 在线 IME 服务

fcitx5 替代设置

默认中文输入后端是 IBus。如果您希望改用 fcitx5(例如 IBus 在当前会话里异常),推荐在启动桌面时直接指定后端:

bash
CHINESE_IME_BACKEND=fcitx5 /usr/local/bin/start-vnc-desktop.sh

fcitx5 替代方案说明

  • IBus 与 fcitx5 不能同时启用/同时使用(互斥)

    • 两者都是“输入法框架”,都会提供 XIM/GTK/Qt 等前端;在同一个桌面会话里同时运行很容易出现 输入不生效、候选框不显示、状态切换异常 等不可预测问题。
    • 因此本教程的脚本会在启动时 只保留一个后端:选择 fcitx5 会先停止 ibus-daemon,选择 ibus 会停止 fcitx5,避免冲突。
  • 启动脚本会自动完成

    • DBus 会话:如缺失则自动 dbus-launch
    • 环境变量GTK_IM_MODULE/QT_IM_MODULE/XMODIFIERS/SDL_IM_MODULE
    • profile 预置:自动写入 ~/.config/fcitx5/profile(默认启用 pinyin + keyboard-us
    • 日志:写入 /tmp/fcitx5.log
  • 常用排错

    • 查看日志tail -f /tmp/fcitx5.log
    • 检查状态(可选)fcitx5-remote(0=close,1=inactive,2=active)。如果刚启动桌面还未打开任何 GUI 应用,可能一直是 0;先打开 mousepad/xfce4-terminal 再检查。
    • 图形化配置(可选)fcitx5-configtool
    • 注意:如果您在“桌面已经启动之后”才手动启动 fcitx5,部分应用可能不会立刻生效;请关闭并重新打开目标应用,或直接用上面的方式重启桌面栈。

(可选)禁用中文 IME

本教程默认启用中文 IME(后端默认 IBus,含候选框)。如您不需要中文输入,可禁用以减少进程数量:

bash
ENABLE_CHINESE_IME=false /usr/local/bin/start-vnc-desktop.sh

测试中文输入

验证设置是否工作:

  1. 打开文本编辑器(如 mousepad
  2. 切换输入法(通常为 Ctrl+Space
  3. 输入拼音:"nihao"应显示中文字符候选
  4. 选择字符:使用数字键或空格键选择

注意

如果您发现“可以打出中文,但不显示候选框”,通常是因为 IBus 面板进程未启动(例如误用了 --panel=disable)。

  • 快速检查:pgrep -a ibus-ui-gtk3

  • 修复方法(在 VNC 桌面终端执行):

    bash
    pkill ibus-daemon
    ibus-daemon -drx &
    ibus engine pinyin 2>/dev/null || true
    ibus engine libpinyin 2>/dev/null || true

如何停止 VNC 桌面系统

当您完成使用 VNC 桌面后,您可能想要停止所有进程以释放系统资源。以下是停止系统的不同方法:

方法 1:优雅停止(推荐)

优雅停止所有进程:

bash
# 停止监控/防空闲/自动恢复循环脚本
pkill -f "vnc-monitor.sh"
pkill -f "anti-idle.sh"
pkill -f "vnc-recovery-loop.sh"

# 停止桌面会话(可选但推荐)
pkill startxfce4
pkill xfce4-session

# 停止 VNC 服务器
pkill x11vnc

# 停止 X 服务器
pkill Xorg

# 停止中文输入法(如果启用)
pkill ibus-daemon
pkill fcitx5

方法 2:强制停止(终极选项)

如果优雅停止不起作用:

bash
# 强制终止所有 VNC 相关进程
pkill -9 x11vnc
pkill -9 Xorg
pkill -9 -f "anti-idle.sh"
pkill -9 -f "vnc-monitor.sh"
pkill -9 -f "vnc-recovery-loop.sh"
pkill -9 -f "ibus-daemon"
pkill -9 -f "fcitx5"

方法 3:一键停止脚本

创建一个便捷的停止脚本:

bash
cat > /usr/local/bin/stop-vnc-desktop.sh << 'EOF'
#!/bin/bash

echo "正在停止 VNC 桌面系统..."

# 停止主要进程
pkill -f "anti-idle.sh"
pkill -f "vnc-monitor.sh"
pkill -f "vnc-recovery-loop.sh"
pkill startxfce4
pkill xfce4-session
pkill x11vnc
pkill Xorg

# 停止中文输入法
pkill -f "ibus-daemon"
pkill -f "fcitx5"

# 清理锁定文件
rm -f /tmp/.X0-lock /tmp/.X11-unix/X0

echo "VNC 桌面系统已停止。"
EOF

chmod +x /usr/local/bin/stop-vnc-desktop.sh

然后使用它:

bash
/usr/local/bin/stop-vnc-desktop.sh

方法 4:禁用自动恢复

如果您希望桌面“只启动、不自动自愈”(例如调试期间):

bash
# 方式 1:启动时禁用自动恢复
ENABLE_AUTO_RECOVERY=false /usr/local/bin/start-vnc-desktop.sh

# 方式 2:运行中停止恢复循环
pkill -f "vnc-recovery-loop.sh"

验证

检查一切是否已停止:

bash
# 检查任何剩余的 VNC 进程
ps aux | grep -E "(x11vnc|Xorg|vnc-|anti-idle|ibus|fcitx5)" | grep -v grep

# 检查端口 5900 是否仍在监听
netstat -tlnp | grep :5900

# 检查 X 服务器锁定文件
ls -la /tmp/.X*-lock 2>/dev/null || echo "未找到 X 锁定文件"

重要注意事项

  • 自动恢复循环会“自愈”系统:默认每 2 分钟运行一次健康检查并在必要时重启组件。如果您在调试问题且不希望它干预,请用 ENABLE_AUTO_RECOVERY=false 启动,或停止 vnc-recovery-loop.sh
  • 容器重启:如果您在容器中运行并重启它,所有进程将自动停止。
  • 资源清理:停止脚本会清理临时文件和锁定文件,以确保干净的关机。
  • 逐步方法:首先尝试方法 1,如果需要再升级到方法 2。

总结

这个生产就绪版本的教程提供了:

  • 全面监控:实时健康检查和日志记录
  • 自动恢复:检测问题并自动重启服务
  • 防空闲措施:防止 VNC 会话在空闲期间变得无响应
  • 中文输入法支持:可选的 IBus 和 fcitx5 集成
  • 企业级调试:详细的日志记录和故障排除工具
  • 优化的 VNC 设置:针对稳定性和响应性调整的参数
  • GPU 电源管理控制:防止省电模式干扰显示

这些生产就绪功能确保了稳定、响应迅速的 VNC 桌面环境,能够处理常见的无头和容器化问题。

参考资料

找不到想要的答案?
让 AI 助手为您解答