ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

WSL2下Ubuntu18.04图形界面搭建与VSCode远程开发实操指南

WSL2下Ubuntu18.04图形界面搭建与VSCode远程开发实操指南

1. 环境盘点与方案选型:为什么这套组合还有人用

1.1 WSL2 与 Ubuntu 18.04 的真实需求判断

先说句实在话,我第一次看到“WSL2安装Ubuntu18.04的图形界面和VSCode”这个需求时,第一反应是:都什么年代了还装 18.04?但仔细聊下来发现,需求确实存在。很多老项目锁定在 Ubuntu 18.04 上,不是因为大家不想升级,而是编译链、驱动库、专有工具只在这个版本下测试过。你在 22.04 上跑得好好的apt install,换到老版本可能就得手工处理一堆依赖。

WSL2 的出现把这类场景的成本拉低了很多。以前要在 Windows 上跑一个 Linux 编译环境,要么装 VMware/VirtualBox,要么双系统重启。前者重、后者折腾,而 WSL2 是一个轻量虚拟机,启动快、内存占用可控,还能直接访问 Windows 文件系统。更关键的是,它能做到“虚拟化但不隔离”,让 Windows 上的 IDE 和 WSL 里的工具链无缝协作。对 18.04 这种老系统来说,WSL2 反而是比真实物理机更好的归宿:不用管驱动,不怕系统崩溃,坏了重新导入一个镜像就行。

不过这里必须泼一盆冷水:Ubuntu 18.04 的官方源已经停止维护,常规 apt 源里很多包已经迁移到 old-releases,不处理的话连apt update都会报错。同时 18.04 在 WSL 下默认没有 systemd 作为一号进程,桌面服务、定时任务这类东西都不能用常规的systemctl enable来管。这些都是后文要逐个解决的坑。所以这篇文章的定位很明确:给那些被项目绑定在 18.04 上的人,趟出一条在 WSL2 里装图形界面和接 VSCode 的完整路线。

1.2 图形界面的三条主流路线怎么选

WSL2 下的 Ubuntu 18.04 要出图形界面,常见方案有三条,我先把它们摆在桌面上对比:

方案原理优点缺点
WSLgWindows 11 原生图形服务,通过 RDP 协议把 Linux GUI 渲染出来基本零配置,像跑 Windows 程序一样依赖新系统/新内核,老 18.04 镜像常常不生效
X Server 转发Windows 跑一个 X Server(如 VcXsrv),Linux 侧把窗口画过来兼容性最好,轻量,可控性强要手动管 DISPLAY 变量和防火墙,偶尔有会话残留
xrdp 远程桌面WSL 内跑 RDP 服务,用远程桌面客户端连接会话稳定,适合当常驻工作台每次启动要手动敲命令,中文输入和会话管理偏弱

我个人主力用的是方案二,也就是 VcXsrv + XFCE。原因很实际:WSLg 固然省事,但很多公司电脑还停在 Windows 10,或者 WSL 内核版本偏旧,WSLg 根本起不来。而 18.04 这种老镜像,在 WSLg 下还会遇到 GL 库不匹配、socket 不挂载之类的怪问题,排查成本远高于直接配一个 VcXsrv。

如果你的需求只是“偶尔看个界面、点两下按钮”,X Server 完全够用;如果你打算把 WSL 当成远程开发的常驻服务器,每天在里面开 IDE、跑服务、看日志,xrdp 更合适。接下来的正文会三条路线都讲,但重心放在 X Server 方案上,一是因为它最通用,二是因为它把 WSL2 的显示原理讲透了,懂了它,另外两条路基本是顺水推舟的事。

2. WSL2 环境搭建与 Ubuntu 18.04 安装

2.1 启用 WSL 功能与版本确认

开始之前先确认宿主机条件。用管理员权限打开 PowerShell,执行下面两条命令:

dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart

