新机器默认装的 Ubuntu 22.04,有些老了,想升级成 26.04。在线升级要先到 24.04 再到 26.04,比较麻烦,于是就是下了一个 26.04.1 server 版的镜像。开始是通过 BMC 远程镜像安装,结果总是在开始安装后出错。以为是远程的问题,于是干脆拷到 ventory 的优盘上现场安装,结果发现同样的问题。不知是我下的 iso 文件有问题还是这个镜像原本就有问题。懒得回去再拷了,优盘上恰好有 24.04 desktop 版,就装它吧,这回一切顺利。装完后设置国内源,然后 sudo apt update 和 sudo apt full-upgrade -y 先更新到最新,然后执行 do-release-upgrage 进行跨版本升级。结果总是说没有可升级的 lts 版本,后来加了一个 -d 选项后才开始升级。最后升级到了 26.04。这里有一个坑,升级后的源里原来的国内镜像被自动注释掉了用的官方镜像,我说后来下载的时候怎么有点慢呢。于是我又改了回去,但是没仔细看,之前被注释掉的 24.04 版的源 noble 字样我没改,导致后来想安一些包时总是说冲突无法安装,比如 xorg。最开始我还以为 26.04 彻底使用 wayland 后完全不许安装 xorg 了呢。其实并非如此,改成正确的 resolute(26.04 版代号)就能正常安装了。
1. 不能浪费显存
既然是桌面版,默认的 gnome-shell 桌面是要占用显存的,而显存是用来计算的,用于显示就有些浪费了。系统有个默认的板载显卡(给BMC用的)作为 VGA 输出,目前是把 nvidia 显卡当成渲染设备了。我不想用 nvidia 显卡进行渲染,使用 cpu 软件渲染就够了。于是创建 /etc/udev/rules.d/61-mutter-ignore-nvidia.rules 文件,内容如下
SUBSYSTEM=="drm", KERNEL=="card1", DRIVERS=="nvidia", TAG+="mutter-device-ignore"
这个文件利用 GNOME Mutter(Wayland compositor)的“设备黑名单”机制,专门用来告诉 Mutter:这个 GPU 你别碰,别把它当渲染设备用。当内核检测到 card1是 nvidia 驱动管理的 DRM 设备时,给它打上 mutter-device-ignore标签,Mutter 看到这个标签就会直接跳过它,不用它做合成/渲染。然后重启 udev 或干脆重启系统令其生效。
# 重启 udev 守护进程
sudo systemctl restart systemd-udevd
# 重新加载规则文件
sudo udevadm control --reload
# 触发一次(让新规则立即生效,可选)
sudo udevadm trigger
这样处理后显示器上的 gnome-shell 图形界面就不使用 GPU 了。可通过 nvidia-smi 查看是否还有 gnome-shell 的进程。
2. 远程桌面 gnome-remote-desktop
我想实现无头的远程桌面访问,也就是不论本地是否接显示器都行,像 vnc 那样。一开始由于没装上 xorg 也没法装 vnc,就只能用 gnome-remote-desktop (GRD)的无头方案了。跟着 gpt 一步步弄的,细节就不说了,好像又得设密码,又得创建 ssl 自签名密钥啥的,还是有点繁琐的。弄好后在客户端装 remmina 程序来访问(rdesktop 早已过时)。虽然能访问但我又发现一个问题,GRD 远程连接和接显示器的本地会话是互斥的,一个登录另一个就要退掉。此外,一个更重要的问题是好不容易本地桌面会话不用 nvidia 了,结果 GRD 一旦连接又会使用 nvidia了,而且占用显存还更多!试了一些方案想禁止 GRD 使用 nvidia,结果都不管用。最终只能又回到 vnc 方案。
3. xfce4 + tigervnc
首先安装
sudo apt install xfce4-goodies tigervnc-standalone-server
【坑1】26.04 下 vnc 的配置目录不是 ~/.vnc 而是 ~/.config/tigervnc,这导致一开始在 ~/.vnc 下该 xstartup 怎么试都不管用,而且当时还奇怪为什么这个目录下没有 passwd 和日志文件呢。后来干脆把 ~/.config/tigervnc 链接到 ~/.vnc 下。
【坑2】vcnserver :1 总是失败,说显示 :1 已被占用,可又不知道是谁占用的。改用 :2 就行。
【坑3】xstartup 内容如下(后来又发现仅此还不够)
#!/bin/sh
# 确保使用 X11 的 Xfce 会话
unset SESSION_MANAGER
unset DBUS_SESSION_BUS_ADDRESS
exec startxfce4
由于坑1,一开始试的时候两个 unset 发现没效果,后来干脆就没使用它们。这导致连接到 vnc 后发现啥都没有,就一个空的 X 窗口,根本没见 xfce4 桌面。奇怪的是,在本地显示器端的 gnome shell 上却出现了 xfce4 的部件!也就是说程序跑到 wayland 的图形界面上了。后来还试过在 /etc/gdm3/custom.conf 中 [daemon] 字段下添加 WaylandEnable=false 并重启 gdm 服务,结果能部分起效:即 xfce4 桌面确实回到 vnc 里了,但是 gnome 的程序比如 gnome-terminal 如果运行的话还是会跑到 wayland 上去,而 x 的程序则不会,比如 xterm 以及 xfce4 自己的程序也不会。其实,根本不用设 WaylandEnable=false,只要在 xstartup 里加上那两句 unset 就行!只不过一开始整个 xstartup 都没有生效却没有发现罢了。
【坑4】装 xfce4 时会装 lightdm,然后会让你选择默认的登录管理器,是选 gdm3 还是 lightdm。我一开始选了 lightdm,结果发现 本地显示器上卡死无法进入桌面,就只有一个光标在屏幕中间还动不了。 最后换回 gdm3 就好了(sudo dpkg-reconfigure gdm3)。
配置好 vnc 后是可以 vnc 与本地的 gnome-shell 同时存在且互不干扰的。而且 vnc 不占用 nvidia!
4. 问题还没解决
按上面配置完似乎好了,然后后来发现仍有问题。可能当时本地只停留在 gdm 登录界面并没有登录进 gnome-shell 吧,今天登录进去以后发现 vnc 又黑屏了,重启也不行,xfce4 又跑到 gnome-shell 里去了。gdm 设置改回 WaylandEnable=false 也不管用。归根结底还是 vnc 和 gnome 共用了 dbus 等资源出现互相争抢,从而出现了莫名其妙的问题。
最后根据 AI 所说,将 xstartup 改为如下基本能解决:
#!/bin/sh
export DISPLAY=:2
unset SESSION_MANAGER
unset DBUS_SESSION_BUS_ADDRESS
unset WAYLAND_DISPLAY
unset GNOME_SETUP_DISPLAY
unset GNOME_DESKTOP_SESSION_ID
unset GNOME_TERMINAL_SCREEN
unset DESKTOP_SESSION
# 私有 runtime dir,不和 seat0 的 GNOME 共用
export XDG_RUNTIME_DIR=/run/user/$(id -u)/vnc
mkdir -p "$XDG_RUNTIME_DIR" && chmod 700 "$XDG_RUNTIME_DIR"
# 私有 session bus,防止被 GNOME 的总线激活把组件吸到 :0
eval "$(dbus-launch --sh-syntax)"
export XDG_SESSION_TYPE=x11
export XKL_XMODMAP_DISABLE=1
export LIBGL_ALWAYS_SOFTWARE=1 # 强制软件渲染,躲开 NVIDIA
export __GLX_VENDOR_LIBRARY_NAME=mesa
[ -r "$HOME/.Xresources" ] && xrdb "$HOME/.Xresources"
xsetroot -solid "#555555" # 灰底:连上能看到灰色 = X 活着,纯黑 = 别的原因
vncconfig -nowin &
sleep 1
exec startxfce4
此外,还要关闭 xfce 合成器,使用如下命令
xfconf-query -c xfwm4 -p /general/use_compositing -s false
还有一点就是要让 vnc 禁用 GLX 扩展。这个采用了变通的方法。服务中使用的是 vncserver 启动的,它是一个 Xtigervnc 的 wrapper,可是并不能把所有参数都传给 Xtigervnc。我需要把 -extension GLX 参数传给 Xtigervnc,直接写在 vncserver 后面不管用。主要这里的 - 指定是“减去/取消”(如果是 + 则是“加上/启用”)。为此,只能把 /usr/bin/Xtigervnc 备份为 Xtigervnc-ori, 再用一个同名脚本封装一下,内容为
#!/bin/bash
/usr/bin/Xtigervnc "$@" -extension GLX
这样 vncserver 调用 Xtigervnc 时就带上了 -extension GLX 参数。
5. 把 vncserver 设成用户级服务
创建 ~/.config/systemd/user/vncserver.service 文件,内容如下
[Unit]
Description=TigerVNC Server for user %i
After=graphical.target
[Service]
Type=forking
Environment=XAUTHORITY=$HOME/.Xauthority
Environment=DISPLAY=:2
Environment=XDG_RUNTIME_DIR=/run/user/%U/vnc
Environment=DBUS_SESSION_BUS_ADDRESS=
ExecStart=/usr/bin/vncserver :2
ExecStop=/usr/bin/vncserver -kill :2
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=default.target
`然后启动并启动服务(不需 sudo,用户自己执行即可)
systemctl --user daemon-reload
systemctl --user enable tigervnc.service
systemctl --user start tigervnc.service
默认情况下,用户级服务只在用户登录后才运行。如果希望通过 VNC 远程连接来首次登录,需要通过 sudo loginctl enable-linger $USER 开启 linger,这个命令让 systemd 为用户保持一个用户管理器实例,即使该用户从未在物理机上登录过。
上面的环境变量设置为的是彻底隔离 vnc 与 gnome 所使用的系统资源,以免它们弄混。在启动服务前还要执行如下操作
# 生成 :2 自己的 authority(写进自己的 ~/.Xauthority,不要碰 gnome 所用的 Mutter 的)
xauth generate :2 . trusted
xauth list | grep ':2'
启动 vnc 服务后使用如下命令检查设置是否生效
# ① auth 文件必须是你自己的,不能再出现 .mutter
ps -p $(pgrep -f Xtigervnc) -o pid=,args= | grep -o '\-auth [^ ]*'
# ② xdpyinfo 应该能正常返回,不再报 cookie 错
xdpyinfo -display :2 | head -5
# ③ GLX 确实没了
xdpyinfo -display :2 | grep -i GLX # 应无输出
6. AI 总结
为什么关 xfwm4 合成器
三个理由,按重要性排序:
-
它是唯一还在碰 GPU 的东西。
-extension GLX禁掉的是 GLX 扩展(客户端直接申请 OpenGL 上下文的路),但 xfwm4 的合成器走的是 Composite + GL texture-from-pixmap,同样需要 NVIDIA 驱动和有效的 GL 上下文。本地 GNOME 的 Mutter 一旦重建上下文或重设设备,xfwm4 这边就拿到一个失效的上下文 →XSync timeout→ 窗口不绘制 → 黑屏。你日志里的GFX1 Handle DeviceReset / FORCED_RESET就是这条路径的证据。 - VNC 里它纯浪费。 Xtigervnc 是直接读 framebuffer 再编码的,合成器先合成一帧、Xvnc 再读一帧,等于多一次全屏幕拷贝,还增加编码量。远程看本来就有延迟,tearing 也看不出来,开合成器只有成本没有收益。
- 禁了 GLX 后它的行为不可控。 有些版本会退回软件 fallback 继续跑,有些会反复失败重试,后者正好表现为“连得上但画面不动”。显式关掉比指望它优雅降级可靠。
你早就关了,那这一层本来就是干净的,我反复提是多余的。
问题总结
症状:同一账号下,本地登录 GNOME 后重启 VNC 就黑屏(客户端能连上,画面不更新);只停在 GDM 不登录则正常;XFCE 进程其实还活着且 DISPLAY 仍是 :2。
根因:不是“桌面被 GNOME 吸走”,而是 Xtigervnc 和本地 GNOME 共用三样东西:
| 耦合项 | 表现 | 处理 |
|---|---|---|
X authority 共用 Mutter 的 .mutter-Xw
|
-auth /run/user/1000/.mutter-Xw,GNOME 侧一动 cookie 就乱,Invalid MIT-MAGIC-COOKIE-1
|
启动时显式 -auth $HOME/.Xauthority,并先 xauth generate :2 . trusted
|
| session bus + XDG_RUNTIME_DIR 共用 | polkit "session differs"、组件被 D-Bus 激活到 :0、设置串扰 | xstartup 里 unset DBUS_SESSION_BUS_ADDRESS + dbus-launch 自建总线,XDG_RUNTIME_DIR 指向私有目录 |
| GPU / GLX 共用 |
Handle DeviceReset / FORCED_RESET、xfwm4 XSync timeout |
启动加 -extension GLX,合成器关掉 |
外加一堆从 GNOME 漏进来的环境变量(WAYLAND_DISPLAY、GNOME_SETUP_DISPLAY 等),会让 VNC 里的应用误连本地会话,顺手 unset 掉。
一句话解法:给 Xtigervnc 一套独立的 authority、私有的 session bus/runtime dir、且不加载 GLX,再把这些写进系统级 systemd service 固化。做完这三件事,本地登不登 GNOME 互不影响。