2026/10/26 20:56:58

Ubuntu 24.04 下 x11vnc 共享已登录 X11 桌面实战

Ubuntu 24.04 下 x11vnc 共享已登录 X11 桌面实战 一台装着 Ubuntu 24.04 的工作站摆在实验室角落屏幕锁着人不在现场可偏偏有个图形界面的程序要在这台机器上点几下才能继续跑。SSH 进去改配置、重启服务都没问题唯独看不到那个已经登录的桌面。这种活儿我碰上过不止一次最后真正把问题解决掉的是 x11vnc 这套老牌方案。x11vnc 干的事情非常朴素它把当前正在运行的 X11 显示会话直接共享出来而不是另起一个虚拟桌面。这一点和很多人第一次接触远程桌面时的预期不一样——它连的是你已经登录的那个 session桌面上的窗口、正在跑的程序、任务栏原封不动地呈现给远程客户端。放在 Ubuntu 24.04 上这套组合有几个绕不开的坑默认会话是 Waylandx11vnc 抓不到画面Xauthority 路径和以前不同认证经常失败systemd 的启动顺序如果没理顺服务起来的时候 X 还没准备好客户端连上去就是一片黑。这篇内容把这些环节按我实际操作的顺序拆开讲从会话类型判定、依赖安装、密码文件、手动跑通、systemd 常驻一直到客户端调优和故障排查给的是可以直接照着敲的命令和参数。适合手里有 Ubuntu 桌面机、需要在局域网内远程看屏或者做技术支持的人也适合刚接触 Linux 远程桌面、被黑屏折腾过的新手。1. 方案想清楚再动手为什么轮到 x11vnc1.1 需求边界要的是正在跑的那个桌面不是新开一个远程桌面这件事先得分清楚两种完全不同的需求。第一种是给我一个干净的新桌面多用户场景、服务器上跑图形程序、或者干脆当远程开发机用这种情况 xrdp、VNC 的独立会话模式都合适。第二种是我要看到现在屏幕上到底是什么比如某台机器上已经登录了图形会话有个 GUI 程序卡在弹窗上等人点确定或者需要远程协助现场人员操作这时候新开一个会话毫无意义——你要看的是那个已经存在的 X server。x11vnc 属于第二种。它本身不创建 X server只是 attach 到已有的:0显示上把帧缓冲内容读出来编码后通过 RFB 协议推给客户端。这个特性决定了它的优势和局限都很明确优势是零侵入被控端不需要改动现有登录状态装了就能用局限是它强依赖 X11——纯 Wayland 会话下它看不到东西因为 Wayland 客户端之间天然隔离没有全局帧缓冲可以读。我在选型时一般按下面这个顺序判断先问被控端是不是已经有人登录并保持会话是的话 x11vnc 是首选再问是否需要多用户各自独立桌面是的话换 xrdp 或者 tigervnc 的独立会话模式最后问要不要跨平台、要不要文件传输和打印机重定向需要的话考虑商业方案。绝大多数我要远程看看这台机器的需求落在第一类。1.2 几种主流做法摆在一起比一比光说 x11vnc 好没意义得把它和常见的替代方案放在同一张表里看取舍才清楚。方案连接对象是否依赖 X11多用户独立会话典型适用场景x11vnc已有登录会话:0是必须 Xorg不支持远程查看/协助已登录桌面GNOME 内置屏幕共享当前会话否Wayland 也支持不支持临时协作配置最简单xrdp新建会话否可配 Xorg 后端支持多人各自登录长期使用TigerVNC 独立服务新建虚拟桌面否支持无头服务器跑图形程序各类商业远控当前会话否视产品而定跨公网、需要完整功能从这张表能看出来x11vnc 的位置很窄但很关键。GNOME 内置的屏幕共享在 Ubuntu 24.04 上其实已经能用了走的是 PipeWire 那条链路配置起来比 x11vnc 简单。但它的短板在于授权流程依赖桌面内的弹窗确认一旦桌面锁屏或者没人点确认远程就连不上另外部分老版本客户端对它的编码兼容性一般画面延迟也偏高。我在需要无人值守、开机就能连的场景里还是更愿意用 x11vnc 加 systemd 常驻。注意如果你的机器完全是 Wayland 会话而且你不打算改回 Xorg那么 x11vnc 不是正确工具硬上只会得到黑屏或者 unable to find X server 的报错别在这上面耗时间。1.3 Ubuntu 24.04 带来的变数Wayland 默认与会话判定Ubuntu 从 21.04 起就把 Wayland 设为 GNOME 的默认会话24.04 延续了这个设定。默认登录进去echo $XDG_SESSION_TYPE输出的是wayland。而 x11vnc 只能读 X server 的帧缓冲在 Wayland 会话下它 attach 到的其实是 Xwayland那只是一个给老程序用的兼容层画面里只有 Xwayland 自己的窗口看不到 GNOME 桌面、看不到其他 Wayland 原生应用连上去大概率是一片黑或者只有零星窗口。所以第一件要做的事是把登录会话切到 Xorg。这件事不复杂但有两个前提得说清楚一是切换后整机会走 Xorg 渲染链路日常使用几乎感觉不到差别但极少数依赖 Wayland 特性的场景比如某些触控板手势、分数缩放会有变化二是切换是全局的影响所有登录用户不是只针对你一个人。还有一个容易被忽略的点GDM 登录界面本身也是一个会话greeter它跑在独立的用户下Xauthority 路径和普通用户不一样。默认情况下 x11vnc 连的是已登录用户桌面不是登录界面。如果你的需求是开机还没人登录时就要能连那属于另一套配置需要以 root 身份跑 x11vnc 并指向 greeter 的认证文件风险更高后面第 6 节会提到但不建议作为常规方案。2. 环境准备把会话拉回 Xorg 再装软件2.1 先确认当前会话到底是什么类型动手改任何东西之前先看清楚现状。这一步很多人跳过结果配置完发现黑屏回头再查浪费半小时。最直接的办法是在图形界面里打开终端敲三条命令echo $XDG_SESSION_TYPE loginctl show-session $(loginctl | awk -v u$USER $3u {print $1; exit}) -p Type ps -o cmd -C Xorg第一条输出x11或wayland这是最直观的判据。第二条从 logind 的会话属性里读类型结果和第一条应该一致如果不一致说明环境变量被污染了以 logind 的为准。第三条是辅助判断——如果Xorg进程存在说明至少有一个 X server 在跑在 Wayland 会话下这个进程通常不存在取而代之的是Xwayland。再补一条命令看显示号ls /tmp/.X11-unix/输出通常会有X0代表:0显示存在。x11vnc 的-display参数就是指向这个。如果只有一个X0那-display :0是对的如果还有别的得挑对应你桌面的那个。2.2 切换到 Xorg 会话的两条路径切换方式有两种选哪种取决于你需不需要让每次登录都固定走 Xorg。临时切换用登录界面的齿轮菜单注销回到 GDM 登录页点用户名右下角那个齿轮图标选 Ubuntu on Xorg再输密码登录。这种方式只对当次会话生效重启后又回到默认。适合只是临时用一次、不想改动系统配置的场景。永久切换改 GDM 配置文件sudo sed -i s/^#WaylandEnablefalse/WaylandEnablefalse/ /etc/gdm3/custom.conf grep -n WaylandEnable /etc/gdm3/custom.conf如果配置文件里原本没有WaylandEnable这一行24.04 的默认文件里它可能被注释掉了那就手动补一行到[daemon]段落下[daemon] WaylandEnablefalse改完重启 GDMsudo systemctl restart gdm3注意重启 gdm3 会把你当前的图形会话整个杀掉正在跑的程序会全部退出。别在还有未保存工作的时候执行这条命令先存盘、先退出程序。重启后在登录界面确认齿轮里选的是 Ubuntu on Xorg登录进去再用前面的命令验证一次XDG_SESSION_TYPE应该输出x11。2.3 安装 x11vnc 与配套工具软件安装本身没什么难度但有几个配套包建议一起装上后面调优和排错会用到sudo apt update sudo apt install -y x11vnc net-tools x11-utils x11-xserver-utils x11vnc -versionx11vnc -version会打印版本号和编译时间Ubuntu 24.04 仓库里给的是 0.9.16 这一支功能完整够用。顺带说一句不建议自己去源码编译最新版除非你碰到了仓库版本里的明确 bug——自己编译出来的二进制在 systemd 里跑路径、依赖、库版本全是坑收益不成正比。net-tools提供netstat排查端口监听时比ss直观一点x11-utils里有xdpyinfo可以用来验证 X server 是否能正常访问x11-xserver-utils里有xhost调试权限问题时能用上。这几个包装完不占多少空间。装完之后先别急着跑服务用xdpyinfo做一次连通性验证DISPLAY:0 xdpyinfo | head -n 20能打印出name of display: :0、版本号、屏幕尺寸这些信息说明当前用户有权限访问这个 X server。如果报unable to open display那问题在权限或者DISPLAY变量先解决这个后面 x11vnc 才有戏。3. 从一条命令跑通画面再谈常驻3.1 手动启动命令与每个参数的理由第一次配置不建议直接写 systemd 单元先在终端里手动跑通看清楚输出日志确认客户端能连上再固化。这样一旦出问题改动的影响面最小。我常用的一条启动命令长这样x11vnc -display :0 -auth guess -rfbauth ~/.vnc/passwd \ -rfbport 5900 -localhost -forever -shared \ -noxdamage -repeat -nolookup -nowf参数逐个说清楚因为很多人是抄了命令但不知道每一项在干什么出问题就无从下手。-display :0指定要共享的 X 显示号。前面用ls /tmp/.X11-unix/看到的那个编号就是它。-auth guess让 x11vnc 自己去猜 Xauthority 文件的位置。它会去读 X 进程的命令行参数、检查常见的认证文件路径、查看$XAUTHORITY环境变量。大多数情况下能猜对猜不对就得手动指定下一小节专门讲。-rfbauth ~/.vnc/passwd指定密码文件。x11vnc 支持明文密码参数-passwd但那会把密码暴露在ps输出里任何能登机器的用户都能看到。用密码文件是基本要求。-rfbport 5900指定监听端口。RFB 协议默认端口和显示号有固定对应关系:0对应 5900:1对应 5901公式就是5900 N。你当然可以随便改但保持默认能让客户端少填一个参数。-localhost只监听回环地址。这一条是安全底线意味着 5900 端口只对本机可见外部要连必须走 SSH 隧道或者额外做转发。直接裸奔在 0.0.0.0 上在局域网里也许还能接受但在任何有外网入口的环境里都是自找麻烦。-forever让 x11vnc 在客户端断开后继续监听而不是跟着退出。不加这个参数第一个客户端断开服务就结束了下次连接直接拒绝。-shared允许多个客户端同时连接。单人使用不加也行但加上没坏处多人协作时有用。-noxdamage关闭 XDamage 扩展的使用。XDamage 本来是用来做增量更新、降低带宽的但在某些显卡驱动和桌面组合下会导致画面不刷新、局部花屏。这个参数属于出问题就加、没出问题也可以加的类型代价是带宽略高。-repeat让 x11vnc 自己处理按键重复。不加的话从某些客户端按住方向键不会有连续移动效果得靠客户端本地模拟体验很差。-nolookup跳过对客户端 IP 的反向 DNS 解析。不加的话每次连接都可能卡几秒钟等 DNS 超时尤其在内网 DNS 配置不规范的机器上特别明显。-nowf关闭文件传输功能。x11vnc 的-transferfile之类的文件传输用得少开着只会增加攻击面。不需要就别开。启动之后终端会刷出一大段日志里面会有类似这样的行PORT5900 rfbListenOnTCP6Port: error Address already in use如果看到Address already in use说明 5900 被占了换个端口或者查一下是不是已经跑了一个实例。最后出现The VNC desktop is: hostname:0和PORT5900基本就是起来了。3.2 认证文件Xauthority怎么找-auth guess失败的典型症状是x11vnc 起来了端口也监听了但客户端连上去是黑屏日志里有XOpenDisplay failed或者Xlib: connection to :0.0 refused by server之类。根因是 x11vnc 没找到正确的 Xauthority没通过 X server 的认证自然读不到画面。手动找的办法有这么几个按可靠性排序。第一直接看 X 进程的启动参数ps -o args -C Xorg输出里通常会带-auth /path/to/Xauthority那个路径就是答案。Ubuntu 24.04 上常见的是/run/user/1000/gdm/Xauthority或者用户家目录下的.Xauthority。第二读环境变量echo $XAUTHORITY在已经登录的桌面终端里这个变量一般是有值的直接把它抄进 x11vnc 的-auth参数即可。第三从 logind 拿loginctl show-session $(loginctl | awk -v u$USER $3u {print $1; exit}) -p Type -p Display拿到会话号和显示号再结合/run/user/uid/目录下的内容找。这个目录下每个用户都有里面可能同时存在gdm/Xauthority和.mutter-Xwaylandauth.XXXXXX两种文件。前者是 GDM 拉起 Xorg 时用的认证文件后者是 Wayland 会话下 Xwayland 用的别搞混。找到之后写死到命令里x11vnc -display :0 -auth $XAUTHORITY -rfbauth ~/.vnc/passwd \ -rfbport 5900 -localhost -forever -shared -noxdamage -repeat -nolookup注意Xauthority 文件是会话级的每次重启、每次重新登录都可能换路径尤其是文件名里带随机串的那种。所以写死路径在 systemd 单元里不是好做法除非你确认路径稳定。更稳妥的是在服务启动脚本里动态取$XAUTHORITY或者继续用-auth guess加一个保底的ExecStartPre检测。3.3 密码文件与权限收口密码文件这一步有个细节很多人做错x11vnc -storepasswd默认写到家目录下的.vnc/passwd而且它不会帮你建目录。第一次用的时候得先建目录mkdir -p ~/.vnc chmod 700 ~/.vnc x11vnc -storepasswd执行后它交互式问你要密码输两遍然后问要不要写进文件回y。生成的文件用-rfbauth引用。非交互的方式适合自动化脚本x11vnc -storepasswd 你的密码 ~/.vnc/passwd密码限制在 8 个字符以内RFB 协议 VNC 认证的长度限制超出的部分会被截断也就是你输 12 位密码实际只用了前 8 位这是个很容易踩的认知差。想用更长的密码得换认证方式但那要客户端配合不在常规范围内。权限必须收紧chmod 600 ~/.vnc/passwd ls -l ~/.vnc/passwd输出应该是-rw-------。如果这个文件被同组或者其他用户可读等于把远程桌面密码交出去了。x11vnc -storepasswd生成的密码是经过 3DES 加密的不是明文但对方拿到加密文件一样能用来连你的机器所以权限该收还是要收。密码位数短是个现实问题所以我在所有需要远程的机器上都坚持一条x11vnc 只监听-localhost外部访问一律走 SSH 隧道。密码只是第二道门第一道门是 SSH 的密钥认证。这样即使 VNC 密码只有 8 位整体安全性还是由 SSH 兜着。4. 交给 systemd开机自启与稳定常驻4.1 用户级服务与系统级服务的取舍手动跑通之后要解决的第一个问题是别每次登录都手敲一遍第二个是机器重启后自动起来。这两个需求都指向 systemd但具体用哪种服务类型得看你的使用场景。用户级服务systemctl --user跟着登录会话走用户登录后才启动注销就停。它的好处是天然能拿到$XAUTHORITY这类会话环境变量不需要额外配置坏处是必须在用户登录之后才生效如果机器重启后停在登录界面没人登录服务不会运行。系统级服务systemctl带User参数在系统启动阶段就跑不依赖用户登录。理论上可以更早提供服务但要自己指定DISPLAY和XAUTHORITY而且启动时机如果早于 X server 就绪会启动失败然后靠重启策略兜底。我的实际选择是用户级服务为主系统级服务在明确需要无人登录也要连时才用。大部分远程看一下已登录桌面的需求用户级服务已经完全覆盖配置也简单。下面两小节分别给出可用配置。4.2 一个能落地的用户级 unit 文件创建目录和文件mkdir -p ~/.config/systemd/user vim ~/.config/systemd/user/x11vnc.service内容[Unit] Descriptionx11vnc server sharing the current X11 desktop Aftergraphical-session.target PartOfgraphical-session.target [Service] Typesimple EnvironmentDISPLAY:0 ExecStartPre/bin/sh -c sleep 3 ExecStart/usr/bin/x11vnc -display :0 -auth guess \ -rfbauth %h/.vnc/passwd -rfbport 5900 -localhost \ -forever -shared -noxdamage -repeat -nolookup -nowf Restarton-failure RestartSec5 [Install] WantedBygraphical-session.target几个关键点解释一下。Aftergraphical-session.target保证它在图形会话起来之后再启动。PartOf让会话结束时这个服务也跟着停避免残留。ExecStartPre/bin/sh -c sleep 3是个土办法但很有效。GNOME 的会话目标在 X server 就绪和窗口管理器完全起来之间有个几秒的空窗x11vnc 在这个窗口期启动-auth guess可能拿不到认证文件服务直接失败。加个短暂延迟能显著降低首次启动失败率。比这更优雅的做法是写一个循环检测脚本但对多数人来说没必要。%h是 systemd 的占位符展开成用户家目录。这样单元文件不用写死用户名。Restarton-failure配合RestartSec5让它在出错后自动重试不会因为一次失败就彻底不工作。启用并启动systemctl --user daemon-reload systemctl --user enable --now x11vnc.service systemctl --user status x11vnc.servicestatus输出里Active: active (running)就对了。想看更细的日志用journalctl --user -u x11vnc.service -f如果希望用户没登录时服务也能跑比如远程重启后立即能连需要开 lingersudo loginctl enable-linger $USER但要注意linger 只保证用户的服务管理器常驻不保证图形会话存在。你的图形会话还是得有人登录或者配置自动登录才有:0显示。所以真有这个需求得配合 GDM 的自动登录一起配置那是另一个话题。4.3 系统级服务的写法与启动顺序明确需要系统级服务时配置文件放在/etc/systemd/system/x11vnc.service[Unit] Descriptionx11vnc server for display :0 Afterdisplay-manager.service network-online.target Wantsdisplay-manager.service [Service] Typesimple User你的用户名 EnvironmentDISPLAY:0 EnvironmentXAUTHORITY/run/user/1000/gdm/Xauthority ExecStart/usr/bin/x11vnc -display :0 -auth %E{XAUTHORITY} \ -rfbauth /home/你的用户名/.vnc/passwd -rfbport 5900 -localhost \ -forever -shared -noxdamage -repeat -nolookup -nowf Restartalways RestartSec10 [Install] WantedBymulti-user.target这里的难点全在XAUTHORITY。写死/run/user/1000/gdm/Xauthority只在特定环境下成立——GDM 拉起 Xorg 时的确会把认证文件放在那儿但路径里的 uid 和文件名可能变。更稳的写法是用一个包装脚本在脚本里动态探测#!/bin/bash AUTH for f in /run/user/$(id -u)/gdm/Xauthority \ /run/user/$(id -u)/.mutter-Xwaylandauth.* \ $HOME/.Xauthority; do if [ -f $f ]; then AUTH$f; break; fi done [ -z $AUTH ] { echo no Xauthority found; exit 1; } exec /usr/bin/x11vnc -display :0 -auth $AUTH \ -rfbauth /home/你的用户名/.vnc/passwd -rfbport 5900 -localhost \ -forever -shared -noxdamage -repeat -nolookup -nowf把这个脚本存成/usr/local/bin/x11vnc-start.shchmod 755然后ExecStart/usr/local/bin/x11vnc-start.sh。多一层包装换来的是环境变化时不用改单元文件。参数与启动时机对照整理成表方便查阅配置项用户级服务系统级服务触发目标graphical-session.targetmulti-user.target依赖顺序Aftergraphical-session.targetAfterdisplay-manager.service环境变量自动继承会话环境需手动指定 DISPLAY/XAUTHORITY无人登录时可用否是但仍需 X server 存在调试方式journalctl --user -u x11vncjournalctl -u x11vnc装完别忘sudo systemctl daemon-reload再enable --now忘了 daemon-reload 会出现改了但没生效的假象。5. 客户端接入与画质调优5.1 客户端选型与基础连接服务端跑起来了客户端这边其实选择不多常用的就那几个。Linux 桌面自带的 Remmina 是最省事的Ubuntu 24.04 上装一下就有sudo apt install -y remmina remmina-plugin-vnc新建连接时协议选 VNC地址填127.0.0.1:5900走隧道的情况或者内网 IP直接连的情况用户名留空——x11vnc 的 VNC 认证只用密码不区分用户名。颜色深度选 24 位真彩质量按网络情况调。TigerVNC 的客户端vncviewer也常用命令行参数更细适合脚本化或者需要精确控制的场景vncviewer -Shared -ViewOnly0 127.0.0.1::5900注意::5900是双冒号表示直接指定端口单冒号后跟的是显示号。这个语法坑过不少人写成单冒号程序会去算5900 0结果一样但写127.0.0.1:1就变成连 5901 了。RealVNC Viewer 体验也不错剪贴板和缩放做得顺滑缺点是免费版功能有阉割。5.2 画质与带宽的折中怎么算VNC 的带宽不是线性增长的理解它的更新机制才能给出合理的参数。RFB 协议的核心是只传变化的区域屏幕静止时几乎不传数据有变化时按矩形脏区推送。所以真正决定带宽的是变化频率和变化面积不是分辨率本身。粗略算一笔账1920×1080 的 24 位色一屏原始数据是 1920×1080×3 ≈ 6.2 MB。ZRLE 编码在桌面上典型的压缩比是 5:1 到 15:1取中间值 10:1一屏全刷约 620 KB。如果每秒全屏刷新 10 次就是 6.2 MB/s折合 50 Mbps——这显然不现实。但实际使用中很少全屏刷新拖动窗口、滚动网页这类操作涉及的区域通常占总面积的 10%~30%折算下来 5~15 Mbps 是常见水平局域网千兆完全不是问题。真正需要调参的是跨网段或者 Wi-Fi 场景下参数取值范围作用我的建议-compresslevel0-9压缩强度越高越省带宽越吃 CPU局域网 0-2跨网段 6-9-quality0-9JPEG 类编码的画质文字办公 6-7看图 8-9-threads整数多线程编码多核机器可加单核别加-ncache0 或像素数客户端像素缓存一般填 0容易引发黑屏-norc无不读配置文件排查参数冲突时用-compresslevel和-quality只对支持对应编码的客户端生效。Remmina 和 TigerVNC 都支持 ZRLE 和 Tight所以这两个参数是管用的如果你的客户端只支持原始 Raw 编码加什么参数都没用带宽照旧。-ncache是个历史遗留的优化把像素缓存在客户端减少重传但它和某些客户端配合时会导致画面撕裂或者黑屏我在生产环境里一律关掉。5.3 走 SSH 端口转发别把 5900 直接摊在网上即使-localhost已经限制了监听地址想要从另一台机器连过来还是需要一个通道。最稳妥的做法是 SSH 本地端口转发ssh -N -L 5900:127.0.0.1:5900 用户名192.168.1.50这条命令的意思是在本地开 5900 端口所有连到本地 5900 的流量通过 SSH 隧道转发到远端机器的 127.0.0.1:5900。-N表示不执行远程命令只做转发。然后客户端连127.0.0.1:5900就行看起来像连本机实际数据走的是加密隧道。服务端的-localhost和这条隧道是配套的服务端口不对外隧道负责把流量安全地带进来。如果想省掉每次敲命令写进~/.ssh/configHost office-pc HostName 192.168.1.50 User 用户名 LocalForward 5900 127.0.0.1:5900 ServerAliveInterval 30以后ssh office-pc建立连接的同时隧道就通了直接开客户端连本地 5900。ServerAliveInterval 30是保活防止长时间不动被中间设备掐断。注意端口转发里的127.0.0.1是站在远端机器的视角写的指向远端自己的回环地址。写成远端的局域网 IP 会让转发绕一圈而且如果服务端只监听-localhost那个 IP 根本没监听转发会失败。5.4 防火墙规则与监听确认如果确实需要在局域网内直连比如同一网段的几台机器互相看屏那就得放开防火墙但范围要收窄。Ubuntu 默认用 ufwsudo ufw allow from 192.168.1.0/24 to any port 5900 proto tcp comment vnc lan sudo ufw status numbered只允许特定网段不要用ufw allow 5900那等于对所有来源开放。改完规则用另一台机器nc -vz 192.168.1.50 5900验证端口可达再开客户端连。监听状态确认用ss -tlnp | grep 5900输出里Local Address:Port应该是127.0.0.1:5900配了-localhost或者0.0.0.0:5900。看到0.0.0.0而你没打算对外暴露就说明-localhost没生效回去检查服务参数。6. 常见问题与排查实录6.1 黑屏、灰屏、只有壁纸没有窗口这是最高频的问题表现形式是客户端连上了、认证也过了但画面是纯黑或者只有壁纸桌面图标和窗口全都看不到。根因基本可以归到三类。第一类是会话类型不对——服务端其实是 Wayland 会话x11vnc attach 到 Xwayland 上只能看到 Xwayland 应用。验证方法是在服务端终端看echo $XDG_SESSION_TYPE是wayland就按第 2 节的方法切 Xorg。第二类是认证文件错了但错得刚好能过。x11vnc 用了一个能打开 display 但指向不同 screen 的认证文件结果读到的是空区域。这种情况看日志最准启动时加-verbose会打印它实际用的XAUTHORITYx11vnc -display :0 -auth guess -verbose -rfbauth ~/.vnc/passwd日志里找Xauthority那几行确认路径和$XAUTHORITY一致。第三类是 XDamage 或者合成器的问题。GNOME 的窗口管理器 mutter 开了合成某些驱动下 x11vnc 读不到合成后的画面。加-noxdamage通常能解决还不行再试-noxrecordx11vnc -display :0 -auth guess -noxdamage -noxrecord -rfbauth ~/.vnc/passwd如果连壁纸都没有、全黑还有一种可能是屏幕处于 DPMS 关闭状态显示器休眠。x11vnc 有-forcedpms参数可以强制唤醒但更稳的做法是在系统设置里把自动息屏关掉或者装caffeine之类的工具做抑制。6.2 认证失败与密码文件问题报错信息通常长这样Xlib: connection to :0.0 refused by server Xlib: No protocol specified前一条是 X server 层面的认证失败说明 Xauthority 不对后一条是 x11vnc 自身和 X 通信被拒同样指向认证。排查顺序先在服务端用同一个用户跑DISPLAY:0 xdpyinfo能通说明权限没问题问题在 x11vnc 拿的认证文件不能通说明当前用户根本无权访问这个 X server可能是用 sudo 切了用户或者会话属于另一个账号。VNC 密码错误的表现不同是客户端提示Authentication failure或password incorrect。常见原因是密码超过 8 位被截断你在客户端输了完整密码反而不对——试前 8 位。另一个原因是密码文件权限不对或者路径写错服务端日志里会有rfbauth failed之类的记录。还有一种隐蔽情况之前跑过一个实例没退干净新实例启动失败但 systemd 显示 active。检查ps aux | grep x11vnc ss -tlnp | grep 5900两个都看一下有残留进程就kill掉再重启服务。6.3 键盘、剪贴板与输入法键盘出问题的典型症状是按下的键没反应、方向键不连续、符号键错位。前两个是-repeat参数没加第三个通常是键盘布局不匹配。符号错位的情况x11vnc 有个-xkb参数用于处理 XKEYBOARD 扩展在部分环境下能修正映射x11vnc -xkb -repeat -display :0 ...如果还是错检查服务端的键盘布局设置setxkbmap -query确认 layout 是us还是cn客户端那边也要设成一致。有些客户端比如老版本 Remmina在连接时会强制用客户端本地的布局导致服务端布局被覆盖这种情况在客户端设置里把使用客户端键盘布局关掉。剪贴板同步依赖服务端的剪贴板管理器。x11vnc 本身会尝试同步 PRIMARY 和 CLIPBOARD 两个选择区但在 GNOME 下有时不生效。补装xclip和autocutsel能改善sudo apt install -y xclip autocutsel autocutsel -selection PRIMARY -fork autocutsel -selection CLIPBOARD -fork这两条命令让两个选择区保持一致双向复制粘贴基本就通了。中文输入法在远程端一般能用但如果服务端用的是 fcitx5 且客户端输入时出现候选框位置错乱那是输入法自己的窗口定位问题跟 x11vnc 关系不大改用客户端本地输入再粘贴过去更省事。6.4 卡顿、断连与画面延迟卡顿的排查要分清楚是网络问题还是服务端渲染问题。判断方法在客户端看画面静止时是否流畅应该完全不耗带宽如果静止时也卡那是编码或者客户端渲染的问题只有操作时卡那是带宽或者延迟问题。服务端这边能做的优化有限主要是关掉不必要的特性x11vnc -display :0 -auth guess -rfbauth ~/.vnc/passwd \ -noxdamage -repeat -nolookup -nowf -noscrollcopyrect \ -compresslevel 2 -quality 7-noscrollcopyrect关掉滚动优化在某些客户端上反而更稳。-compresslevel 2在局域网里足够CPU 占用低。网络这边的优化优先用有线Wi-Fi 下 2.4G 频段基本没法用5G 也要看信号质量。SSH 隧道本身有加密开销但现代 CPU 上 AES 加速后影响很小不是瓶颈。真正影响大的是 RTT跨城市连接即使带宽充足操作延迟也会到 50ms 以上鼠标跟手性明显下降这是物理距离决定的调参解决不了。断连问题看日志journalctl --user -u x11vnc.service -n 100 --no-pager常见原因是服务端的 X 会话重启比如用户注销又登录导致 x11vnc 失去连接。这种情况下Restarton-failure会把它拉起来但会有几秒中断。要彻底避免得让服务跟着会话走也就是用户级服务加PartOfgraphical-session.target的配置。6.5 排查速查表把前面这些症状和处置方式整理成表出问题时按图索骥能省不少时间。症状最可能原因处置动作客户端连接被拒服务未启动或端口被占systemctl --user statusss -tlnp | grep 5900连上后纯黑屏会话是 Wayland切 Xorg 会话后重试只有壁纸无窗口Xauthority 不对-verbose看日志手动指定-auth认证失败密码超 8 位或文件权限试前 8 位chmod 600画面局部花屏XDamage 兼容问题加-noxdamage按住方向键不动缺按键重复处理加-repeat连接卡数秒才出画面反向 DNS 超时加-nolookup服务开机不自启未 enable 或 linger 未开systemctl --user enableloginctl enable-linger服务起来就退出X 会话未就绪加ExecStartPre延迟或改启动目标剪贴板不通选择区不同步装autocutsel并 fork7. 长期维护与几条实操经验7.1 权限最小化与暴露面控制x11vnc 本质上是一个把桌面完整交给对方的服务连上之后对方能看到你屏幕上的所有内容、能操作你的鼠标键盘权限等同于坐在机器前。所以能收的口子都要收。监听地址坚持-localhost这是第一道。SSH 隧道是第二道密钥认证比密码强得多。VNC 密码是第三道8 位虽然不长但配合前两道已经够用。文件传输用-nowf关掉少一个功能少一份风险。如果机器上有多人使用用户级服务比系统级更合适因为只有会话所有者能启动和停止它。日志里偶尔会看到陌生 IP 尝试连接说明端口暴露了。定期ss -tlnp看一眼监听状态发现0.0.0.0:5900就立刻改回-localhost。7.2 升级与桌面栈变化的应对Ubuntu 每次大版本升级桌面栈都可能动。24.04 到 26.04 之间GNOME 版本、GDM 配置路径、Xorg 是否还默认提供这些都可能变。我的做法是在升级前把当前可用的完整命令和 unit 文件备份到/root/backup/或者个人的 dotfiles 仓库里升级后直接对比差异。具体要备份的东西~/.config/systemd/user/x11vnc.service、~/.vnc/passwd、/etc/gdm3/custom.conf、以及那条手动启动命令。这四个东西凑齐换台机器十分钟就能重建环境。升级后第一件事验证x11vnc -version和DISPLAY:0 xdpyinfo两个都正常再启服务。如果xdpyinfo报错但图形界面正常多半是 Xauthority 路径变了按 3.2 节的方法重新找一遍。7.3 我个人踩过的几个坑第一个坑是早期图省事把-auth guess去掉、直接用-auth /home/user/.Xauthority结果某次系统更新后这个文件不存在了Ubuntu 把认证文件挪到了/run/user/1000/下服务静默失败systemctl status显示inactive (dead)日志里只有一行XOpenDisplay failed。从那以后我写 unit 文件都留一个ExecStartPre做前置检查路径不通就直接报错退出而不是让服务处于半死不活的状态。第二个坑是密码长度。给人配环境时设了一个 10 位密码客户端死活连不上两边都以为是网络问题折腾了四十分钟才想起来 RFB 协议只认前 8 位。现在我的做法是密码统一设 8 位复杂度和可靠性之间找个平衡安全性靠 SSH 隧道补。第三个坑是 systemd 的启动顺序。用户级服务配了Aftergraphical-session.target但 GNOME 的会话目标在systemctl --user list-units里有时显示 inactive服务跟着不启动。根因是 GNOME 的graphical-session.target需要systemd-oomd或者相关组件触发纯命令行登录的情况下它根本不会 active。解决方式是改成WantedBydefault.target配合ExecStartPre里的循环等待虽然不够正统但实际最稳。第四个坑是分辨率变化。笔记本外接显示器拔插之后X 的屏幕尺寸变了x11vnc 还按老尺寸推送客户端看到的画面会被裁掉一块。这种情况重启一下服务就好或者加-noxinerama让它按单个屏幕处理。这不是 x11vnc 的 bug是 X RandR 动态调整后服务端没有自动跟随。最后一个经验是关于要不要开机自启这件事。如果这台机器只是偶尔需要远程看一眼我反而不建议配成常驻服务——常驻意味着攻击面常驻而且 systemd 拉起失败时排查成本更高。更轻量的做法是写一个别名或者小脚本需要的时候 SSH 进去执行一下用完就退。真正需要 7×24 可连的场景比如远程值守的工作站再上 systemd 常驻并且把日志、重启策略、监控都配齐。配好之后我一直会做一件事拿另一台机器模拟一次完整流程从 SSH 隧道建立、客户端连上、复制粘贴、切窗口、断线重连全部走一遍。这套流程跑通了才算这台机器真的可以远程。光看服务状态是 active 就交付后面大概率还要被叫回来一次。