第一条启用“适用于 Linux 的 Windows 子系统”,第二条启用“虚拟机平台”。后者是 WSL2 和 WSL1 的分水岭:WSL1 本质上是一个系统调用翻译层,把 Linux 的系统调用翻译成 Windows 的,性能表现和兼容性都不如真机;WSL2 则是一个轻量虚拟机,跑的是完整 Linux 内核,网络行为、文件系统语义都和真实环境更接近。Ubuntu 18.04 里很多老软件依赖真实的网络栈和内核行为,所以非 WSL2 不可。

两条命令执行完重启电脑,然后执行:

wsl --set-default-version 2

如果系统提示需要更新内核组件,去下载 WSL2 内核更新包装上即可。这里有个特别大的坑要提醒:wsl --set-default-version 2只对之后安装的发行版生效,已安装的发行版不会自动转换。你需要在 PowerShell 里用wsl -l -v查看所有发行版的 VERSION 列,确认是 2。如果显示为 1,手动执行wsl --set-version <发行版名> 2转换。我见过不止一个人在新电脑上折腾图形界面半天,最后发现发行版还跑在 WSL1 上,一切都白搭。

2.2 安装 Ubuntu 18.04 的三种方式

Ubuntu 18.04 已经不在应用商店的默认推荐位里,安装需要稍微绕一下,主流有三种方式:第一种是在商店里搜“Ubuntu 18.04”的旧条目,如果账号之前买过或收藏过就可以直接装,但这个方法现在基本靠运气;第二种是通过wsl --install加发行版名的方式,目前也只能装到较新的版本;第三种是自己准备 rootfs 镜像,然后用wsl --import手动导入,这是最可靠、也最适合离线场景的方法,我推荐用这个。

具体操作如下:先下载 Ubuntu 18.04 的 rootfs 压缩包(官方云镜像仓库里有对应文件),然后在 Windows 上创建一个目录存放发行版数据,比如D:\wsl\ubuntu1804,最后执行:

wsl --import Ubuntu1804 D:\wsl\ubuntu1804 D:\download\ubuntu-18.04-rootfs.tar.gz --version 2

导入完成之后直接wsl -d Ubuntu1804进去,你会发现默认是 root 用户,而且没有创建过普通用户,也没有.bashrc。这一点和新版本镜像差距很大,必须手动补上。我的做法是依次执行这几条:

useradd -m -s /bin/bash devuser passwd devuser usermod -aG sudo devuser echo -e "[user]\ndefault=devuser" >> /etc/wsl.conf

最后一句尤其重要:/etc/wsl.conf是 Windows 侧读取的配置,[user] default=devuser会让下次启动时直接以普通用户登录,避免一直拿 root 干活。改完配置后记得执行wsl --terminate Ubuntu1804再重新启动发行版,否则配置不会生效。等进了普通用户,再把默认 shell 的一些常用工具补齐,这个环境才算真正可用。

2.3 基础配置:换源、更新、中文字体

新导入的 18.04 基本是“裸”的,第一步就是换源。18.04 停止维护后,默认源archive.ubuntu.com的很多软件包已经迁移到 old-releases 仓库,直接apt update会报大量 404。你需要打开/etc/apt/sources.list,把里面的地址整体替换成能用的镜像源。bionic 的源格式大概是http://xx.ubuntu.com/ubuntu/ bionic main restricted universe multiverse这样,把域名换成你所在网络环境访问速度快的镜像地址就行。

换完源执行:

sudo apt update && sudo apt upgrade -y

然后安装基础工具链。这里我强烈建议把编译器、版本管理工具、以及中文字体一次装齐,省得后面反复补:

sudo apt install -y build-essential git curl wget \ ca-certificates gnupg lsb-release \ fonts-noto-cjk fontconfig

