实现Linux无头模式下硬件加速的屏幕共享

本文章分为两个部分,第一部分为有可视化界面的机载电脑(使用AMD, Intel集显参考此方法),如何在局域网下不连接显示屏来可视化界面,第二部分为服务器中,如何直接可视化界面(需要sudo权限,使用Nvidia显卡渲染参考此方法)

局域网屏幕共享

简单记录下局域网下,Linux的X11界面如何共享到其他设备使用,并配置开机自动启动功能。

如果是从外网连接,直接用ToDesk或者向日葵即可(注意:向日葵不支持Ubuntu24.04),用本地局域网连接推荐用WIFI6,带宽更大

此处有两种常用工具:NoMachine和VNC,这里推荐用VNC服务器,延迟相比NoMachine更低些

NoMachine使用方法非常简单,直接在两台电脑上都下载NoMachine,服务端打开server,客户端刷新即可看到可连接的设备,缺点是经常卡住不懂,需要手动刷新页面非常麻烦

VNC服务端

参考CSDN - VNC服务端比对 (vncserver vs x11vnc)

VNC的服务端有两种常用的版本,分别为

  • vncserver(默认用TigerVNC, 还有TightVNC, TurboVNC等):创建一个全新的独立桌面(适合无指定显卡渲染,完全由软件渲染,即没有配置/etc/X11/xorg.conf文件)
  • x11vnc:直接共享当前屏幕内容(适合有指定显卡渲染,即有配置/etc/X11/xorg.conf文件,需要手动启动一个X服务)

分别的安装方法为:

# TigerVNC
sudo apt install tigervnc-standalone-server
# x11vnc
sudo apt install x11vnc

服务端启动VNC服务后都会在本机上创建一个端口,他们的默认端口都是5900, 5901, ...,当主机没有固定的显示屏时,推荐使用vncserver

vncserver配置开机自启(在没有直连显示器时使用,稳定,不会有黑屏)

直接启动

首先介绍vncserver直接使用的方法,他会创建一个新的DISPLAY窗口,不会和已有的DISPLAY窗口冲突并且不会共享窗口,先用vncpasswd配置VNC登陆密码

❯ vncpasswd
Password:
Verify:
Would you like to enter a view-only password (y/n)? n
A view-only password is not used

创建新窗口

❯ vncserver :1

New Xtigervnc server 'kuavo-NUC12WSKi7:2 (kuavo)' on port 5902 for display :2.
Use xtigervncviewer -SecurityTypes VncAuth -passwd /home/kuavo/.vnc/passwd :2 to connect to the VNC server.

查看当前以创建窗口

❯ vncserver --list

TigerVNC server sessions:

X DISPLAY #     RFB PORT #      RFB UNIX PATH   PROCESS ID #    SERVER
1               5901                            38001           Xtigervnc

如果创建的是:1则对应端口为5901,后续客户端连接对应的端口即可,创建:N(N为正整数)则对应端口为590N:0通常为默认的窗口界面,如果没有连主显示屏可能是黑屏)

关闭:1号窗口:vncserver -kill :1

配置开机自启

tigervnc已经为我们配置好开机自启文件了,我们只需要学会使用即可,cat /usr/lib/systemd/system/tigervncserver@.service查看已经为我们配置好的启动文件,使用方法就是在/etc/tigervnc/vncserver.users中加入一个名称即可

sudo vim /etc/tigervnc/vncserver.users

# 在文件的最下面一行加入, 例如我电脑的用户名为kuavo
:1=kuavo

如果之前启动了:1窗口,先将其关闭vncserver -kill :1,使用systemctl启动:

sudo systemctl start tigervncserver@:1.service  # 启动服务
sudo systemctl status tigervncserver@:1.service  # 查看服务的启动状态, 显示active (running)就说明正常
sudo systemctl enable tigervncserver@:1.service  # 创建开机自启

x11vnc配置开机自启(在有直连的显示屏时使用)

参考ubuntu18.04安装x11vnc远程登录并设置开机自启

直接启动

