目标:Debian 13 最小化安装后,本机保持纯 TTY,不启动本地图形桌面;仅在 RDP 登录时启动 xorgxrdp + dwm。普通窗口使用 monocle 布局铺满远程桌面,dialog / transient / fixed-size 窗口由 dwm 按 floating 方式处理。
本文以普通 RDP 登录用户执行用户级命令;需要系统权限的命令使用 sudo。
sudo apt update
sudo apt upgrade -y
为了保持最小化,不直接安装完整 xorg 元包,而是显式安装 xrdp、xorgxrdp、xterm 和需要的 X11 工具:
sudo apt install --no-install-recommends \
xrdp \
xorgxrdp \
xterm \
x11-utils \
x11-xserver-utils \
dbus-user-session
如果不在意安装更多 X.Org 驱动和工具,也可以安装完整 xorg 元包;本文采用上面的最小化方案。
sudo systemctl set-default multi-user.target
systemctl get-default
预期输出:
multi-user.target
启用 xrdp:
sudo systemctl enable --now xrdp
sudo apt install --no-install-recommends \
build-essential \
wget \
ca-certificates \
libx11-dev \
libxft-dev \
libxinerama-dev \
fonts-dejavu-core
mkdir -p ~/src
cd ~/src
wget https://dl.suckless.org/dwm/dwm-6.8.tar.gz
tar xf dwm-6.8.tar.gz
cd dwm-6.8
nano config.mk
将:
X11INC = /usr/X11R6/include
X11LIB = /usr/X11R6/lib
修改为:
X11INC = /usr/include
X11LIB = /usr/lib
cd ~/src/dwm-6.8
cp config.def.h config.h
nano config.h
将整个 config.h 替换为:
/* See LICENSE file for copyright and license details. */
/* appearance */
static const unsigned int borderpx = 0;
static const unsigned int snap = 0;
static const int showbar = 0;
static const int topbar = 1;
static const char *fonts[] = { "monospace:size=10" };
static const char col_black[] = "#000000";
static const char col_white[] = "#ffffff";
static const char *colors[][3] = {
/* fg bg border */
[SchemeNorm] = { col_white, col_black, col_black },
[SchemeSel] = { col_white, col_black, col_black },
};
/* one tag only */
static const char *tags[] = {
"1"
};
/* no application-specific rule yet */
static const Rule rules[] = {
/* class instance title tags mask isfloating monitor */
{ NULL, NULL, NULL, 0, 0, -1 },
};
/* layout */
static const float mfact = 0.55;
static const int nmaster = 1;
/*
* Important for our use case:
* ignore application size hints when tiled/monocle.
*/
static const int resizehints = 0;
/* keep focus on real EWMH fullscreen clients */
static const int lockfullscreen = 1;
static const int refreshrate = 120;
/*
* Only one layout:
*
* normal windows -> monocle
* dialog/transient/floating windows -> floating
*/
static const Layout layouts[] = {
/* symbol arrange function */
{ "[M]", monocle },
};
/*
* dwm.c:spawn() references these two symbols unconditionally.
* We don't use dmenu, but keep dummy definitions for vanilla dwm.
*/
static char dmenumon[2] = "0";
static const char *dmenucmd[] = { NULL };
static const char *termcmd[] = {
"xterm",
"-ls",
NULL
};
/*
* Keyboard shortcuts.
*
* Alt + Shift + Enter : new xterm
* Alt + Tab : next client
* Alt + Shift + C : close current client
* Alt + Shift + Q : quit dwm
*/
#define MODKEY Mod1Mask
static const Key keys[] = {
/* modifier key function argument */
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
{ MODKEY|ShiftMask, XK_c, killclient, {0} },
{ MODKEY|ShiftMask, XK_q, quit, {0} },
{ MODKEY, XK_Tab, focusstack, {.i = +1 } },
};
/*
* Debug/maintenance only.
*
* Alt + left mouse -> move floating window
* Alt + right mouse -> resize floating window
*
* They can be removed later if not needed.
*/
static const Button buttons[] = {
/* click event mask button function argument */
{ ClkClientWin, MODKEY, Button1, movemouse, {0} },
{ ClkClientWin, MODKEY, Button3, resizemouse, {0} },
};
说明:MODKEY 为 Mod1Mask,因此这里的修饰键是 Alt,不是 Super。
注意:dwm 会自动将标准 EWMH dialog、transient 和 fixed-size 窗口作为 floating 处理,但某些应用若没有正确声明窗口类型,仍可能需要通过 xprop 获取 WM_CLASS / title 后在 rules[] 中增加专用规则。
cd ~/src/dwm-6.8
make clean
make
sudo make install
/usr/local/bin/dwm -v
sudo nano /etc/xrdp/xrdp.ini
在 [Globals] 中加入或修改:
autorun=Xorg
并确认文件中的 [Xorg] 段类似下面内容,重点是 code=20:
[Xorg]
name=Xorg
lib=libxup.so
username=ask
password=ask
ip=127.0.0.1
port=-1
code=20
sudo nano /etc/xrdp/sesman.ini
在 [Globals] 中确保只保留一组相关配置,不要重复定义:
[Globals]
EnableUserWindowManager=true
UserWindowManager=.xrdp-session
DefaultWindowManager=startwm.sh
UserWindowManager=.xrdp-session 表示 xrdp-sesman 会从 RDP 用户的 home 目录执行 ~/.xrdp-session。如果脚本不可执行,会回退到 /etc/xrdp/startwm.sh。
先创建 ~/.Xresources:
nano ~/.Xresources
写入:
XTerm*renderFont: true
XTerm*faceName: DejaVu Sans Mono
XTerm*faceSize: 24
XTerm*background: #1e1e1e
XTerm*foreground: #d4d4d4
XTerm*cursorColor: #aeafad
XTerm*cursorBlink: true
XTerm*highlightColor: #264f78
XTerm*highlightTextColor: #ffffff
XTerm*scrollBar: false
XTerm*color0: #1e1e1e
XTerm*color1: #cd3131
XTerm*color2: #0dbc79
XTerm*color3: #e5e510
XTerm*color4: #2472c8
XTerm*color5: #bc3fbc
XTerm*color6: #11a8cd
XTerm*color7: #e5e5e5
XTerm*color8: #808080
XTerm*color9: #f14c4c
XTerm*color10: #23d18b
XTerm*color11: #f5f543
XTerm*color12: #3b8eea
XTerm*color13: #d670d6
XTerm*color14: #29b8db
XTerm*color15: #ffffff
XTerm*utf8: 1
XTerm*saveLines: 10000
如需立即测试字体,也可以运行:
xterm -fa "DejaVu Sans Mono" -fs 24
在已有 X 会话中立即重新加载资源:
xrdb -load ~/.Xresources
验证:
xrdb -query | grep '^XTerm'
已经打开的 xterm 不一定会应用新资源,应新开一个 xterm 测试。
nano ~/.xrdp-session
写入:
#!/bin/sh
export XDG_SESSION_TYPE=x11
export XDG_CURRENT_DESKTOP=dwm
export DESKTOP_SESSION=dwm
# Load X resources before starting the first xterm.
if [ -r "$HOME/.Xresources" ]; then
/usr/bin/xrdb -load "$HOME/.Xresources"
fi
# Start dwm.
/usr/local/bin/dwm &
DWM_PID=$!
# Start the initial terminal.
/usr/bin/xterm -ls &
# Ending dwm ends the RDP graphical session.
wait "$DWM_PID"
这一步非常重要。~/.xrdp-session 必须能够由实际 RDP 登录用户执行,不能是 root:root 0700。
sudo chown "$USER":"$USER" "$HOME/.xrdp-session" "$HOME/.Xresources"
chmod 700 ~/.xrdp-session
chmod 644 ~/.Xresources
ls -l ~/.xrdp-session ~/.Xresources
预期 ~/.xrdp-session 的 owner/group 是当前 RDP 用户。
sudo systemctl restart xrdp
sudo systemctl restart xrdp-sesman
首次验证或修改会话启动逻辑后,建议直接重启虚拟机,以避免 mstsc 重新连接到之前仍然存在的旧 xrdp session:
sudo reboot
使用 Windows mstsc 连接虚拟机。正常情况下:
~/.Xresources 中的 24pt 深色配置。| 快捷键 | 功能 |
|---|---|
| Alt + Shift + Enter | 新建 xterm |
| Alt + Tab | 切换到下一个已有 client;没有窗口时不会自动创建 xterm |
| Alt + Shift + C | 关闭当前 client |
| Alt + Shift + Q | 退出 dwm,并结束当前 RDP 图形会话 |
| Alt + 鼠标左键 | 移动 floating 窗口 |
| Alt + 鼠标右键 | 调整 floating 窗口大小 |
sudo grep -Ei 'window manager|xrdp-session|startwm|exec' /var/log/xrdp-sesman.log | tail -100
如果看到 errno: 13 / Permission denied,优先检查:
ls -l ~/.xrdp-session
stat ~/.xrdp-session
脚本应归 RDP 登录用户所有,并具有执行权限。
xrdb -query | grep -iE 'XTerm.*(renderFont|faceName|faceSize)'
xprop | grep -E 'WM_CLASS|WM_NAME|_NET_WM_WINDOW_TYPE|WM_TRANSIENT_FOR'
点击异常窗口,根据输出结果在 dwm 的 rules[] 中补充 isfloating=1 的规则,然后重新编译安装 dwm。