fonts-noto-cjk是我踩过最大的坑之一。第一次装 XFCE 桌面时没装中文字体,结果整个界面所有中文全部显示成方块,当时我还以为桌面环境坏了,重装了两遍才发现是字体问题。装好之后执行fc-cache -fv刷新字体缓存。这个坑在 20.04、22.04 上不太明显,因为新镜像通常已经预置了 Noto 字体,但 18.04 的 rootfs 极其精简,必须手动补。

另外,老镜像是没有 systemd 的,所以后面凡是涉及systemctl enable的操作都要改成service xxx start或手动写启动脚本。这一步不是可选项,而是整个 18.04 在 WSL 下能不能稳定工作的底层逻辑,后面会反复遇到。

3. 图形界面落地:X Server 方案完整实操

3.1 Windows 侧配置 VcXsrv

X Server 方案说起来一句话:Windows 上跑一个 X Server,Linux 里的图形程序通过 X11 协议把窗口“画”到 Windows 桌面上。这里要注意角色关系:VcXsrv 是显示服务端,Linux 桌面环境是客户端,和普通认知里的“服务器/客户端”正好反过来。理解这一点,后面排查报错会顺畅很多。

VcXsrv 的安装没什么难度,装完启动 XLaunch,需要重点确认几个配置:

  • 显示模式选 Multiple windows,让每个 Linux 窗口独立出现在 Windows 桌面;
  • Display number 保持默认 0;
  • 勾选 Disable access control,否则会报连接被拒;
  • 其他选项默认即可。

勾选 Disable access control 的原因在于 WSL2 是 NAT 网络,Windows 防火墙会把来自虚拟网卡的连接当外部连接处理,同时 X11 协议本身有基于主机的访问控制列表。初学者报Unable to open display,十有八九是这一项没勾,或者 Windows 防火墙弹窗时点了拒绝。启动成功后,托盘区会出现一个 X 图标。如果图标一闪而过,检查一下系统安全软件是不是把 VcXsrv 拦截了,这种事在国产安全软件上尤其常见。

3.2 Ubuntu 侧安装桌面环境

Linux 侧我推荐装 XFCE,而不是 GNOME。原因很实在:18.04 老系统资源本就不宽裕,GNOME 3 在 WSL2 里跑起来拖泥带水,而 XFCE 轻量、稳定、中文支持也成熟。安装命令:

sudo apt install -y xfce4 xfce4-terminal

装完先别急着启动桌面,先验证一下 X 通路是否打通。进入 WSL 后设置 DISPLAY 变量:

export DISPLAY=$(grep nameserver /etc/resolv.conf | awk '{print $2}'):0

这一步是 WSL2 特有的,也是最容易出错的地方。WSL2 的虚拟机通过 NAT 访问外网,Windows 宿主机会把自己的 IP 作为 DNS 服务器写进/etc/resolv.conf,所以读nameserver那一项就能拿到宿主 IP。有人习惯直接用localhost或者127.0.0.1作为 DISPLAY,这在 WSL1 下还能碰巧工作,在 WSL2 下会因为网络栈隔离而失败。所以老老实实去解析nameserver才是正路。

设置完变量,先跑一个极简的测试程序:

xeyes

如果 Windows 桌面弹出一对大眼睛,说明通路已经打通。确认没问题,再把 DISPLAY 的配置写进.bashrc,不然每次开终端都要重新设一遍:

echo 'export DISPLAY=$(grep nameserver /etc/resolv.conf | awk "{print \$2}"):0' >> ~/.bashrc

注意$2前面的反斜杠转义不能丢,否则写入的时候 shell 就把变量展开了,等你 .bashrc 加载时拿到的是空值。这个细节看起来小,实际坑了很多人。

3.3 启动桌面与多个会话的细节

通路验证通过后,启动完整桌面:

startxfce4

正常的话 Windows 桌面会弹出 XFCE 的面板和桌面。但如果你发现面板不完整、桌面右键菜单缺失,多半是 D-Bus 会话没起来。X11 转发只解决了显示问题,桌面组件之间的通信还需要 D-Bus,裸跑startxfce4经常出现这种“显示了一半”的诡异状态。

