1. 离线环境里为什么要折腾 xrdp 这套组合
1.1 一个很具体的场景约束
先把话说在前面:这篇东西不是写给"机器能联网、yum install 一把梭"的人看的。它针对的是一类非常具体、非常难受的场景——目标机器完全断网,或者只有内网、没有可用软件源,但你需要在这台 CentOS 7 上跑起一个能远程连进去的图形桌面。这种场景通常出现在内网隔离区、生产线边缘节点、实验室的老旧服务器、以及一些"装完就再也拔不了网线"的机柜里。
这类机器的共性非常明显:系统是 CentOS 7,可能是最小化安装(minimal),IEEE 上除了网卡驱动什么都没有;机器本身没有外网,物理权限也受限制,插 U 盘要走审批;而使用者又确实需要一个图形界面,比如跑一个只有 GUI 的采集软件、看一眼监控画面、做一次图形化的配置。命令行解决不了,SSH 又不够用。
这时候大多数人的第一反应是装 VNC。我早年也这么干,后来发现 VNC 在离线环境里更麻烦:tigervnc-server 要拉一堆 X 相关依赖,独立会话还得手动编 xstartup,中文输入、剪贴板、分辨率调整全靠自己拼。而 xrdp 的好处在于,它走的是 RDP 协议——客户端侧什么都不用装。Windows 自带远程桌面连接,日常办公电脑直接就能连,不用给三十台客户端各装一个 VNC Viewer。这一条在封闭环境里的价值非常高。
所以我这套方案的核心判断是:离线 + 多客户端 + 只要图形可用即可,优先 xrdp;要求低延迟的视频级画面或需要多显示器高质量渲染,才考虑别的路子。
1.2 xrdp 到底做了什么,别把它当成黑盒
很多人装完 xrdp 之后遇到黑屏、闪退,就是因为没搞清楚它的层次。我把它拆成三段来讲,理解了这三段,后面排错会快很多。
第一段是协议层。xrdp 自己监听 3389 端口,接收 RDP 协议,把远端的键盘、鼠标、画面编码解出来。这一层只干协议转换,不画界面。第二段是会话管理。xrdp 里有个叫 sesman 的组件(对应xrdp-sesman服务),负责认证、分配会话、记录会话状态。你连进来之后,是 sesman 去决定"这个用户开一个新会话还是接回旧会话"。第三段是后端 X 服务器。xrdp 并不自己渲染桌面,它需要起一个真实的 X server,然后从里面抓画面。这一块在 CentOS 7 上通常是xorgxrdp这个包提供的 Xorg 后端驱动。
明白了这三层,就能解释一个非常经典的现象:xrdp 装好了、服务也起来了、端口也通了,但连上去是黑屏。原因八成是第三段断了——xorgxrdp没装,或者 Xorg 起不来,或者startwm.sh里的启动脚本执行失败,没有拉起任何窗口管理器。桌面环境本身是一层,后端 X 是另一层,两者缺一不可。
这里有个选择要讲清楚:老版本的 xrdp 还支持Xvnc后端(用 Xvnc 当 X server),但那条路要额外拉 tigervnc-server,依赖更重,性能也一般。CentOS 7 的 EPEL 里 xrdp 已经带得比较全了,优先走 Xorg 后端 + xorgxrdp,这是我实测下来最稳的组合。
2. 离线介质清单:先把"要什么"算清楚
2.1 三张清单,缺一样就够你跑两趟
离线部署最怕的不是技术难,是"上去发现少一个包"。机房离你工位二十分钟,来回一趟半天没了。所以我在动手前一定列三张清单,写在一个文本文件里,装完一项划一项。
第一张是系统底座清单:CentOS 7 的完整 DVD ISO(不是 minimal ISO,最小化镜像里没有我们要的包)、一个可写 U 盘、以及一个能联网且系统版本、架构完全一致的"下载机"。这个一致性非常关键——x86_64不能对i686,7.6和7.9的 glibc 版本也不一样,拿错版本装上去就是libc.so.6(GLIBC_2.17)(64bit) is needed这种经典报错。
第二张是依赖闭包清单。这是整个过程里最费脑子的部分,下一节单独讲。
第三张是验证清单:装完之后要确认的几个点,包括服务自启、端口监听、用户能登录、中文能打、剪贴板能用。没有这张清单,你很容易在"能连上"这一步就收工了,回去之后用户报"复制粘贴用不了",又是一趟。
2.2 依赖闭包怎么算:两条路,各有各的坑
依赖闭包的计算,在离线场景下只有两种靠谱做法。
做法一:在联网的同版本机器上做"预演下载"。装好 yum-utils,然后:
mkdir -p /opt/offline-rpms yum install --downloadonly --downloaddir=/opt/offline-rpms \ xrdp xorgxrdp这条命令会把 xrdp、xorgxrdp 以及它们尚未安装的依赖一起下到目录里。注意我说的是"尚未安装"——--downloadonly只下缺的,已经装过的不会下。所以那台下载机不能预先装过桌面环境,否则你下出来的包在干净的 minimal 机器上装不上。我一般的做法是拿一台刚装完 minimal、什么都没加的同版本虚拟机当下载机,这样算出来的闭包最贴近目标机。
做法二:用repotrack强行拉全量依赖树。这个更暴力也更保险:
yum install -y yum-utils repotrack -a x86_64 -p /opt/offline-rpms xrdp xorgxrdprepotrack不管目标机已装什么,直接把整条依赖链递归下载下来,包括那些其实已经装了的。包会多,可能上百个,但胜在不会漏。我第一次做的时候用的是做法一,结果漏了xorg-x11-server-Xorg的一堆子包,上去之后 Xorg 起不来,白跑一趟。从那以后,只要是一次性的关键部署,我一律用repotrack,宁可多拷 200MB,也不愿意再跑第二趟。
还有一个细节:桌面环境也要算进闭包。你可以只装 xrdp 不装桌面,但那样连上去也是黑屏,因为没有任何窗口管理器。所以在下载机上还要算上@xfce或者@gnome-desktop这类组。组包用repotrack不好处理,得更简单粗暴一点:
yum groupinstall -y --downloadonly --downloaddir=/opt/offline-rpms "Xfce"2.3 介质目录结构和校验
包下载完之后,别一股脑拷 U 盘。我习惯按功能分目录,并在根目录放一个MANIFEST文本:
/offline-bundle/ ├── 00-iso/ # 系统 ISO ├── 10-base/ # 底座补装包(vim、net-tools、tar 等) ├── 20-desktop/ # 桌面环境组包 ├── 30-xrdp/ # xrdp 及其依赖 ├── 40-extra/ # 输入法、字体、浏览器等 └── MANIFEST.txtMANIFEST.txt里写清楚:ISO 的校验和、每个目录的包数量、生成日期、下载机的主机名和系统版本。这个东西的价值在于——三个月后你或者别人再进一次机房,能一眼看出这套介质是哪来的、对应哪个版本,不至于拿着一堆不知道能不能用的 rpm 瞎试。
拷完之后一定做一次完整性校验,U 盘在传输过程中损坏的概率远比你想象的高:
# 在 U 盘上生成校验文件 find /media/usb/offline-bundle -name "*.rpm" -exec md5sum {} \; > md5.txt # 到目标机上再校验一遍 md5sum -c md5.txt | grep -v OK如果grep -v OK有输出,说明有包坏了,重拷。
3. 系统底座:从最小化安装到能用的本地源
3.1 最小化安装时要注意的几个选项
CentOS 7 最小化安装本身没什么好说的,但有三个地方我在装机时会刻意处理,能省掉后面很多麻烦。
第一是分区。如果这台机器要长期跑图形桌面,/别只给 20G。GNOME 桌面装完大概吃 1.5G,Xfce 约 800MB,加上 yum 缓存、日志、用户目录,我一般给/留 50G,/home单独分。别小看这个,我见过/满了导致 Xorg 写不了临时文件、登录直接黑屏的案例,排查了半天才想到是磁盘。
第二是网络。哪怕机器最终不联网,装机时也建议把网卡配好并设成开机启动。因为 xrdp 的服务要绑地址,防火墙要按网卡区域加规则,网卡没起来的话,后面firewall-cmd加规则会加到默认 zone 上去,行为不一致。
第三是SELinux。我的习惯是保持 enforcing,不做永久关闭,只在装 xrdp 时按需放行。原因很简单:关掉是最省事的做法,但把一台机器关掉 SELinux 再扔进内网,等于给自己埋了个长期隐患,而且时间一长没人记得当初为什么关的。正确做法放在第 5 节讲。
3.2 用 ISO 直接搭一个本地 yum 源
这是离线部署里最关键的一步,做完之后,底座部分的包就能用yum正常解析依赖和装组包了,不用一个个rpm -ivh。
先把 ISO 传到机器上,挂到某个目录:
mkdir -p /mnt/iso mount -o loop /root/CentOS-7-x86_64-DVD.iso /mnt/iso确认一下repodata目录存在:
ls /mnt/iso/repodata/ | head然后写一个本地源文件,同时把系统里所有其他 repo 都禁掉:
mkdir -p /etc/yum.repos.d/backup mv /etc/yum.repos.d/CentOS-*.repo /etc/yum.repos.d/backup/ cat > /etc/yum.repos.d/local-iso.repo <<'EOF' [local-iso] name=Local CentOS 7 ISO baseurl=file:///mnt/iso enabled=1 gpgcheck=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 EOF这里gpgcheck=1我建议保留。离线环境里很多人习惯直接gpgcheck=0图省事,但那样等于放弃了包完整性的最后一层校验,U 盘传坏了你也发现不了,装上去的行为会很诡异。CentOS 7 的 DVD 里自带 GPG key,路径就在上面那行,直接引就行。
刷一下缓存看看是否识别:
yum clean all yum repolist正常的话能看到local-iso这个源,包数量在四千左右(具体取决于 ISO 版本)。
挂载这件事还有一个必须处理的点:重启之后挂载会丢。要么写进/etc/fstab,要么把 ISO 的完整内容拷到硬盘上。我更推荐后者:
mkdir -p /opt/localrepo cp -r /mnt/iso/* /opt/localrepo/然后baseurl=file:///opt/localrepo。硬盘空间换稳定,值得。如果坚持用 fstab 挂载,记得加上loop和ro参数,并且写好nofail,避免 ISO 文件被挪走之后系统起不来。
3.3 补装基础工具链
底座装完,先把几个后面一定会用到的小工具装上。这些包里有一部分 DVD 里有,没有的从10-base目录补:
yum install -y vim-enhanced net-tools lsof tar unzip \ wget createrepo yum-utils opensslcreaterepo这个包值得单独说。如果你后续要往本地源里追加第三方 rpm(比如 EPEL 里的 xrdp 包),直接扔进目录里yum是不认的,必须重新生成索引:
cp /media/usb/offline-bundle/30-xrdp/*.rpm /opt/localrepo/Packages/ createrepo --update /opt/localrepo yum clean all && yum makecache--update参数很重要,它只处理新增和变化的包,不重建整个索引,几千个包的仓库能在几秒内完成。
提示:如果你把 ISO 内容拷到硬盘,新增包一定要放进
Packages/子目录,不要放根目录,否则createrepo生成的路径和原有索引会打架。
4. 桌面环境:装哪一套、装多少、怎么起
4.1 GNOME、Xfce、MATE 在离线场景下的取舍
这个问题在联网环境下反而简单,随便装。离线环境下要考虑三个因素:包体积、依赖深度、在 xrdp 下的表现。
| 桌面环境 | 组包名 | 大致体积 | 依赖深度 | xrdp 下表现 | 我的评价 |
|---|---|---|---|---|---|
| GNOME(标准) | "GNOME Desktop" | 1.5G 以上 | 很深,拉 systemd 组件、tracker、gnome-shell | 能跑,但动画和渲染开销大,远程体验偏卡 | 除非业务软件强依赖 GNOME,否则不推荐 |
| Xfce | "Xfce" | 约 800M | 较浅 | 轻量、响应快,远程手感最好 | 离线首选 |
| MATE | "MATE Desktop" | 约 900M | 中等 | 稳定,兼容性好 | Xfce 装不上时的备选 |
| 纯 WM(openbox 等) | 无组包 | 极小 | 极浅 | 快,但没有面板、没有文件管理器 | 只做单一任务时可用 |
我的默认选择是Xfce。原因很实际:它的依赖闭包小,离线下载时不容易漏;远程桌面场景下,用户要的是"能操作",不是"好看",Xfce 的窗口管理和面板够用;而且它对显卡和 OpenGL 没有硬性要求,在虚拟机、老服务器上不会因为缺 3D 加速而起不来。
有一个坑要提前说:CentOS 7 的 Xfce 组包里,窗口管理器是xfwm4,而 xrdp 默认的会话脚本可能会去找gnome-session。如果startwm.sh没改,连上去就是灰底加一个 X 光标,什么也没有。这个问题在第 5.3 节处理。
4.2 用本地源装桌面组
源配好了之后,装组包和联网时写法完全一样:
yum groupinstall -y "Xfce"如果提示找不到组,先确认组列表里有没有:
yum grouplist | grep -i xfce这里还有一个常见情况:组包装到一半报某个子包找不到,那是因为你用的是 minimal ISO,包里不全。这时候把 DVD ISO 换成完整版,或者从下载机的20-desktop目录手工补。补的时候不要一个个rpm -ivh,用yum localinstall让它帮你解析依赖顺序:
yum localinstall -y /media/usb/offline-bundle/20-desktop/*.rpmlocalinstall和rpm -ivh的区别在于前者会用本地源里的其他包去满足依赖,后者只认已安装的。这个区别在补依赖的时候非常关键。
4.3 图形目标与显示管理器
CentOS 7 用 systemd 的 target 来管理启动模式。装完桌面后,把默认 target 切成图形:
systemctl set-default graphical.target但这里有个很重要的判断:严格来说,跑 xrdp 并不需要系统进入 graphical.target。xrdp 的 Xorg 后端是自己起 X server 的,不依赖本机是否运行了显示管理器(gdm)。也就是说,你完全可以保持multi-user.target,让服务器不开本机图形界面,省内存,同时远程照样能连。
我的做法是:服务器角色保持multi-user.target,只在需要本地也接显示器的机器上切 graphical。这样省下来的几百兆内存,在内存本来就紧张的老机器上很有意义。判断标准很简单——这台机器会不会有人直接坐在它面前用键盘鼠标?会,就切;不会,就别切。
5. xrdp 的安装与核心配置
5.1 安装顺序与依赖补齐
EPEL 里的 xrdp 分两个包:xrdp(主体)和xorgxrdp(Xorg 后端驱动)。两个必须都装,缺后者一定黑屏。
离线安装的顺序建议是:
cd /media/usb/offline-bundle/30-xrdp yum localinstall -y ./*.rpm如果报依赖缺失,先用rpm -qpR看看缺什么:
rpm -qpR xrdp-*.rpm | sort > /tmp/need.txt rpm -qa --qf '%{NAME}\n' | sort > /tmp/have.txt comm -23 /tmp/need.txt /tmp/have.txtcomm -23输出的是"需要但没装"的包名,这一段排查很有效,比在yum的输出里大海捞针强。注意rpm -qpR的输出里有很多rpmlib(...)和config(...)这类伪依赖,可以过滤掉:
rpm -qpR xrdp-*.rpm | grep -v -E '^(rpmlib|config)' | sort装完确认一下关键文件在位:
rpm -ql xrdp | grep -E 'xrdp.ini|sesman.ini|startwm.sh' rpm -ql xorgxrdp | headxorgxrdp里应该能看到xorgxrdp_drv.so这类文件。看不到就是装错包或者装的是空壳。
5.2 xrdp.ini 里真正需要动的几处
/etc/xrdp/xrdp.ini这个文件很长,大部分默认值不用碰。我只会改这几处:
[Globals] # 单次连接的最大会话时长,单位秒,0 表示不限 max_bpp=32 # 允许的加密级别,老客户端连不上时往下调 crypt_level=high # 断开后是否保留会话 bitmap_cache=yes bitmap_compression=yes [Xorg] name=Xorg lib=libxup.so username=ask password=ask ip=127.0.0.1 port=-1 code=20重点说port=-1。这个值的意思是"由 sesman 动态分配一个空闲端口给这个会话的 X server"。很多人把它改成固定的5910之类,结果第二个用户连进来就失败——端口被占了。保持-1是最稳的,除非你有明确的调试需求。
max_bpp=32决定了画面色深。带宽紧张的内网可以把客户端那边调到 16 位,服务端这个值不用动,客户端会协商。但如果你在[Globals]里写死max_bpp=16,画面会有明显的色带,看监控画面的时候很难受,不建议。
另一个参数在/etc/xrdp/sesman.ini:
[Sessions] MaxSessions=20 KillDisconnected=false DisconnectedTimeLimit=0 IdleTimeLimit=0KillDisconnected=false是关键设置。默认情况下,用户断开连接后会话会被杀掉,下次连进来是一个全新桌面,之前开的东西全没了。改成 false 之后,会话保留在后台,重新连上就是原来的画面。这一条对实际使用体验的影响非常大,几乎是必改项。
但要注意副作用:会话保留意味着内存不释放。如果一台机器 20 个人轮流连、都不主动注销,内存会被吃光。所以MaxSessions要给一个合理值,并且配合IdleTimeLimit(空闲超时)来兜底。我的经验值是:MaxSessions设为实际并发人数的 1.5 倍,IdleTimeLimit设 3600(一小时),既不至于刚走开就被踢,也不会长期占着不放。
5.3 startwm.sh:黑屏问题的高发区
/etc/xrdp/startwm.sh是会话启动脚本,xrdp 起完 X server 后会执行它来拉起桌面。默认脚本是给 RHEL 系的 GNOME 设计的,用 Xfce 的话必须改。
先备份:
cp /etc/xrdp/startwm.sh /etc/xrdp/startwm.sh.bak然后改成这个结构:
#!/bin/sh if [ -r /etc/default/locale ]; then . /etc/default/locale export LANG LANGUAGE fi # 中文环境所需的变量 export LANG=zh_CN.UTF-8 export LC_ALL=zh_CN.UTF-8 export XDG_SESSION_TYPE=x11 export XDG_CURRENT_DESKTOP=XFCE # 输入法变量,后面第 6 节详解 export GTK_IM_MODULE=fcitx export QT_IM_MODULE=fcitx export XMODIFIERS="@im=fcitx" # 启动 Xfce exec startxfce4几个关键点:
第一,必须用exec。不用 exec 的话,脚本作为父进程等着桌面退出,xrdp 在会话清理时可能会留僵尸进程,久了机器上会挂一堆。第二,startxfce4的路径要在 PATH 里,如果yum装的是标准 Xfce 组包,/usr/bin/startxfce4是存在的,可以直接调。第三,注意脚本的可执行权限:
chmod +x /etc/xrdp/startwm.sh这个权限丢了也是黑屏,而且systemctl status xrdp看不出任何异常,日志里只有一句很含糊的 "session started"。这是我最常排查到的一个坑。
如果用的是 MATE,把最后一行换成exec mate-session;GNOME 换成exec gnome-session。但一定要确认对应的可执行文件存在,which startxfce4一下,没有就是桌面环境没装全。
5.4 端口、SELinux 与防火墙:三个都要过
启动服务并设自启:
systemctl enable --now xrdp systemctl status xrdp ss -lntp | grep 3389能看到 3389 在监听,说明服务本身没问题了。
防火墙:
firewall-cmd --permanent --add-port=3389/tcp firewall-cmd --reload firewall-cmd --list-ports如果你用的是自定义 zone,记得加--zone=xxx,否则规则加到默认 zone 上,而网卡不在那个 zone 里,等于白加。这个错我踩过,firewall-cmd --list-ports明明有输出,但就是连不上,查了半天是 zone 不匹配。
SELinux:这一步是很多人直接setenforce 0的地方。正确的做法是先看审计日志:
ausearch -m avc -ts recent | grep xrdp如果没有输出,说明 SELinux 没拦,什么都不用做。如果有输出,先看被拦的是哪个标签、哪个操作。常见的是 xrdp 需要往/var/run/xrdp写 socket,这在 EPEL 包的策略里一般是放行的;真正会拦的是会话进程需要执行内存映射这类操作。确认是被误解拦之后,用布尔值放行:
setsebool -P xrdp_execmem 1比关 SELinux 好得多,而且重启后依然有效(-P是持久化)。
注意:不要为了省事在
/etc/selinux/config里写SELINUX=disabled。这台机器在内网里长期运行,关掉安全模块的代价远大于你省下的十分钟。
6. 客户端接入与日常体验调优
6.1 连接参数怎么设才不糊
Windows 自带远程桌面连接,直接输 IP 就能连。但默认设置下画面会偏糊,尤其是文字。要调的地方有三个:
在"显示"标签页,把分辨率选成和你本地显示器一致或者接近的值,别用"全屏"让它自动算。色彩深度选"最高质量(32 位)"。在"体验"标签页,把"检测连接质量"改成"局域网(10 Mbps 或更高)",然后把"桌面背景""字体平滑""视觉样式"这几项关掉——远程场景下这些纯属浪费带宽,关掉之后文字反而更清晰、响应更快。
实测下来,局域网内 100M 环境下,这套设置基本感觉不到卡顿,滚动网页、拖动窗口都挺顺。如果是跨网段、有丢包的环境,可以把色彩降到 16 位,效果立竿见影。
6.2 中文输入、剪贴板、字体这三件事
中文输入。这是离线环境里最容易翻车的地方。Xfce 默认不带输入法,需要额外装 fcitx 或 ibus。离线安装的话,闭包里得包含fcitx、fcitx-gtk2、fcitx-gtk3、fcitx-qt5(如果要用 Qt 程序)、以及至少一套拼音引擎fcitx-pinyin或fcitx-libpinyin。
装完之后要改两个地方。一是刚才startwm.sh里的那三个环境变量,必须写在启动桌面之前。二是 fcitx 的自启动,最简单的做法是在~/.config/autostart/里放一个 desktop 文件,或者直接在startwm.sh里fcitx &后台拉起。我倾向于前者,因为startwm.sh里加太多东西不利于排查。
还有一个细节:语言环境必须生成。如果装系统时没选中文,zh_CN.UTF-8这个 locale 可能压根不存在,设了LANG=zh_CN.UTF-8也会回落到英文。检查:
locale -a | grep zh_CN没有的话用localedef生成,或者从闭包里补langpacks-zh_CN包。
剪贴板。xrdp 的剪贴板走的是cliprdr通道,服务端需要在xrdp.ini的[Globals]段确认cliprdr=yes。多数版本默认开。如果复制粘贴不生效,先查这里,再查客户端——Windows 远程桌面连接的"本地资源"里要勾上"剪贴板"。
字体。服务器上如果只装了最小字体集,中文会显示成方块。补装:
yum install -y wqy-microhei-fonts wqy-zenhei-fonts fc-cache -fvwqy系列在 CentOS 7 的 ISO 里就有,离线可解。
6.3 同一账号重复登录的冲突
这个现象很有迷惑性:用户 A 断开了连接(没注销),过一会儿从另一台客户端再连,输完账号密码之后画面卡住或者直接被踢回登录框。原因是一个账号只能有一个 X 会话,第二次连接会试图复用现有会话,如果复用的路径有问题就会失败。
处理方式有两个。一是建议用户养成"注销"而不是"断开"的习惯,但这靠人靠不住。二是在sesman.ini里调整会话策略:
[Sessions] # 每次连接都新建会话,不复用 Policy=UBDUBD的意思是 User、Bpp、Display 三个维度都匹配才复用会话,实际效果更接近"每次新建"。这样解决了冲突,但代价是断开一次就丢一次现场,用户会抱怨。
折中的做法是:保持KillDisconnected=false,但把MaxSessions设为人数上限,并且在培训里明确"同一账号在一台机器上只能有一个会话,换机器请先注销"。技术方案和用户习惯各让一步,这在真实项目里往往比纯技术方案更管用。
7. 常见故障速查
7.1 四个高频问题,按出现频率排
| 现象 | 最可能原因 | 快速验证 | 处理 |
|---|---|---|---|
| 连上后黑屏,只有一个 X 光标 | startwm.sh没改或没执行权限 / 桌面没装 | sh -x /etc/xrdp/startwm.sh手动跑 | 改脚本、加exec、chmod +x |
| 登录后立刻断开,回到登录框 | xorgxrdp未安装 / Xorg 启动失败 | tail -50 /var/log/xrdp.log | 补装xorgxrdp,检查/var/log/Xorg.*.log |
| 账号密码正确但提示认证失败 | PAM 配置或用户被锁 / 家目录权限 | tail /var/log/secure | 检查/etc/pam.d/xrdp-sesman、chown家目录 |
| 能连但端口不通、超时 | 防火墙 zone 不匹配 / 服务未自启 | ss -lntp | grep 3389、firewall-cmd --get-active-zones | 加对 zone,systemctl enable xrdp |
7.2 日志在哪,怎么读
排查 xrdp 最重要的两个日志文件是/var/log/xrdp.log和/var/log/xrdp-sesman.log。前者记录连接、协议协商、会话建立;后者记录认证和会话分配。黑屏类问题看前者,认证类问题看后者。
我的习惯是先在客户端连一次(触发问题),然后立刻在服务端tail -f两个日志一起看:
tail -f /var/log/xrdp.log /var/log/xrdp-sesman.log日志里有几个关键词值得记住。看到xrdp_mm_process_login_response: login failed是认证问题;看到xrdp_wm_log_msg: some problem后面跟着X server字样,是后端 X 起不来;看到error loading libxup.so是xorgxrdp装错版本,这种情况通常是 EPEL 的 xrdp 版本和 xorgxrdp 版本不配套,两个包必须来自同一次下载。
还有一个隐蔽的坑:磁盘满导致会话建立失败,但日志里只有一句sessions相关的一般性错误。所以排查第一步我会先df -h看一眼根分区,这个动作能省掉不少时间。
7.3 会话卡死怎么清
用户报"连上去是黑屏,重启服务也没用",这时候八成是残留的会话进程在捣乱。清理步骤:
# 看当前有多少个 xrdp 相关进程 ps -ef | grep -E 'xrdp|Xorg' | grep -v grep # 停服务 systemctl stop xrdp xrdp-sesman # 清残留 pkill -9 -f Xorg pkill -9 -f xrdp rm -f /var/run/xrdp/*.pid /tmp/.X*-lock rm -rf /tmp/.X11-unix/X* # 起服务 systemctl start xrdp/tmp/.X11-unix/下的 socket 和/tmp/.X*-lock锁文件是重灾区。X server 异常退出后锁文件不会自动清,下一次启动会因为"display 已被占用"而失败。这个问题的典型表现就是第一个用户能连,第二个连不上,或者重启服务后依然连不上。养成"清残留必删锁文件"的习惯,能少走很多弯路。
8. 加固与长期维护
8.1 这台机器暴露在内网,得有个底线
xrdp 的 3389 端口一旦开放,就等于把图形登录界面挂在了网络上。内网也不是绝对安全的,所以我至少做这几件事。
限制来源。用 firewalld 的 rich rule 只允许指定网段访问:
firewall-cmd --permanent --add-rich-rule=' rule family="ipv4" source address="10.20.0.0/16" port port="3389" protocol="tcp" accept' firewall-cmd --reload比--add-port精确得多。如果你不清楚网段,先跟网络管理员要,别图省事开成 any。
禁止 root 直接登录。xrdp 默认走 PAM,root 能不能登取决于系统策略。我一般会在/etc/xrdp/sesman.ini里确认AllowRootLogin=false(部分版本默认就是 false),并且要求业务账号用普通用户。真需要提权,进桌面之后再su,别在登录框上开这个口子。
限制会话数量。前面提到的MaxSessions除了防内存打爆,也有安全意义——防止有人脚本化地疯狂建会话把机器拖死。
8.2 版本锁定与介质更新
CentOS 7 的生命周期已经结束,这不是什么秘密,但内网存量机器还大量在跑。这个现实决定了我们的策略:不上新特性,只求稳定可复现。
具体做法是:把所有用到的 rpm 一次性固化在离线介质里,并且记录版本号。以后要重装,还是用这套介质,不要试图去网上找"更新的版本"。因为一旦 xrdp 和 xorgxrdp 的版本错配,问题会非常难查,而且网上很难找到对应版本的资料。
建议在介质目录里放一个VERSIONS.txt:
xrdp-0.9.21-1.el7.x86_64.rpm xorgxrdp-0.2.17-2.el7.x86_64.rpm xfce4-session-4.12.1-18.el7.x86_64.rpm ...每次部署完,把这台机器上关键包的版本回填进去,形成"这套介质部署出来的机器都是什么版本"的映射。这个习惯看起来很笨,但在我经历过的几次"三个月后另一台机器也要装、结果拿到的是另一批包"的混乱里,它是唯一靠谱的锚点。
定期做的事只有两件:一是清理/var/log和/tmp,二是检查磁盘。图形桌面的日志比纯命令行多得多,~/.xsession-errors这个文件能悄悄涨到几个 G,logrotate默认是不管的。加一条 crontab 更省心:
0 3 * * * find /home -name ".xsession-errors*" -size +100M -delete我在这套方案上前后做过十几次部署,从最初的"漏包跑两趟"到后来能一次装通,真正起作用的不是哪个高级技巧,而是三件事:下载机用干净的同版本系统、依赖用 repotrack 拉全、所有配置文件改完必须chmod +x并且手动跑一遍验证。第三条尤其重要,startwm.sh我至少有三四次是因为权限或者手动跑报错才发现问题,而不是等到用户连上来才暴露。离线环境里没有yum install给你兜底,能提前手动跑一遍的,别省这个动作。