# 安装x11vnc
sudo apt-get install x11vnc -y
# 设置VNC密码
sudo x11vnc -storepasswd /etc/x11vnc.pass
# 给予权限
sudo chmod 777 /etc/x11vnc.pass
# 创建启动文件
sudo vim /etc/init/x11vnc.conf

在安装完x11vnc后,按功能键(Win键)后输入x11vnc server可以打开可视化配置界面,第一个界面配置端口,用默认5900即可,在第二个界面点Accept Connection,然后就启动VNC服务了,可以用于调试是否可以联通,我们以下的自启动方法无需该界面进行配置

启动文件如下

# x11vnc.conf
exec /usr/bin/x11vnc -auth guess -capslock -forever -loop -noxdamage -repeat -rfbauth /etc/x11vnc.pass -rfbport 5900 -shared

测试启动文件能否使用

source /etc/init/x11vnc.conf

配置开机自启

配置开机自启动

sudo vim /etc/init.d/x11vnc.sh

启动脚本内容如下

#!/bin/bash
source /etc/init/x11vnc.conf

修改权限

sudo chmod 777 /etc/init.d/x11vnc.sh

添加到自启动项中,按左下角功能键(Win键),输入startup application,打开窗口点击右侧Add,修改内容如下后保存:

如果不想用GUI可以在~/.conf/autostart下创建x11vnc.desktop文件,内容如下

X11VNC startup application

VNC客户端

VNC的客户端也有两种选择,Windows推荐用RealVNC效果可能更好些(Linux也可以用,但是界面比较简陋),更推荐的是用网页版的noVNC,直接通过网页即可访问,功能也很全。

noVNC服务端自动启动

一个直接用网页即可访问VNC的服务端/客户端,非常方便,只需在服务端启动一个网页程序,然后客户端就可以直接访问主机的网页啦,使用方法如下:

cd ~/Programs  # 进入到你想保存软件的位置
git clone https://github.com/novnc/noVNC.git
# 启动客户端网页界面, x11vnc端口为默认为5900, vncserver端口为590N, 这个N表示创建的DISPLAY=:N编号
# 网页访问端口默认为6080
./noVNC/utils/novnc_proxy --vnc localhost:5900

ifconfig查看本机的IP地址,例如我的是192.168.31.103,则在局域网中的另一台电脑或手机可通过http://192.168.31.103:6080/vnc.html直接访问可视化界面

自动启动配置如下,还是先创建启动脚本

cat /etc/init.d/novnc.sh  # 启动脚本内容如下
#!/bin/bash
<YOUR_PATH>/noVNC/utils/novnc_proxy --vnc localhost:5900

注意上述路径请替换为你的,并测试一下能否运行source /etc/init.d/novnc.sh

记得添加访问权限sudo chmod 777 /etc/init.d/novnc.sh

类似上述设置自启动脚本的方法,添加到自启动项中,按左下角功能键(Win键),输入startup application,打开窗口点击右侧Add,修改内容如下后保存:
noVNC startup application

RealVNC

RealVNC/Download中下载并安装,在打开APP界面,直接输入IP:5900即可直接连上(Linux的缺点是无法复制文本内容,有点麻烦)

服务器可视化

除了apt所需的命令需要管理员权限,其他的命令都可以非管理员执行,例如vncserver、启动noVNC,由于服务器默认是没有可视化界面的,因此考虑用tigervnc来启动界面

sudo apt install tigervnc-standalone-server

先用tigervncserver -xstartup /usr/bin/xterm排除下问题

可能缺少xterm,用sudo apt install xterm安装,

查看下xsessions下有哪些可用的界面

$ ls /usr/share/xsessions/
gnome.desktop  gnome-flashback-compiz.desktop  gnome-flashback-metacity.desktop  gnome-xorg.desktop \
ubuntu.desktop  xfce.desktop

例如我有gnomexfce

(不推荐)Xvnc启动X服务(不支持默认显卡渲染驱动)

vncserver启动的X服务和Xorg(默认的外接显示器的启动是不一样的),而Nvidia的显卡渲染配置是在/etc/X11/xorg.conf下的,因此我们必须加载此文件才能用显卡渲染(找不到显卡可能在OpenGL或GLA渲染中出现黑屏,例如IsaacGym和IsaacSim),因此推荐用下文Xvfb启动X服务的方法

