最早动这个念头,是因为我人在外地,却需要操作实验室里那台装着Ubuntu 20.04桌面的机器。旁边还坐着一位同事,他随时要看我屏幕上的运行结果,我不能另开一个独立会话把他晾在一边。试过TeamViewer、向日葵、XRDP,体验都不算顺:商业软件在Linux下动不动掉线,XRDP默认又会新建一个和物理桌面完全无关的虚拟会话。最后换到X11VNC,问题才算真正解决。这篇就把我在Ubuntu 20.04 Desktop上配置X11VNC远程桌面的完整过程写清楚——从安装到自启动、从参数含义到安全加固、再到实际排错,适合需要在局域网远程控制Linux桌面、或者在外面通过跳板机连回办公电脑的人参考。
1. 为什么偏偏选X11VNC:本地会话与虚拟会话的本质差异
1.1 先搞清楚Linux远程桌面的两条技术路线
Linux下的远程桌面方案看着很多,但底层逻辑其实就两条。一类是“另起炉灶”,在后台创建一个全新的、和物理桌面独立的图形会话,比如XRDP、TigerVNC Server、X2Go都是这个思路。你远程连上去,看到的是一套干干净净的新桌面,和坐在机器前面的人看到的画面完全无关。另一类是“现场镜像”,直接附加到当前正在运行的X11显示服务上,把物理屏幕上已经存在的画面实时转发给远端,X11VNC就是这类方案的代表。
这两条路线没有绝对的优劣,但选错会很痛苦。如果你只是一个人安安静静地远程办公,独立会话反而更舒服,因为它不会打扰占用物理桌面的人。但如果机器旁边还坐着别人,或者你远程操作的软件依赖当前物理会话里的显卡、加密狗、特殊显示环境,独立会话就麻烦了——远处的人看到的和你本地看到的东西对不上,协作时很容易一脸懵。
X11VNC是一个VNC服务端,但它不启动任何新的桌面进程,只是挂在你已有的X11显示服务上,把当前的帧缓冲内容通过VNC协议推送给客户端。这个过程有一个非常关键的属性:所见即所得。你在远程看到的,就是物理屏幕上正在显示的内容,包括已经打开的窗口、正在跑的进度条、弹窗和警告。
1.2 主流方案横向对比
我在Ubuntu 20.04上实际用过一轮,把主要方案的特性整理成了下面这张表,方便直接对照。
| 方案 | 会话逻辑 | Ubuntu 20.04适配 | 资源占用 | 适合场景 |
|---|---|---|---|---|
| X11VNC | 镜像现有X11会话 | 好,apt直接安装,稳定 | 中低 | 远程操作物理桌面、远程协助、演示 |
| TigerVNC Server | 独立Xvnc虚拟会话 | 可以,但需自行配置桌面管理器 | 中 | 无头服务器跑轻量桌面 |
| XRDP | 默认新建独立Xorg会话 | 可装,但和物理桌面不同步 | 中高 | Windows RDP客户端直连Linux |
| TeamViewer/向日葵等 | 自带会话管理 | 可用,但偶发掉线、响应慢 | 较高 | 跨平台临时远程协助 |
这里要特别提醒:XRDP虽然名字里带个RDP,看着很亲切,但它在Ubuntu 20.04上默认行为和Windows的远程桌面有本质区别。Windows的RDP可以直接接管当前桌面会话,而Linux的XRDP通常给你的是一个新会话。如果你的需求是“远程看到和本地一模一样的桌面”,XRDP不是你要找的东西。
1.3 为什么不是TigerVNC
TigerVNC是Linux上很常见的VNC服务端,但它和X11VNC的适用场景不一样。TigerVNC Server在无显示器、无图形登录环境的服务器上更顺手,它负责把远程桌面会话跑起来;而X11VNC的强项是——这台机器已经有人登录了图形桌面,你想把当前这个会话共享出去。Ubuntu 20.04桌面版最常见的状态恰恰是后者:本地用户登录了GNOME桌面,你需要远程接管它。
所以我的结论很简单:已经在跑物理桌面的机器,远程控制首选X11VNC;没有显示器的服务器,才需要考虑启动独立会话的方案。认清这个区别,后面所有配置都不会走偏。
2. 安装之前先确认会话类型:Wayland还是Xorg决定成败
2.1 这一步不做,后面大概率黑屏
Ubuntu 20.04虽然默认登录会话还是Xorg,但系统已经在推广Wayland。如果当前用户登录的是Wayland会话,X11VNC会直接连不上,或者连上后只有一片灰,因为Wayland本身不暴露X11的帧缓冲接口,x11vnc根本没地方挂载。
先花十秒确认当前会话类型:
echo $XDG_SESSION_TYPE loginctl show-session $(loginctl | grep $(whoami) | awk '{print $1}') -p Type输出应该是x11。如果看到的是wayland,请在登录界面点右上角齿轮图标,切换到“Ubuntu on Xorg”再登录。这个操作只需要做一次,后续默认都会走Xorg。
另外,用NVIDIA闭源驱动的机器,Wayland会话下的VNC体验更差,不仅黑屏,偶尔还会把本地物理屏幕搞花。所以我的建议是:这台机器要长期做远程控制,就直接固定在Xorg会话。
2.2 安装x11vnc,版本确认一下
Ubuntu 20.04的软件源里x11vnc版本是0.9.16,够用且稳定,不需要从源码编译。
sudo apt update sudo apt install -y x11vnc x11vnc -version能看到版本号就没有问题。如果你想用后续文章会提到的SSL加密特性,需要确认包是否编译了SSL支持。仓库里的版本一般都有,不过我最常用的还是SSH隧道方案,下面会细说。
2.3 设置独立的VNC密码文件
VNC密码和系统登录密码是两回事,建议单独设置一个只有远程连接用的复杂口令。
sudo mkdir -p /etc/x11vnc sudo x11vnc -storepasswd '你的VNC密码' /etc/x11vnc/passwd sudo chmod 600 /etc/x11vnc/passwd这里有个大多数人不知道的细节:传统VNC协议在认证阶段只比较密码的前8个字符。也就是说,你设置了一个20位的长密码,实际生效的可能是前8位。这不是x11vnc的bug,而是RFB协议老底子留下的限制。所以不要把VNC密码当作唯一防线,配合后续的防火墙或SSH隧道才是正确姿势。
3. 一条启动命令、一个systemd服务:让X11VNC开机就在
3.1 先手工启动一次,把基础功能跑通
不要一上来就写systemd服务,先手工启动一次,确认命令本身没问题。
sudo x11vnc -display :0 -auth guess -forever -loop -noxdamage -repeat \ -rfbauth /etc/x11vnc/passwd -rfbport 5900 -shared -o /var/log/x11vnc.log终端里没有报错后,用任意VNC客户端连一次。如果能直接看到桌面,再进行下一步。如果连不上,优先看日志最后几行:
sudo tail -20 /var/log/x11vnc.log最常见的错误是XOpenDisplay failed,说明x11vnc找不到X显示服务,要么-display参数不对,要么-auth没有指对授权文件。
3.2 逐个参数搞清楚,配置才不会改错
很多教程直接甩一条命令让你复制,一旦出问题就抓瞎。这里把关键参数都拆开说明。
-display :0:告诉x11vnc要挂到哪个X显示上。Ubuntu桌面默认第一个图形会话是:0,基本不用改。-auth guess:自动猜测Xauthority文件的路径。这条不加,root都救不了你,x11vnc会因为无法通过X授权认证而拒绝工作。-forever:客户端断开后进程不退出,继续保持监听状态,等下一次连接。-loop:如果显示连接失败或者进程异常退出,自动重试。开机后桌面环境还没起来时特别有用。-noxdamage:禁用X DAMAGE扩展。NVIDIA闭源驱动下我强烈建议直接加上,否则远程画面很容易出现残影、局部不刷新。-repeat:允许键盘重复事件。不加的话,你远程按住方向键或退格键会发现毫无反应。-rfbauth:指定VNC密码文件。-rfbport 5900:监听端口,默认就是5900。-shared:允许多个VNC客户端同时连接。团队协作时很有用,代价是带宽会分摊。-o /var/log/x11vnc.log:写日志。
3.3 用systemd管住它,而不是写进autostart
为什么不推荐把启动命令写进~/.bashrc或者桌面环境的“启动应用程序”?因为autostart只在用户登录后才会触发,而且用户退出登录、桌面进程结束,x11vnc也会跟着死掉。systemd服务则可以在开机后立刻启动,进程独立于你的登录会话,崩溃了还能自动拉起来。
创建服务文件:
sudo vim /etc/systemd/system/x11vnc.service[Unit] Description=X11VNC Remote Desktop Server After=graphical.target [Service] Type=simple Environment=DISPLAY=:0 ExecStart=/usr/bin/x11vnc -display :0 -auth guess -forever -loop -noxdamage -repeat -rfbauth /etc/x11vnc/passwd -rfbport 5900 -shared -o /var/log/x11vnc.log Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target然后启用:
sudo systemctl daemon-reload sudo systemctl enable --now x11vnc systemctl status x11vnc这里有个实践经验:让x11vnc以root身份跑最省事。因为root能读取所有用户的Xauthority文件,-auth guess基本都能猜中。如果换成普通用户运行,就要额外处理权限,很容易踩坑。
3.4 GDM登录界面能不能远程连?
很多人配置完成后发现一个尴尬问题:开机后停在登录界面,远程连过去要么黑屏,要么连接被拒绝。这是因为GDM登录界面运行在独立的显示服务器上,而x11vnc挂载的是用户桌面:0,在还没有用户登录时,:0上根本没有可共享的桌面会话。
如果你确实需要重启后远程直接可用,可以设置自动登录。在Ubuntu 20.04的“设置 – 用户”里打开自动登录,或者修改/etc/gdm3/custom.conf:
[daemon] AutomaticLoginEnable=true AutomaticLogin=你的用户名注意,自动登录会带来安全风险——任何人物理接触这台机器都能直接进入桌面。这个取舍要自己权衡,我个人只建议在实验室、机房等可信环境里使用。
4. 别让5900端口裸奔:防火墙与SSH隧道两种加固姿势
4.1 局域网内的最小防火墙规则
VNC协议本身没有加密,密码又是老式的8位DES,直接把5900端口暴露到整个网络里并不安全。如果你只是在同一个局域网里用,最小限度也要用UFW限制来源IP。
sudo ufw allow OpenSSH sudo ufw allow from 192.168.1.0/24 to any port 5900 proto tcp sudo ufw enable第一行先放行SSH非常重要。不这么做的话,一旦开启UFW,现有SSH连接会立刻中断,远程就再也回不去了。
如果不需要其他网段访问,那就不要加更宽松的规则。Ubuntu默认防火墙没启用时,5900端口会监听在所有网卡上,这等于告诉同一网络里的所有人“这里有VNC端口可以试”。
4.2 我最推荐的方案:SSH隧道加-localhost
如果条件允许,我最推荐的组合是把x11vnc限制为只监听本机回环地址,然后通过SSH隧道访问。这样一来,5900端口根本不会暴露在网络上,VNC流量也被SSH加密了,即使VNC密码偏弱,风险也可控。
修改systemd服务文件,在ExecStart里加上-localhost参数:
ExecStart=/usr/bin/x11vnc -display :0 -auth guess -forever -loop -noxdamage -repeat -rfbauth /etc/x11vnc/passwd -rfbport 5900 -shared -localhost -o /var/log/x11vnc.log然后在Windows客户端机器上建立SSH隧道:
ssh -L 5900:localhost:5900 用户名@Ubuntu主机IPVNC客户端里连接localhost:5900即可。
如果你在公司或者跨网络环境,可以先把SSH端口转发到一台能访问目标机的跳板机上,再做本地转发,思路是一样的。走公网时绝对不要直接把5900映射出去,我见过太多因为裸奔VNC导致桌面被控制、数据被翻的案例了。
4.3 x11vnc其实还有SSL选项
如果你不想用SSH隧道,x11vnc还支持-ssl参数开启TLS加密,Ubuntu仓库版一般编译了SSL支持。生成自签名证书后用-ssl启动,VNC客户端连接时可以勾选“接受自签名证书”。但实测下来,Windows上的RealVNC Viewer对自签名证书的处理很麻烦,需要手动信任,操作成本比SSH隧道高不少。所以我个人还是更喜欢-localhost + SSH隧道的组合,简单、可靠、生态好。
5. 客户端连接实测:黑屏、断连、卡顿的排查链路
5.1 常用的VNC客户端怎么选
不同平台上我习惯的客户端不太一样。
- Windows:RealVNC Viewer,兼容性好,解码效率也高;TigerVNC Viewer也可以,更轻量。
- macOS:直接用Finder的“前往 – 连接服务器”,输入
vnc://IP:5900就能连,不用装额外软件。 - Linux桌面:Remmina自带的VNC插件挺好用,Ubuntu上装一下就有了。
连接时填IP:5900,敲VNC密码就能看到桌面。如果是SSH隧道模式,填localhost:5900。
5.2 黑屏、灰屏、连接被拒绝:我遇到最多的三种情况
先后按这几个方向排查:
- 连接被拒绝:先看系统服务是否还活着,
systemctl status x11vnc,然后确认防火墙没有拦,sudo ufw status。 - 能连上但黑屏:优先怀疑会话类型。确认远程机当前是Xorg会话,不是Wayland。其次考虑显卡驱动问题,给启动命令补上
-noxdamage。如果显示器休眠了,有些显卡会把输出停掉,可以先本地唤醒屏幕再连。 - 连上后立刻断开:打开
/var/log/x11vnc.log看日志,基本都能看到线索。最常见的是密码文件权限不对,或者x11vnc没有权限读Xauthority。检查/etc/x11vnc/passwd是不是600权限、服务是不是root跑的。
5.3 远程卡顿、刷新不全,怎么优化
VNC协议是基于屏幕区域按需更新的,不像RDP那样针对视频和动画做专门优化,所以在网络一般的情况下,卡顿会很明显。我的习惯做法是几个参数组合使用。
- 服务端加
-solid,把桌面背景设成纯色。壁纸是大面积反复传输的元凶,纯色背景能省很多流量。 - 服务端加
-scale 0.75,把画面按比例缩小后再传输,带宽立刻下降,适合跨网络办公。 - 客户端把颜色深度调到16位甚至8位,颜色失真换来流畅度,只看文档完全够用。
- 别在VNC里硬开着高帧率的动画、视频,这不是VNC擅长的场景。
5.4 键盘乱码和鼠标偏移
远程输入时字符不对,多半是客户端键盘布局和服务端不一致。把客户端键盘布局临时切到US English,或者在远程终端里执行setxkbmap us,基本能解决。鼠标点击位置偏移则出现在客户端显示比例和服务端分辨率不匹配的时候,把VNC客户端的缩放设为1:1或者Adapt模式即可。
5.5 锁屏界面怎么远程解锁
GNOME锁屏后,VNC客户端连上去会看到锁屏界面。这时候输入VNC密码没有用,需要在锁屏界面输入系统用户的登录密码才能解锁。这不是配置问题,是安全设计,习惯就好。
6. 进阶调优:画质、缓存、多显示器的取舍
6.1 -ncache能在滚动长页面时救你一命
x11vnc有个特色参数-ncache,可以在客户端本地多缓存几帧画面。滚网页、翻代码的时候,画面更新会明显流畅,因为重复出现的屏幕内容不用反复传。我一般设成10:
-ncache 10需要提醒的是,这个功能依赖客户端对x11vnc扩展编码的支持。RealVNC Viewer配合得很好,但部分开源客户端可能无效。如果用了-ncache后画面出现奇怪的色块,可以改小数值或者去掉。
6.2 多显示器只共享主屏
如果远程机器接了多台显示器,x11vnc默认会把多个屏幕拼成一整块大画布推给客户端。但有时你只想让远端看主屏,这时候用-clip指定捕获区域:
-clip 1920x1080+0+0+0+0是主屏左上角坐标。这个参数在做临时共享、演示场景时非常实用,避免对方看到一堆用不上的屏幕内容。
6.3 日常运维三板斧
用了很长时间x11vnc之后,我养成了固定排查习惯,三个命令覆盖日常运维:
systemctl status x11vnc sudo tail -f /var/log/x11vnc.log sudo ss -tlnp | grep 5900服务状态、实时日志、端口监听,这三个信息基本能定位绝大多数问题。如果哪天远程突然连不上了,第一件事就是打开日志看,而不是直接重启服务——日志里往往写着真正的原因,重启只会掩盖问题。
6.4 假如还是想用RDP客户端
我知道很多人习惯了Windows自带的远程桌面,到了Linux上也希望用RDP。Ubuntu 20.04装XRDP确实能用,但请记住前面说的会话逻辑:默认创建的独立会话和物理桌面不同步。如果你只是想远程开一个Linux桌面界面,XRDP是可以的;如果你要的是“远程看到和本地屏幕完全一样的东西”,那就回来用X11VNC。这两个需求不要混为一谈,这也是我在开篇花那么大篇幅讲技术路线差异的原因。
要说个人体会,最有价值的一条经验是:VNC这类方案的重心永远在于“会话模型选对”,而不是那一堆参数。先把“我是要接管现有桌面还是新建独立桌面”想清楚,再动手配置,基本不会走弯路。x11vnc参数再多,绕不开这个核心判断。