我的解决方法是封装一个启动函数。在.bashrc里加上:

function gui() { export DISPLAY=$(grep nameserver /etc/resolv.conf | awk '{print $2}'):0 dbus-launch startxfce4 > /dev/null 2>&1 & }

用dbus-launch包一层,确保桌面会话有完整的 D-Bus 环境,面板和通知区域才能正常渲染。这也是为什么很多教程写“装了桌面但是不出面板”,问题就出在这个地方。

另外有个心理预期要提前建立:WSL2 每次重启,虚拟网卡的 IP 会变,nameserver也会跟着变。所以每次开机后如果图形界面突然连不上,先去查 DISPLAY 有没有变化,再确认 VcXsrv 是不是还在运行。这不是配置错了,是 WSL2 的动态网络特性决定的。我的习惯是把 VcXsrv 放进 Windows 开机启动项,配合.bashrc里的动态 DISPLAY 解析,基本能实现“开机即可用”。

4. WSLg 与 RDP 备选方案

4.1 WSLg 的启用条件

如果你的宿主机是 Windows 11,且 WSL 版本较新,其实还有个更省事的选择:WSLg。WSLg 通过内置的 RDP 协议直接渲染 Linux GUI 应用,用户在 Windows 桌面上看到的就是一个普通窗口,不需要额外配置 DISPLAY,也不需要启动任何 X Server。

但 WSLg 在 Ubuntu 18.04 上能不能用,要满足几个硬条件:操作系统支持 WSLg、WSL 内核版本足够新、发行版没有被旧式配置干扰。我自己实测下来,全新安装的 22.04 用 WSLg 基本零配置,但 18.04 的旧 rootfs 导入后,经常出现/mnt/wslg目录不存在的现象,也就是说 WSLg 根本没有把图形 socket 挂载进这个发行版。

遇到这种情况,先用命令检查环境:

ls /mnt/wslg ls /tmp/.X11-unix

如果/mnt/wslg存在,说明 WSLg 已经生效,此时可以把 DISPLAY 指过去:

export DISPLAY=:0 export WAYLAND_DISPLAY=wayland-0

如果目录不存在,说明当前内核和系统组合里 WSLg 没有正常工作,老老实实回到 VcXsrv 方案。还有一个快速补救办法是执行wsl --update更新内核后再重启全部发行版,有时只是内核太旧。

4.2 xrdp 远程桌面方案

X Server 方案适合偶尔用一下,如果你打算把 WSL2 当成常驻的 Linux 工作机,xrdp 更稳。它的思路是在 WSL 内跑 RDP 服务,Windows 自带的“远程桌面连接”直接连进去,体验比 X 转发稳定得多,也不怕窗口焦点被抢。

安装步骤:

sudo apt install -y xrdp xfce4 echo "xfce4-session" > ~/.xsession sudo service xrdp start

看到没,我特意用了service xrdp start而不是systemctl enable xrdp,因为 18.04 在 WSL2 下默认没有 systemd。如果某篇教程让你systemctl启服务,基本可以直接判断那篇是针对新版 Ubuntu 的。这一点是老镜像最典型的坑。

启动 xrdp 后,在 Windows 的远程桌面连接里输入localhost:3389通常就能连上,因为 WSL2 会把监听端口的流量通过 localhost 映射到 Windows。不过 xrdp 的会话管理比较粗糙,输入法支持也一般,而且每次 WSL 重启后都要手动再service xrdp start。我的定位建议是:它适合做“固定工作台”而非“日常桌面”,日常开发还是 VSCode + WSL 的组合更舒服。

5. VSCode 接入 WSL:远程开发的正牌姿势

5.1 Windows 侧 VSCode 与 Remote-WSL 扩展

