ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Ubuntu 20.04源码编译TigerVNC 1.12.0并配置systemd开机自启

Ubuntu 20.04源码编译TigerVNC 1.12.0并配置systemd开机自启 1. 项目概述与核心价值最近在折腾一台老旧的服务器系统是Ubuntu 20.04 LTS想把它变成一个可以远程图形化操作的开发机。直接物理操作太麻烦SSH虽然快但有些图形界面的调试和配置工作还是离不开桌面环境。VNC自然就成了首选方案。市面上VNC服务端不少TigerVNC以其高性能和活跃的维护脱颖而出尤其是它的1.12.0版本在安全性和渲染效率上都有不少改进。但问题来了Ubuntu 20.04官方源里的TigerVNC版本比较老直接apt install装不上最新的。更关键的是我希望这个VNC服务能像系统服务一样开机自启稳定运行而不是每次重启都得手动敲命令。这个需求很典型你有一台Ubuntu服务器或台式机可能放在机房或者作为家庭服务器你需要一个可靠的远程桌面方案来管理它。网上教程很多但往往只讲安装或者只讲配置把开机启动、权限管理、故障排查这些真正影响日常使用的“坑”给略过了。今天我就把从源码编译安装TigerVNC 1.12.0到配置成systemd服务实现开机自启的完整过程连同我踩过的坑和解决方案一次性讲清楚。无论你是运维工程师、开发者还是单纯的Linux爱好者这篇手把手的指南都能帮你搭建一个稳固的远程图形工作环境。2. 环境准备与依赖梳理在动手之前我们必须把“地基”打牢。编译安装软件尤其是像TigerVNC这样涉及图形系统、网络和安全模块的软件对系统环境有明确要求。盲目开始很容易在编译中途报错回头再补依赖反而更耗时。2.1 系统更新与基础工具首先确保你的Ubuntu 20.04系统是最新的。这不是废话系统更新不仅能获取安全补丁还能确保基础库的一致性避免一些因版本滞后导致的诡异链接错误。sudo apt update sudo apt upgrade -y更新完成后安装编译所需的“工具箱”编译器、构建工具和必要的开发库。build-essential套件是必须的它包含了gcc, g, make等核心工具。sudo apt install -y build-essential2.2 TigerVNC编译依赖详解TigerVNC的依赖项比较多我们可以根据其源码中的说明文档通常是README或CMakeLists.txt来归纳。核心依赖可以分为几大类X Window系统开发库TigerVNC是一个VNC服务器它需要与X Server交互捕获屏幕图像。因此X11相关的开发包必不可少。图形与字体库用于处理图形渲染和字体显示例如libjpeg用于JPEG压缩、libpng等。安全与加密库现代VNC通信必须加密所以需要GnuTLS或OpenSSL。其他工具库如pam用于用户认证、gettext国际化等。一个比较稳妥的安装命令如下它基本覆盖了编译TigerVNC 1.12.0所需的主要依赖sudo apt install -y cmake libjpeg-turbo8-dev libgnutls28-dev libpng-dev \ libpam0g-dev libx11-dev libxext-dev libxdamage-dev libxrandr-dev \ libxfixes-dev libxinerama-dev libfltk1.3-dev libssl-dev \ libavcodec-dev libavformat-dev libavutil-dev libswscale-dev \ libtool nasm pkg-config gettext这里有几个关键点需要注意libjpeg-turbo8-dev这是JPEG编解码库的开发版本。TigerVNC默认使用它来进行图形压缩性能比传统的libjpeg好很多务必安装。libgnutls28-dev和libssl-dev两者都是加密库。TigerVNC可以支持其中一种。我选择都装上让CMake在配置时自己选择避免编译错误。libavcodec-dev等FFmpeg库这些是可选的用于支持视频流的编码能提升动态画面的传输效率。如果你的应用场景涉及看视频或频繁的界面动画建议装上。fltkTigerVNC自带的一个简单的VNC查看器vncviewer的图形界面依赖。如果你不打算在服务器上编译这个查看器可以省略libfltk1.3-dev。但为了完整性我建议装上。注意安装这些开发包会占用几百MB的磁盘空间这是编译环境的常态。如果空间紧张可以在软件编译安装成功后用sudo apt autoremove清理一些不必要的依赖但不要在生产环境编译中途这么做。3. 获取与编译TigerVNC 1.12.0源码官方源里没有新版本我们只能从源码构建。这种方式虽然步骤稍多但能确保我们获得最新特性并且对整个软件的构建过程有完全的控制权。3.1 下载源码包TigerVNC的源码托管在GitHub上。我们不直接克隆Git仓库因为可能包含未稳定的开发代码而是下载官方发布的稳定版本源码包。1.12.0版本发布页的源码包通常是一个.tar.gz文件。我们可以使用wget直接在终端下载。首先找一个临时工作目录比如~/build。mkdir -p ~/build cd ~/build wget https://github.com/TigerVNC/tigervnc/archive/refs/tags/v1.12.0.tar.gz -O tigervnc-1.12.0.tar.gz下载完成后解压源码包tar -xzvf tigervnc-1.12.0.tar.gz cd tigervnc-1.12.03.2 配置与编译过程解析TigerVNC使用CMake作为构建系统。CMake的一个优势是支持“out-of-source build”即在一个独立的目录中构建不污染源码目录。这是一个好习惯。mkdir build cd build接下来是关键的配置步骤。我们运行cmake来检测系统环境、定位依赖库并生成Makefile。cmake -G “Unix Makefiles” -DCMAKE_INSTALL_PREFIX/usr/local ..-G “Unix Makefiles”指定生成Unix环境下的Makefile。-DCMAKE_INSTALL_PREFIX/usr/local这是最重要的一个参数。它指定软件最终安装的根目录。设置为/usr/local是遵循Linux的惯例用户手动编译的软件通常安装在这里与系统包管理器apt安装的软件通常在/usr分开便于管理。..告诉CMake上一级目录即源码目录是CMakeLists.txt所在的位置。执行这个命令后CMake会输出一大段检测信息。你需要仔细查看是否有任何关键的“NOT FOUND”错误。常见的错误是某个依赖库没找到比如“Could NOT find GnuTLS”。如果出现你需要回到上一步确认对应的-dev包是否已安装例如libgnutls28-dev或者可能需要安装其他名称的包。配置成功后就可以开始编译了。使用make命令-j参数后面跟的数字表示并行编译的作业数通常设置为你的CPU核心数可以显著加快编译速度。你可以用nproc命令查看核心数。make -j$(nproc)编译过程可能需要5到15分钟取决于你的机器性能。期间会输出大量的编译信息。只要没有以“error”字样终止通常都是正常的。3.3 安装与部署编译完成后将软件安装到之前指定的/usr/local目录sudo make install安装过程会将可执行文件如vncserver、vncpasswd、Xvnc等、库文件、配置文件和手册页复制到/usr/local下的相应子目录。安装完成后你可以验证一下主要程序是否在正确的位置which vncserver # 应该输出/usr/local/bin/vncserver /usr/local/bin/vncserver --version # 应该输出TigerVNC server的版本信息例如 1.12.0至此TigerVNC服务器软件本身就已经安装好了。但此时直接运行vncserver可能会失败因为它还需要一些配置。4. 配置VNC服务器与用户环境安装完二进制文件只是第一步让VNC服务以我们期望的方式运行起来需要一系列的配置。这包括设置访问密码、配置启动脚本、以及适配桌面环境。4.1 设置VNC访问密码首先为你的用户设置一个VNC连接密码。这个密码是加密存储的用于远程客户端连接时的认证。vncpasswd执行命令后它会提示你在~/.vnc目录下创建密码文件。你需要输入并确认密码。请注意这个密码不是系统登录密码而是专用于VNC连接的密码。为了安全建议使用强密码。实操心得vncpasswd命令默认只允许8个字符的密码。如果你输入更长的密码它只会截取前8位。这是VNC协议的一个历史遗留限制。虽然TigerVNC做了一些改进但为了最大兼容性建议密码就设8位。安全更多地依赖后续的SSH隧道或网络隔离。4.2 创建自定义的xstartup脚本当VNC客户端连接时服务器需要启动一个桌面会话。这个启动过程由一个名为xstartup的脚本控制。TigerVNC安装后在/usr/local/bin下会有一个vncserver的Perl脚本它会在用户首次启动VNC服务时在~/.vnc目录下生成一个默认的xstartup脚本。但这个默认脚本通常很简陋可能只启动一个终端窗口。我们需要一个能启动完整桌面环境的脚本。对于Ubuntu 20.04 GNOME桌面一个有效的~/.vnc/xstartup脚本如下#!/bin/sh unset SESSION_MANAGER unset DBUS_SESSION_BUS_ADDRESS # 避免一些GNOME相关的启动问题 export XDG_CURRENT_DESKTOPGNOME # 启动GNOME会话 exec /usr/bin/gnome-session 给这个脚本加上执行权限chmod x ~/.vnc/xstartup脚本解析unset SESSION_MANAGER和unset DBUS_SESSION_BUS_ADDRESS这两行是为了解决在systemd用户会话下启动桌面环境时可能出现的DBus冲突问题。不清除这些变量可能导致桌面组件无法正常通信。export XDG_CURRENT_DESKTOPGNOME明确告诉系统我们启动的是GNOME桌面确保加载正确的配置和组件。exec /usr/bin/gnome-session 这是核心它启动GNOME桌面会话。符号让它在后台运行。为什么不用startx或gnome-session --sessionubuntu在早期的教程里你可能会看到更复杂的脚本调用startx或指定session。但在Ubuntu 20.04的systemd用户会话管理下直接启动gnome-session是最稳定可靠的方式。startx更适合纯粹的X环境而gnome-session会处理好所有GNOME特有的服务和初始化。4.3 手动测试VNC服务在配置systemd之前强烈建议先手动测试一下确保一切正常。首先停止任何可能已经存在的VNC服务器实例端口通常是5901开始vncserver -kill :1 2/dev/null || true然后启动一个新的VNC服务器实例指定显示编号为:1对应端口5901分辨率等参数/usr/local/bin/vncserver :1 -geometry 1920x1080 -depth 24 -localhost no:1VNC显示编号:N对应端口5900N。这里:1就是端口5901。-geometry 1920x1080设置虚拟桌面的分辨率。-depth 24颜色深度24位真彩色。-localhost no允许非本机连接。重要警告在生产环境或公网中永远不要使用这个参数此时应该用-localhost yes然后通过SSH隧道连接这是最基本的安全措施。这里为了测试方便先关闭。启动成功后你会看到类似这样的输出New ‘X’ desktop is your-hostname:1 Starting applications specified in /home/yourusername/.vnc/xstartup Log file is /home/yourusername/.vnc/your-hostname:1.log现在你可以在同一局域网的另一台机器上使用VNC Viewer如TigerVNC Viewer、RealVNC Viewer连接你的服务器IP:5901输入之前设置的VNC密码应该就能看到远程的GNOME桌面了。测试完毕后记得杀掉这个测试进程vncserver -kill :15. 创建Systemd服务单元实现开机自启手动启动可以工作但我们的目标是服务化、自动化。Systemd是现代Linux系统的服务管理器用它来管理VNC服务是最规范、最可靠的方式。5.1 Systemd用户服务与系统服务的选择这里有一个关键决策点将VNC服务设置为系统服务还是用户服务系统服务以root或特定系统用户身份运行服务在系统启动时就开始对所有用户可用。通常用于守护进程。用户服务以某个登录用户的身份运行服务在该用户登录后才启动。更贴合“桌面会话”的概念。对于桌面环境的VNC服务用户服务是更合适的选择。因为桌面环境严重依赖于用户的个人配置~/.config,~/.local等。以root身份运行桌面会话会遇到无数权限和配置问题。因此我们将为特定用户创建一个systemd用户服务。5.2 编写Systemd服务单元文件我们需要在用户的家目录下创建systemd的用户服务目录和单元文件。mkdir -p ~/.config/systemd/user/然后创建服务文件~/.config/systemd/user/vncserver.service[Unit] DescriptionRemote desktop service (VNC) for %i Afternetwork.target graphical-session-pre.target Wantsgraphical-session-pre.target [Service] Typeforking User%i PAMNamelogin PIDFile/home/%i/.vnc/%H:%i.pid Environment“DISPLAY:1” ExecStartPre/bin/sh -c ‘/usr/bin/vncserver -kill :%i /dev/null 21 || :’ ExecStart/usr/local/bin/vncserver :%i -geometry 1920x1080 -depth 24 -localhost yes ExecStop/usr/bin/vncserver -kill :%i [Install] WantedBydefault.target文件内容逐行解析[Unit]部分Description服务描述%i是一个特殊的占位符在实例化服务时会替换成实例名如“1”。After和Wants确保服务在网络就绪和图形会话环境准备就绪后才启动。graphical-session-pre.target是用户图形会话启动前的一个阶段目标这对于需要X11或Wayland的桌面服务很重要。[Service]部分Typeforking因为vncserver命令会启动一个后台守护进程Xvnc所以服务类型是“forking”。User%i指定运行服务的用户。这里%i再次被使用但在这个上下文中我们通常用实例名来区分不同显示编号的服务用户是固定的。更常见的做法是写死用户名比如Useryourusername。为了灵活性我们可以保留%i但在启动服务时需要明确。PAMNamelogin使用PAM的“login”模块来建立用户会话环境这有助于正确设置用户的环境变量和资源限制。PIDFile指定记录主进程PID的文件路径。%H是主机名。Environment“DISPLAY:1”设置环境变量DISPLAY。注意这里写死了:1。这意味着这个服务单元文件只管理显示编号为1的VNC服务器。如果你想管理多个显示编号如:1,:2你需要创建多个服务文件或者使用更高级的模板单元服务。为了简单起见我们先管理一个。ExecStartPre在启动主服务前先尝试杀死可能残留的同编号VNC进程确保干净启动。ExecStart核心启动命令。关键改动我们使用了-localhost yes。这意味着VNC服务只监听本地回环地址127.0.0.1。这是强制性的安全措施远程连接必须通过SSH隧道转发。ExecStop停止服务时执行的命令。[Install]部分WantedBydefault.target当用户会话启动到default.target时这个服务会被启用。5.3 启用、启动与测试服务首先重新加载systemd用户的配置让它识别我们新建的服务文件systemctl --user daemon-reload然后启用这个服务使其在用户登录后自动启动systemctl --user enable vncserver.service现在你可以立即启动服务而不需要注销再登录systemctl --user start vncserver.service检查服务状态确认它正在运行systemctl --user status vncserver.service如果状态显示为active (running)并且日志没有报错就说明服务启动成功了。你可以用ss -tlnp | grep 5901命令查看5901端口是否处于监听状态且只监听在127.0.0.1。5.4 配置用户级Systemd随系统启动这里有一个常见的误区用户服务--user默认只在用户登录后才启动。对于一台无头服务器没有显示器不手动登录我们需要让用户服务在系统启动时、用户未登录的情况下也能启动。这需要通过一个特殊的机制用户管理器user.service。我们需要启用系统的“linger”功能为指定用户创建长期存在的用户管理器。sudo loginctl enable-linger $(whoami)这个命令会为当前用户创建一个用户级的systemd实例它在系统启动时就会运行即使用户没有通过控制台或SSH登录。这样我们之前启用的用户服务vncserver.service就会在系统启动时自动运行。验证linger是否启用loginctl show-user $(whoami) | grep Linger应该输出Lingeryes。最后一步重启系统进行终极测试sudo reboot系统重启后等待几分钟然后通过SSH登录服务器。检查VNC服务是否已经自动运行systemctl --user status vncserver.service ps aux | grep Xvnc如果服务是active状态并且有Xvnc进程在运行那么恭喜你开机自启的目标已经完美实现。6. 安全加固与远程连接实践让服务跑起来只是成功了一半安全地访问它才是重中之重。前面我们已经通过-localhost yes将VNC服务绑定到了127.0.0.1杜绝了直接暴露在公网的风险。现在我们需要通过SSH隧道来安全地连接。6.1 通过SSH隧道连接VNC假设你的服务器IP是192.168.1.100VNC服务运行在服务器的5901端口但只监听127.0.0.1。你在本地电脑客户端上操作。在本地电脑的终端中建立一条SSH隧道ssh -L 5901:localhost:5901 your_username192.168.1.100 -N-L 5901:localhost:5901这是端口转发参数。意思是“将本机客户端的5901端口通过SSH连接转发到远程服务器192.168.1.100上的localhost:5901”。-N表示不执行远程命令只建立隧道。现在你的本地电脑的5901端口通过加密的SSH隧道已经连到了服务器上只监听本地的VNC服务端口。6.2 使用VNC Viewer连接本地端口打开你的VNC Viewer如TigerVNC Viewer在地址栏中不再填写服务器的IP而是填写localhost:5901或者127.0.0.1:5901然后输入你之前用vncpasswd设置的密码。连接成功后所有的VNC通信数据都将在SSH隧道中加密传输安全性得到了保障。重要安全提示这种“SSH隧道VNC”的模式其安全性等同于你的SSH连接。请务必确保SSH服务本身的安全例如禁用root的SSH密码登录。使用密钥对认证禁用密码认证。更改SSH默认端口22。使用fail2ban等工具防止暴力破解。6.3 防火墙配置考虑即使VNC服务只绑定到localhost配置防火墙仍然是一个好习惯。Ubuntu 20.04默认使用ufw。你需要确保SSH端口默认22或你修改后的端口是开放的sudo ufw allow 22/tcp sudo ufw enable绝对不要在防火墙上开放5901等VNC端口因为服务本身并不监听外部IP。7. 故障排查与常见问题实录在实际操作中你几乎一定会遇到一些问题。下面是我在多次部署中遇到的典型问题及其解决方案。7.1 编译阶段问题问题1CMake配置时报告“Could NOT find GnuTLS”现象运行cmake命令时在输出中看到红色错误编译无法继续。原因系统缺少GnuTLS的开发库。解决确保已安装libgnutls28-dev。如果已安装但仍找不到可能是库文件路径不在CMake的搜索范围内。可以尝试安装pkg-config工具它可以帮助CMake定位库。问题2make编译时大量未定义引用错误现象make过程中失败错误信息包含“undefined reference to ...”。原因通常是链接阶段找不到库可能是依赖库安装不完整或者编译顺序有问题。解决确认所有-dev包都已安装。彻底清理build目录重新执行cmake和make。有时候旧的编译缓存会导致问题。cd ~/build/tigervnc-1.12.0 rm -rf build mkdir build cd build # 重新cmake和make7.2 服务启动阶段问题问题3启动vncserver或systemd服务失败日志显示“/tmp/.X11-unix/X1”无法创建现象~/.vnc/目录下的log文件报错提到无法创建X11的Unix套接字文件。原因/tmp/.X11-unix/目录权限问题或者/tmp目录挂载了noexec选项。解决检查/tmp/.X11-unix的权限ls -ld /tmp/.X11-unix应该是drwxrwxrwt。检查/tmp的挂载选项mount | grep /tmp不应包含noexec。如果是需要修改/etc/fstab并重启。问题4通过VNC Viewer连接后只有灰色背景和一个“X”光标没有桌面现象能连接输入密码也正确但进入后是空荡荡的灰色桌面。原因~/.vnc/xstartup脚本没有正确执行或者执行的桌面环境命令失败了。排查检查xstartup脚本是否有执行权限chmod x。查看VNC日志文件cat ~/.vnc/your-hostname:1.log看最后几行是否有错误。常见错误是找不到gnome-session命令。确认你的系统确实安装了GNOME桌面。Ubuntu 20.04 Desktop版默认是GNOME。如果是Server版你需要先安装桌面环境sudo apt install ubuntu-desktop。尝试在xstartup脚本中在exec行之前添加一行export DISPLAY:1。问题5systemd服务状态为active (exited)而不是active (running)现象systemctl --user status vncserver.service显示服务已退出。原因Typeforking配置下systemd期望主进程“fork”后父进程退出子进程成为守护进程。如果vncserver脚本没有按预期fork或者PID文件没有正确生成systemd就会认为服务启动失败并退出。解决检查PID文件路径/home/%i/.vnc/%H:%i.pid是否正确。%H可能包含域名导致文件名不匹配。可以尝试在服务文件中将PIDFile改为固定的路径例如PIDFile/home/yourusername/.vnc/localhost:1.pid。查看完整的服务日志journalctl --user -u vncserver.service -e这里通常有更详细的错误信息。7.3 连接与安全相关问题问题6VNC连接非常卡顿原因网络延迟高或者VNC的编码设置不适合当前画面。优化使用SSH压缩在建立SSH隧道时加入-C参数ssh -C -L ...。调整VNC编码TigerVNC支持多种编码。在VNC Viewer连接时通常可以设置“Preferred encoding”。尝试选择“Tight”或“ZRLE”并禁用“CopyRect”等看看是否有改善。降低色彩深度和分辨率在服务启动命令中尝试-depth 16和更低的分辨率如-geometry 1280x720。问题7忘记了VNC密码解决直接重新运行vncpasswd命令。它会提示你输入新密码并覆盖旧的~/.vnc/passwd文件。注意如果你为多个显示编号设置了不同密码旧版TigerVNC的行为你可能需要删除~/.vnc目录下对应的passwd文件再重新运行。整个流程从依赖安装、源码编译、手动配置再到最终封装成systemd用户服务并实现安全开机自启涉及了Linux系统管理、软件编译、服务配置和网络安全多个层面的知识。最关键的体会是理解每个步骤背后的“为什么”——为什么要用-localhost为什么要用用户服务为什么要用linger——比单纯复制命令更能让你在遇到问题时游刃有余。这个方案在几台不同的Ubuntu 20.04机器上部署都运行稳定通过SSH隧道的连接方式既安全又方便希望这份详细的记录也能帮你顺利搭建自己的远程桌面环境。
返回列表