在服务器 / 容器里想跑 Chromium、Electron、Playwright,报错:
[...] ozone_platform_x11.cc:259] Missing X server or $DISPLAY
意思很直白——程序想弹 GUI,但当前环境没 X11 显示服务。三个典型场景。
场景一:SSH 到 Linux 服务器
SSH 登进去的 shell 默认没有桌面:
ssh root@server
google-chrome # 直接报 Missing X server
两种解法:
Headless 模式(首选)
google-chrome --headless=new --disable-gpu --no-sandbox https://example.com
Playwright:
browser = playwright.chromium.launch(headless=True)
Puppeteer:
const browser = await puppeteer.launch({ headless: true });
非 headless 场景用 X11 转发
ssh -X root@server
或用 -Y(信任模式,速度更快)。前提是本机有 X server(Mac 上是 XQuartz,Windows 上是 VcXsrv/X410)。
场景二:Docker 容器里
容器默认没 X server:
$ echo $DISPLAY
(空)
首选还是 headless。要真的跑 GUI 就靠 Xvfb(虚拟帧缓冲):
apt update && apt install -y xvfb
xvfb-run -a chromium https://example.com
xvfb-run 会在后台起一个虚拟 X server 让程序连。Playwright 官方镜像就自带这套。
如果显示环境变量已经写了 DISPLAY=:1,但仍然报错,那是因为 :1 对应的 X server 根本没起:
ls /tmp/.X11-unix/
看不到 X0 / X1 就是没启动。容器里手动 export DISPLAY=:1 是没用的——DISPLAY 只是”连哪个 X server”,不会创建 X server。
场景三:WSL
WSL2 现在原生支持 WSLg,一般不会碰到这错。老 WSL1 或者关了 WSLg 的话:
export DISPLAY=:0
sudo apt install x11-apps
xclock # 测试有没有 GUI
再不行就装个 X server(Windows 上 VcXsrv / X410)。
快速判断清单
先看几个变量:
echo $DISPLAY # 应该是 :0 或 :1
ls /tmp/.X11-unix/ # 应该有 X0 之类的 socket
ps aux | grep -E 'Xorg|Xvfb' # 有 X server 进程在跑
hostname # 类似 6e6340e2e0d2 基本是容器
cat /proc/1/cgroup # 看到 docker 关键字 = 容器
对号入座:
| 现象 | 判断 |
|---|---|
| DISPLAY 空 | 没有桌面环境,用 headless 或 Xvfb |
| DISPLAY 有但 X11 socket 目录空 | 声明了但 X server 没起 |
| hostname 是短哈希 | Docker 容器 |
WSL 里 xclock 不动 | WSL 侧 X server 没通 |
一句话总结
服务器 / 容器跑浏览器,能 headless 就 headless,非要 GUI 上 Xvfb。 手动改 $DISPLAY 只是告诉客户端连哪儿,从来不会凭空生出一个 X server。