图形界面配好之后,真正的生产力工具是 VSCode。很多刚接触这个组合的人会误以为 VSCode 需要跑在 Linux 图形界面里,其实恰恰相反:VSCode 跑在 Windows 侧,通过 Remote-WSL 扩展在 WSL 环境里打开工作区,所有编译、调试、终端命令都在 Linux 里执行,但编辑器界面还是 Windows 原生窗口。这个设计的好处是,VSCode 根本不依赖你配好的 X Server,图形界面配不好也不影响开发。

具体步骤:

  1. 在 Windows 侧安装 VSCode,建议选择 System Installer 版本,用户级安装有时会带来 PATH 问题;
  2. 在扩展市场安装Remote - WSL扩展;
  3. 打开 PowerShell,输入wsl -d Ubuntu1804进入 WSL;
  4. 在 WSL 里的目标目录执行code .。

执行code .后,VSCode 会以远程会话形式打开当前目录,左下角状态栏显示WSL: Ubuntu-18.04。此时你在编辑器里装的插件、终端里跑的命令、断点调试时调用的调试器,全部走的是 WSL 侧的真实环境,和 Windows 侧的 Node.js、Python 完全隔离。这也是这套组合最大的价值:Windows 负责交互界面和输入法,WSL 负责真实的 Linux 运行环境。

5.2 WSL 侧开发环境的必要补充

VSCode 能在 WSL 里正常工作,还需要补齐几个基础组件。如果是从 rootfs 手动导入的 18.04,很可能连git、curl都没有,更别说编译工具链。VSCode 的 C/C++ 插件在调试时要调用 gcc、gdb,Python 插件要调用解释器,这些都得提前装好:

sudo apt install -y gcc g++ gdb make python3 python3-pip

注意 18.04 自带的 Python 是 3.6,很多新库已经不支持。如果项目依赖较新的 Python 特性,建议用 pyenv 装一个更高版本,不要直接动系统的 Python,否则 apt 依赖会一团糟。

另一个容易忽略的点是 vscode-server 的下载。Remote-WSL 第一次连接时,会在 WSL 侧自动下载并启动 vscode-server,这个过程要访问微软的服务器。如果公司网络有代理限制,可以在 VSCode 的 settings.json 里配置代理,或者在 WSL 侧设置http_proxy、https_proxy环境变量,指向 Windows 宿主机的代理端口。注意这里说的是公司常规代理,和网上那些所谓“访问加速”的东西完全是两回事,别混为一谈。

5.3 与图形界面配合的实用配置

既然已经装了 XFCE 和 X Server,其实可以让某些 GUI 程序也走图形界面。典型场景是:用 VSCode 跑一个可视化调试工具,或者打开一个浏览器预览页面,这些窗口都可以通过 DISPLAY 画到 Windows 桌面。

我的做法是在.bashrc里写两个别名,按需切换:

alias gui-on='export DISPLAY=$(grep nameserver /etc/resolv.conf | awk "{print \$2}"):0' alias gui-off='unset DISPLAY'

平时开发用gui-off,不开 X Server,节省 Windows 资源;需要跑可视化工具时gui-on,把窗口画出来。这样既不会让一堆 X 客户端抢占焦点,也不影响日常开发。

VSCode 自身还有一些针对 WSL 场景的优化配置,放在 settings.json 里:

{ "remote.WSL.fileWatcher.polling": true, "files.watcherExclude": { "**/node_modules/**": true, "**/.git/**": true } }

remote.WSL.fileWatcher.polling在 WSL1 时代几乎是必需品,因为旧版文件系统事件通知不可靠。WSL2 已经大幅改善,但在某些网络驱动器或重负载项目里,开轮询模式反而更稳。files.watcherExclude是常规优化,排除掉 node_modules 这类目录,VSCode 的文件监听不会疯狂吃 CPU。

6. 常见问题与排查记录

6.1 图形界面黑屏或无法连接

这是配置 X Server 后最常遇到的故障类别。我把自查顺序整理成一张速查表:

现象排查点解决办法
Unable to open displayDISPLAY 变量是否正确确认echo $DISPLAY输出的是宿主 IP:0
连接被拒绝VcXsrv 的访问控制启动时勾选 Disable access control
防火墙拦截Windows Defender 弹窗在防火墙规则中放行 VcXsrv 的专用和公用网络
窗口闪现即消失缺少 D-Bus 会话用dbus-launch startxfce4启动
中文全部是方块缺中文字体安装 fonts-noto-cjk 后刷字体缓存

防火墙那条我要单独多说一句:很多人勾了 Disable access control,却忘了 Windows 防火墙对“专用网络”和“公用网络”的区分。公司 WiFi 通常被识别成公用网络,在这种情况下防火墙默认会拦外部连接,VcXsrv 即便放行了专用网络也连不上。我的解决办法是在防火墙高级设置里,为 VcXsrv 把“专用”和“公用”都设为允许。

6.2 网络与镜像源相关问题

WSL2 的 NAT 网络模式让不少人困惑,常见问题有下面几类:

apt 下载慢是最普遍的,换国内镜像基本解决。公司内网需要代理时,要在 WSL 侧设置http_proxy和https_proxy,注意指向 Windows 宿主机的 IP 而不是 localhost,因为 WSL2 里 localhost 不指向 Windows。DNS 解析异常时,先检查/etc/resolv.conf,如果里面是空内容或者指向了 127.0.0.53,可以在 Windows 侧把 WSL 的自动生成 DNS 关掉,手动指定一个可用 DNS。

DNS 问题在 18.04 上尤其突出,因为新版 WSL 会把 systemd 相关的网络配置带进来,而 18.04 的残留配置不一定兼容。遇到Temporary failure in name resolution,先确认/etc/resolv.conf内容合法,再考虑手动固定。不要一上来就改网卡配置文件,WSL2 重启后网络配置会被重新生成,改了也白改。

6.3 性能优化与日常维护

最后分享几个长期使用的心得。首先是内存控制。WSL2 默认最多用宿主机一半内存,在 8GB 的机器上跑 18.04 桌面会很吃力。在 Windows 用户目录下建一个.wslconfig文件,内容是:

[wsl2] memory=4GB processors=2 swap=2GB

改完必须执行wsl --shutdown,重启后配置才生效。这个方法对 18.04 尤其有价值,因为 XFCE 桌面加上开发工具链,内存占用很容易吃满默认配额。

其次是磁盘占用。18.04 镜像加图形界面加开发依赖,轻轻松松超过 10GB。WSL2 的虚拟磁盘文件只增不减,删了包也不一定回收空间。真要回收,需要wsl --shutdown后用磁盘工具压缩 VHD 文件。但我的实际感受是,18.04 的 apt 依赖树比较乱,压缩收益不大,折腾风险却不小,不如定期审视有没有用不到的包直接卸掉。

最后是配置文件备份。整个环境最有价值的东西,其实就那么几个文件:.bashrc、/etc/wsl.conf、Windows 侧的.wslconfig。我会把.bashrc同步到 Windows 侧某个目录,必要时直接做软链接。这样即使发行版损坏,重装之后几分钟就能恢复工作环境,不用从头再来。

从我自己实际使用的感受来说,WSL2 加 Ubuntu 18.04 这套组合真正的价值,在于把 Windows 的日常生态和 Linux 的开发工具链无缝拼在一起。图形界面解决的是“能不能看懂”的问题,VSCode 的 Remote-WSL 解决的是“干得舒不舒服”的问题——后者才是每天真正产生生产力的部分。如果你按上面步骤走通一遍,后面维护起来会轻松很多。最后提醒一句,18.04 毕竟已经老去,如果不是项目硬性要求,新环境尽可能选 22.04 或更新版本,你会省掉很多和“老版本适配”搏斗的时间。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进