# Linux连接到图形界面的方案
1. ToDesk或者其他远程连接工具,可以直接连接到控制台桌面。这个不多说了,但是要注意运行在不同X桌面上的ToDesk间不互通,不等同于多屏幕,一次只能在一个桌面启动ToDesk,多个会冲突。
2. 通过VNC或者RDP来连接。VNC连接有两种方案,一种是通过`x11vnc`转发已经开启的控制台桌面或虚拟桌面,另一种是通过`TigerVNC`/`TightVNC`等工具直接call一个`vncserver`命令,同时完成开启桌面和开启服务器。而RDP连接使用的是`xrdp`,有很多配置(兼容xvnc,但是既然使用了`xrdp`,就没有必要再手动配置VNC服务器了,而是应该使用`xrdp`自动提供的更好的GUI方式:`xorg`)。
3. 最推荐的方式是使用RDP,因为比VNC实在是少卡顿太多了,而且还是Windows自家的远程方案,Windows自带客户端。
## RDP方案
这里以Fluxbox为例,也可以使用其他的WM/DE。首先安装:
```sh
sudo apt install -y xrdp xorgxrdp fluxbox
sudo systemctl enable xrdp --now
```
配置一个`~/.xsession`:
```
picom &
exec fluxbox
```
然后`chmod +x ~/.xsession`
然后可以从`/etc/xrdp/xrdp.ini`里更改一下RDP端口,然后把该文件末尾除了xorg之外的session type(如xvnc/vnc-any)全部注释。
配置结束后,重启服务:
```
sudo systemctl restart xrdp
```
之后就可以在Windows上直接运行命令`mstsc`来连接咯!
## VNC方案
### 方案一:转发控制台桌面
这种方法的核心是“所见即所得”,你看到的远程桌面,就是连接在物理显示器上图形界面,与ToDesk一致。当然,也可以通过`Xvfb`来创建虚拟桌面,然后转发它。
`x11vnc`作为一个轻量级的程序,连接到已经存在的X服务器会话。它像一个“中间人”,截获该X会话的所有图形变化,然后通过VNC协议将其广播给客户端。它不创建新的桌面,仅仅是分享已有的。
```
# 安装
sudo apt install x11vnc
# 设置密码
x11vnc -storepasswd
sudo cp ~/.vnc/passwd /etc/x11vnc.passwd
sudo chmod 600 /etc/x11vnc.passwd
# 手动启动
# -display :0 -> 指定要共享的X会话
# -forever -> 允许多个客户端连接,一个断开后不退出
# -pwfile -> 指定密码文件
# -rfbport 5900 -> 指定VNC监听端口 (默认)
# -bg -> 后台运行
x11vnc -display :0 -forever -pwfile /etc/x11vnc.passwd -rfbport 5900 -bg
```
为了让`x11vnc`开机自启,建议配置成systemd服务。
创建服务文件`/etc/systemd/system/x11vnc.service`:
```
[Unit]
Description=Start x11vnc at startup.
After=graphical.target
[Service]
Type=simple
ExecStart=/usr/bin/x11vnc -display :0 -forever -pwfile /etc/x11vnc.passwd -rfbport 5900
ExecStop=/usr/bin/pkill x11vnc
Restart=on-failure
User=root # 注意权限,可能需要根据实际情况调整
[Install]
WantedBy=multi-user.target
```
启用并启动:
```
sudo systemctl enable x11vnc.service
sudo systemctl start x11vnc.service
```
另外可以补充一下,`Xvfb`是一个用来生成虚拟桌面(但不带任何会话,也不带VNCServer)的指令,有了`Xvfb`后可以使用`env DISPLAY=:<DISPLAY_NO> <某个GUI程序>`的方法来在该X会话中启动一个图形程序,这时`x11vnc`就可以转发了,用法如下:
```
Xvfb :3 -screen 0 2560x1440x24 -dpi 144 -ac -nolisten tcp +extension GLX +render -noreset
```
`:3`是示意,可以是任何未占用的`DISPLAY`编号。`-screen <number>`可以有多个,每个都可以有分辨率、色深、DPI。其他参数不建议改。
但是警惕,在此虚拟桌面中,硬件图形加速是不可用的。所有图形渲染都由CPU完成(通过`+extension GLX`参数支持OpenGL在CPU上运行),无法胜任高负载的3D渲染、游戏或视频流处理任务。
为了把空屏占满,我们可以启动一个极简WM:
```
DISPLAY=:3 startfluxbox
```
然后转发并连接:
```
x11vnc -display :3 -forever -usepw -rfbport 5903 -repeat -wait 5 -defer 5 -bg
```
### 方案二:创建虚拟桌面
这种方法是完全独立的。它会在后台创建一个全新的、纯内存的虚拟显示环境,你可以在里面启动一个完整的桌面环境(如XFCE/LXDE等)。
VNCServer可以看作是`Xvbf`和`x11vnc`和一个启动脚本(如WM或DE)的组合。
安装:选择`tigervnc`或`tightvnc`。注意这和客户端的`vncviewer`无需相同。客户端只有`tightvnc`比较好用,`tigervnc`不支持Hi-DPI。服务器上两个都可以用。
设置密码:每个用户第一次启动VNC服务前,都需要为自己设置一个密码。这个密码是针对用户的,存储在用户的 `~/.vnc/` 目录下。
```
vncpasswd
```
配置启动脚本:`vi ~/.vnc/xstartup`。这里使用最轻量但是还算能用的桌面环境LXDE(需要提前安装):
```
#!/bin/bash
lxterminal &
/usr/bin/lxsession -s LXDE &
```
然后:
```
chmod +x ~/.vnc/xstartup
```
启动:
```
# 启动编号为 :1 的虚拟桌面 (客户端连接端口为 5900 + 1 = 5901)
# -geometry 2560x1440 -> 可在此指定分辨率
# -dpi -> 可在此指定DPI
vncserver :1 -geometry 2560x1440 -dpi 120
# 列出当前运行的VNC会话
vncserver -list
# 停止编号为 :1 的虚拟桌面
vncserver -kill :1
```
每次都输入参数很麻烦。你可以为 TigerVNC 创建一个用户配置文件,让设置永久生效。
编辑或创建 `~/.vnc/config` 文件:
```
# VNC服务器默认配置
geometry=2560x1440
dpi=120
# 你还可以添加其他参数,如:
# localhost=yes # 只允许从本地(通过SSH隧道)连接,更安全
```
保存后,下次直接运行 `vncserver :1` 就会自动应用这个配置。
## 一些方便使用的小技巧
### 中文环境和中文输入法
首先安装中文字体并刷新系统记录:
```sh
sudo apt install -y fonts-noto-cjk
fc-cache -fv
```
接下来是中文输入法fcitx5:
```sh
sudo apt install -y fcitx5 fcitx5-chinese-addons fcitx5-rime
```
然后,在xsession中(或者手动启动):
```
export GTK_IM_MODULE=fcitx
export QT_IM_MODULE=fcitx
export XMODIFIERS=@im=fcitx
export SDL_IM_MODULE=fcitx
export LANG=zh_CN.UTF-8
export LC_COLLATE=C
fcitx5 -d &
# ... 其他
```
然后,第一次运行时,应该配置一下,运行`fcitx5-configtool`,在里面配置需要的东西。注意默认不会给每个程序打开输入法,Ctrl+Space才会打开,然后Shift是切换中英文,这个也可以配置为自动打开,具体请到GUI配置界面自己摸索。
所有需要输入法的程序都必须在fcitx5运行以后再启动,之前启动的无法使用输入法。
### 仅开放SSH端口进行连接的方法
这是一种推荐的方法,能够避免远程连接易被攻击带来的风险。同时也是一种部署友好的方法,避免在防火墙中添加无必要的端口放行规则。
在客户端机器上打开SSH转发:
```
ssh -L xxxx:localhost:yyyy -c [email protected] -m [email protected] -x -a -o "IPQoS=lowdelay" -o "Compression=no" -N remote_user@remote_host
# ssh -L # SSH Local Port Forwarding
# <local port>:<forwarding host relative to remote>:<forwarding port relative to remote>
# -N # no interactive terminal
# <remote user>@<remote host>
```
这里`yyyy`代表远端机器上VNC或RDP服务器的端口,`xxxx`是要映射到的本地端口,也是本地的mstsc或vncviewer最终要连接的端口,而要连接的主机名始终为本机localhost。
### 临时更改分辨率(仅VNC)
虽然`Xvfb`和`vncserver`都有直接指定geometry和DPI的参数,但是都不像服务器端物理控制台里的DE一样,可以动态设置这些参数。因此,需要一种能动态设置参数的方法,也就是`xrandr`。
而RDP是受客户端分辨率控制的,并不是服务器端主动控制,因此无需考虑这个环节。
首先,不带参数运行`xrandr`得到当前屏幕和显示器参数:
```
xrandr
```
如果有显示器,应该会展示出来其名称及可用分辨率,同时还有屏幕(Screen)的信息。如果是纯虚拟桌面,显示器名称应该叫类似于`screen`或者`default`或者带`VNC`字样的名字。`xrandr`的输出形式类似于:
```
Screen 0: minimum 32 x 32, current 2560 x 1440, maximum 32767 x 32767
<显示器名称> connected 2560x1440+0+0 0mm x 0mm
2560x1440 60.00*+
1920x1080 60.00
```
由于我们主要讨论`Xvfb`和`vncserver`创建出的虚拟桌面,对于物理屏幕的操作更简单傻瓜,因此我们只在最后附上更改物理屏幕的方法,而先介绍虚拟桌面需要的操作。
```
# 获取一个mode标准
cvt 1920 1080
# 返回应类似:
# Modeline "1920x1080_60.00" 173.00 1920 2048 2248 2576 1080 1083 1088 1120 -hsync +vsync
# 给xrandr添加mode,--newmode后跟cvt返回的Modeline之后一串(注意不包含单词Modeline)
xrandr --newmode <cvt返回值>
# 将此模式赋予当前显示器
xrandr --addmode <显示器名称> "1920x1080_60.00"
# 将当前显示器更改为此模式
xrandr --output <显示器名称> --mode "1920x1080_60.00"
```
而物理显示器一般直接使用支持的分辨率和刷新率就好了:
```
xrandr --output <显示器名称> --mode <运行无参xrandr列出的模式之一>
```