xfce4界面 - 配置xstartup

编辑文件vim ~/.vnc/xstartup

#!/bin/sh
unset SESSION_MANAGER
unset DBUS_SESSION_BUS_ADDRESS
xrdb $HOME/.Xresources 2>/dev/null
startxfce4 &

gnome界面 - 配置xstartup

安装gnome界面相关应用:sudo apt install ubuntu-gnome-desktop gnome-session gnome-panel gnome-terminal nautilus

编辑文件vim ~/.vnc/xstartup

#!/bin/sh
unset SESSION_MANAGER
unset DBUS_SESSION_BUS_ADDRESS
export XKL_XMODMAP_DISABLE=1
[ -r $HOME/.Xresources ] && xrdb $HOME/.Xresources
gnome-session --session=gnome &

可能出现的错误

黑屏报错

出现报错:

Could not update ICEauthority file /run/user/1016/ICEauthority

这是因为用另一个用户启动了这个vncserver但是他不具有当前ssh登陆的用户的权限,修改这个目录的权限即可

sudo chown guohanwei /run/user/1016

vncserver exited too early

出现这个报错信息:vncserver exited too early,可以参考StackExchange - vncserver exited too early,修改~/.vnc/xstartup,删除最后的&符号即可

gnome登陆界面输入密码后无法进入界面

不清楚问题原因,可能没有管理员全线无法进入界面

转发gdm3后黑屏

不清楚问题原因,推荐使用后续的openbox直接启动方法

使用TurboVNC+VirtualGL用硬件提升渲染速度

此方法不如(推荐)Xorg服务器启动以支持Nvidia驱动渲染,因为IsaacSim和IsaacGym通过vglrun启动时仍然会出现黑屏问题

sudo apt install virtualgl
# 或者在官网下载
https://sourceforge.net/projects/virtualgl/files/
# 找到*_amd64.deb安装包

查看是否有显卡渲染:

$ glxinfo -display :1 | grep "OpenGL renderer"
# 或者
$ /opt/VirtualGL/bin/glxinfo -display :1 | grep "OpenGL renderer"

# 显示没有显卡驱动
OpenGL renderer string: llvmpipe (LLVM 12.0.0, 256 bits)

# 前面加上vglrun即可用显卡驱动渲染
$ vglrun /opt/VirtualGL/bin/glxinfo -display :1 | grep "OpenGL renderer"
OpenGL renderer string: NVIDIA GeForce RTX 4090/PCIe/SSE2

测试渲染速度:

$ glxgears
6757 frames in 5.0 seconds = 1351.280 FPS
6821 frames in 5.0 seconds = 1364.121 FPS

❯ vglrun -d :1 glxgears
14218 frames in 5.0 seconds = 2843.435 FPS
14330 frames in 5.0 seconds = 2865.927 FPS

安装方法参考:cyoahs - TurboVNC+VirtualGL:实现服务器的多用户图形化访问与硬件加速

IsaacGym启动后黑屏问题

这个是vncserver转发的问题,可以通过Xorg启动渲染的方式解决

Gnome和Mujoco无法启动的问题

Mujoco报错为python: /builds/florianrhiem/pyGLFW/glfw-3.4/src/monitor.c:449: glfwGetVideoMode: Assertion monitor != NULL' failed.

解决:在xorg.conf配置文件中没有对虚拟Monitor进行配置(参考下述xorg-nvidia-dummy-monitor.conf配置文件)

(推荐)Xorg服务器启动以支持Nvidia驱动渲染

这一段启动需要sudo权限,以及至少4个终端,推荐用VsCode或者Tmux拆分终端,或者直接参考最后的一键启动脚本

这个可能是服务器上最好用的窗口渲染方法,在尝试了各种VNC转发,只有这种方法可以渲染IsaacGym, IsaacSim

XorgXvfb都是启动X服务的方法(startx也是便捷方法,但是启动后权限总是有问题于是不用),但只有Xorg才会用到/etc/X11/xorg.conf配置文件,因此使用Xorg

