背景介绍
日常开发中,经常需要远程操作 Linux 服务器,并在其中的容器里运行 X11 图形应用程序(如 xclock
、matplotlib
等)。典型的操作场景为:
从 Windows PC 上使用 SSH 登录到一台 Linux 服务器(服务器本身没有 X Server),而服务器又通过容器(使用桥接网络)运行了需要图形界面的程序。
Windows PC (X Server) <===> Linux Server <===> Container (X11 Apps)
SSH Docker/Podman
理想情况下,我希望 X11 图形应用能够通过这两层:
- 从容器“跳”到服务器;
- 再从服务器通过 SSH 转发到 Windows PC 上的 X Server(例如 MobaXterm)。
然而,容器的独立网络环境、X11 的访问控制以及 DISPLAY 配置的复杂性,常常导致 X11 应用无法正常显示。经过一番探索,笔者找到了一套高效的解决方案。
注意:本文要求读者具备基本的 X11 相关知识,可移步笔者另一篇 博文 获取基本的操作知识。
配置方案
要实现这一需求,我们需要确保以下三点:
- 服务器的 SSH X11 转发正常工作,并能监听外部接口;
- 容器内能够访问服务器的 X11 转发端口;
- 容器中配置与服务器一致的 Xauth Cookie,以完成 X11 的访问认证。
具体步骤如下:
1. 在服务器上配置 SSH X11 转发
首先,我们需要确保服务器的 SSH 服务可以正确转发 X11 图形。编辑服务器上的 sshd_config
文件,添加以下内容:
X11Forwarding yes
X11DisplayOffset 10
X11UseLocalhost no
其中,X11UseLocalhost no
是关键配置,它使得 X11 转发端口监听在所有网卡上(0.0.0.0
),而不仅仅是 127.0.0.1
。
保存配置后,重启 SSH 服务:
sudo systemctl restart sshd
接下来,从 Windows 使用 ssh -X
(或 ssh -Y
)登录服务器,获取 $DISPLAY
变量的值:
ssh -X youruser@server_ip
echo $DISPLAY
如果 $DISPLAY
不为空,说明环境变量自动配置正常,例如:192.168.1.33:10.0
。基于该值验证 X11 转发是否正常。
首先通过 netstat
或 ss
命令确认端口监听状态:
netstat -antp | grep 6010
注意,6010 = 6000 + 10。如果 $DISPLAY
中的 offset 不为 10,请自行调整命令。
然后运行一个简单的 X11 应用进行测试:
xclock # 应该能在 Windows X Server 上显示时钟窗口
2. 在容器中配置 DISPLAY 和网络
容器和服务器之间使用桥接网络模式,因此容器和服务器的 IP 并不相同。下文假设容器可以访问到服务器的(某个)IP:192.168.1.33。
进入容器后:
设置 DISPLAY 环境变量,指向服务器的 IP 和 DISPLAY 号:
export DISPLAY=192.168.1.33:10.0
其中
10.0
是 SSH 分配的 DISPLAY 号,需要与服务器上的一致。如果需要测试网络连通性,可使用
telnet
或nc
测试:telnet 192.168.1.33 6010
3. 在容器中设置 Xauth Cookie
X11 的认证使用 MIT-MAGIC-COOKIE-1 机制,因此容器内需要与服务器相同的 Xauth Cookie。以下是两种方法:
方法 1:直接复制服务器上的 .Xauthority
文件
将 服务器(宿主机) 上当前用户的 .Xauthority
文件复制到容器内:
podman cp ~/.Xauthority your_container:/root/.Xauthority
然后,在 容器 中设置 XAUTHORITY 环境变量:
export XAUTHORITY=/root/.Xauthority
该方案中,由于你直接复制了 Cookie,容器内的 DISPLAY 变量必须和服务器上的完全一致。
方法 2:手动添加 Cookie
在 服务器(宿主机) 上运行 xauth list
查看当前会话的 Cookie:
xauth list
例如,输出如下:
localhost/unix:10 MIT-MAGIC-COOKIE-1 abcdef1234567890abcdef1234567890
localhost:10 MIT-MAGIC-COOKIE-1 abcdef1234567890abcdef1234567890
在 容器 中使用 xauth add
命令手动添加:
xauth add 10.88.0.1:10 MIT-MAGIC-COOKIE-1 abcdef1234567890abcdef1234567890
该方案中,你可以将 10.88.0.1 替换为任何可以访问到宿主机的 IP/域名,例如 host.containers.internal
。
4. 测试 X11 应用程序
配置完成后,在容器中运行 X11 图形应用程序:
xclock
如果所有设置正确,xclock
的窗口应该能显示在 Windows 的 X Server 上。
后记
上次折腾 X11 可能还是 2022 年,三年时光弹指一瞬……
总之,通过以上方案,笔者成功在远程服务器的容器中运行 X11 应用,并将图形无缝地显示在 Windows 上。希望这篇文章能为遇到类似需求的读者提供一些帮助!