我们要直接用Nvidia显卡渲染需要自定义一个X服务,再启动x11vnc用VNC协议转发图像界面,用noVNC使浏览器可以访问VNC界面,最后打开xfce会话就可以看到图形界面啦,从而也可以用Nvidia驱动渲染界面,打开IsaacGym, IssaacSim,流程如下:

  1. 查看当前可用的显卡驱动Bus ID后面会用到(或者从现在已有的/etc/X11/xorg.conf查看BusID,如果xorg.conf为空就用nvidia-xconfig初始化一个即可):
    # 用nvidia-smi -q查询BusID(16进制), 需手动转为10进制
    nvidia-smi -q | grep "Bus Id"
    
    # 脚本将nvidia-smi -q查询到的BusID从16进制转为10进制(脚本可能失效)
    nvidia-smi -q | grep "Bus Id" | while read -r _ _ _ busid; do
      bus=$(echo $busid | cut -d':' -f2)
      dev=$(echo $busid | cut -d':' -f3)
      func=$(echo $busid | cut -d':' -f4 | cut -d'.' -f2)
      dev_hex=$(echo $busid | cut -d':' -f4 | cut -d'.' -f1)
      printf "PCI:%d:%d:%d\n" $((16#$bus)) $((16#$dev_hex)) $((16#$func))
    done
    
    # 我的输出为(8张显卡)
    PCI:1:0:0
    PCI:36:0:0
    PCI:65:0:0
    PCI:97:0:0
    PCI:129:0:0
    PCI:161:0:0
    PCI:193:0:0
    PCI:225:0:0
  2. 新建一个sudo vim /etc/X11/xorg-nvidia-dummy-monitor.conf X服务启动配置文件,在这里下载edid.bin是我自己显示屏的EDID文件,放到/etc/X11/edid.bin下,这样就可以得到和我显示屏一样的配置文件了
    Section "Device"
        Identifier     "NvidiaGPU"
        Driver         "nvidia"
        VendorName     "NVIDIA Corporation"
        BoardName      "GeForce RTX 4090"
        BusID          "PCI:97:0:0"
        Option         "AllowEmptyInitialConfiguration" "true"
        Option         "ConnectedMonitor" "DFP-0"
        Option         "CustomEDID" "DFP-0:/etc/X11/edid.bin"  # 显示器配置文件
    EndSection
    
    Section "Monitor"  # 必须要Monitor才能启动gnome界面, mujoco也需要
        Identifier     "Monitor0"
        VendorName     "Generic"
        ModelName      "Virtual Monitor"
        HorizSync       28.0 - 72.0
        VertRefresh     50.0 - 75.0
        Option         "DPMS"
    EndSection
    
    Section "Screen"
        Identifier     "Screen0"
        Device         "NvidiaGPU"
        Monitor        "Monitor0"
        DefaultDepth    24
        SubSection "Display"
            Depth       24
            Modes      "1920x1080"
            Virtual     1920 1080
        EndSubSection
    EndSection
    
    Section "ServerLayout"
        Identifier     "Layout0"
        Screen         "Screen0"
    EndSection
  3. 启动X服务:sudo X :1 -config /etc/X11/xorg-nvidia-dummy-monitor.conf(设置界面编号为DISPLAY=:1,指定使用我们刚才配置的文件,不会影响到正常的连接显示屏,因为默认配置文件是/etc/X11/xorg.conf

    检查当前DISPLAY下的分辨率和Monitor连接状态:DISPLAY=:1 xrandrDISPLAY=:1 xrandr --listmonitors输出显示有屏幕型号即正确

  4. 启动x11vnc转发:(安装x11vnc见上文
    • 配置密码(仅需一次):sudo x11vnc -storepasswd,默认保存在~/.vnc/passwd文件下,这里就保存在/root/.vnc/passwd下了,后面写脚本更方便些(需要注意这样启动的是root的桌面,如果无需root,还是将密码保存在用户文件夹下)
    • 启动转发:sudo x11vnc -display :1 -rfbauth /root/.vnc/passwd -forever -shared -loop,每个参数的作用如下:
      • -display :1:转发X服务器:1显示界面
      • -rfbauth /root/.vnc/passwd:使用密码
      • -forever:允许持续运行,不会在第一个客户端断开时退出
      • -shared:支持多电脑连接
      • -loop:如果发生错误(如 X session 暂时不可用),会自动尝试重新连接
      • -noxdamage:(可选)禁用 X Damage 扩展,用于修复某些情况下屏幕不刷新的问题(尤其在某些显卡驱动下);当屏幕变化不大时,该扩展可以显著降低负载,并更快地检测变化区域
  5. 使用novnc显示:./utils/novnc_proxy --vnc localhost:5900安装noVNC见上文

这时候在浏览器上输入<服务器IP>:6080即可连接上VNC,我们在终端中启动DISPLAY=:1 xclock一个小闹钟,可以看到屏幕,但是我们无法进行拖动,可以用DISPLAY=:1 openbox来进行简单窗口拖动,但是还是没有会话界面,下面启动一个会话界面xfce4或者gnome

  1. 先启动DBUS会话服务
    # 启动
    eval $(dbus-launch --sh-syntax)
    export DBUS_SESSION_BUS_ADDRESS
    export DBUS_SESSION_BUS_PID
    # 验证一下有没有返回值
    echo $DBUS_SESSION_BUS_ADDRESS
    # unix:abstract=/tmp/dbus-7vGHzBEZzq,guid=7fe9bcd482e14c8e918179976829d0cd
  2. 启动gnome:DISPLAY=:1 gnome-session,或者,启动xfce4:DISPLAY=:1 startxfce4
  3. 通过命令行打开可视化程序,只需要在终端执行一次export DISPLAY=:1,后续的所有可视化窗口都会在这个界面显示出来啦

例如我们在Gnome下启动了python -m mujoco.viewer./isaac-sim.sh, python 1080_balls_of_solitude.py效果如下,大功告成!(用工位的网络,非常流畅,和本机使用差不多效果,还只需要启动一个网页即可,非常方便,手机也可以)

通过glxinfo | grep renderer可查看使用的渲染:

$ glxinfo | grep renderer
# 有Nvidia驱动
OpenGL renderer string: NVIDIA GeForce RTX 4090/PCIe/SSE2
# 没有显卡驱动,CPU软件渲染
OpenGL renderer string: llvmpipe (LLVM ...)

一键启动脚本

创建脚本位置放在/usr/local/bin/start-gnome-vnc.sh(放哪都行,因为有sudo命令所以放在根目录下了),使用方法:

# 设置一次启动权限
sudo chmod +x /usr/local/bin/start-gnome-vnc.sh

sudo bash start-gnome-vnc.sh  # 启动全部脚本

# ctrl+c即可退出, 并自动kill掉所有启动的进程

脚本功能:按照上述流程依次启动X服务、DBus会话服务、gnome会话、x11vnc转发、noVNC网页可视化;并自动检查6080端口是否被占用,若占用则说明已启动,无需再次启动

  1. 下面脚本中的x11vnc密码就用/root/.vnc/passwd了,按需调整密码保存的位置(脚本由ChatGPT 4o生成)
  2. 需要调整noVNC保存的路径哦

进一步可以在~/.bashrc中加入快捷启动命令:

# ~/.bashrc
alias start-gnome-vnc="sudo bash /usr/local/bin/start-gnome-vnc.sh"

source ~/.bashrc
start-gnome-vnc  # 即可一键启动了
# 退出使用Ctrl+C或者找到Xorg进程将其kill

关闭已经启动的X服务

通过ps aux | grep "Xorg :1"命令可以查看当前启动的服务(例如我是在DISPLAY=:1上启动的),那么就要关掉/usr/lib/xorg/Xorg这个程序启动的PID,sudo kill -9 3557223即可

ps aux | grep "Xorg :1"
root     3557222  0.2  0.0  15008  4844 pts/5    S+   21:40   0:00 sudo Xorg :1
root     3557223 20.2  0.0 26109244 219564 tty2  Ssl+ 21:40   0:00 /usr/lib/xorg/Xorg :1  # 注意是这个/usr/lib/xorg/Xorg

实现Linux无头模式下硬件加速的屏幕共享
https://wty-yy.xyz/posts/47970/
作者
wty
发布于
2025年5月15日
许可协议