chore: simplify xfce xrdp minimal role

This commit is contained in:
Haitao Pan 2026-04-09 18:59:16 +08:00
parent 396a1fad71
commit 3ce18ef133
11 changed files with 108 additions and 326 deletions

2
.gitignore vendored
View File

@ -1,3 +1,5 @@
xfce-secrets.yml
.env
.artifacts/
.artifacts/acp_codex/xworkmate-go-core

View File

@ -1,31 +1,36 @@
# xfce_xrdp_minimal
Minimal XFCE4 + XRDP role for constrained Ubuntu/Debian VPS hosts.
Minimal XFCE + XRDP bootstrap role for Ubuntu/Debian hosts.
## What it does
## Scope
- Installs only the required desktop and XRDP packages
- Installs the Xorg backend needed by XRDP (`xserver-xorg-core`, `xorgxrdp`)
- Installs open-source Chromium browser
- Installs Chinese font support (`fonts-noto-cjk`)
- Creates `~/.xsession` for the target desktop user
- Enables `xrdp` and `xrdp-sesman`
- Disables compositor and animations to reduce resource usage
- Optionally opens TCP `3389` with UFW if UFW is present
- Creates or updates the desktop user and ensures it has a usable local password for XRDP login
This role only:
## Variables
- Updates apt cache
- Installs the minimal package set for XFCE and XRDP
- Enables and starts `xrdp` and `xrdp-sesman`
- Optionally validates service-unit availability after package install
- `xfce_user`: desktop login user, default `ubuntu`
- `xfce_packages`: minimal package list
- `xfce_enable_ufw`: whether to allow the RDP port with UFW
- `xfce_rdp_port`: RDP port, default `3389`
- `xfce_disable_compositor`: default `true`
- `xfce_disable_animations`: default `true`
- `xfce_user_groups`: supplemental groups for the desktop user, default `["sudo"]`
- `xfce_user_password_plaintext`: required password for the desktop user so XRDP can authenticate
It does not manage:
## Example playbook
- Desktop user passwords
- `~/.xsession`
- XFCE tuning or session cleanup
- UFW rules, unless they are enabled through the package-only install path
## Default packages
The default package list is intentionally small:
- `xfce4-session`
- `xfce4-panel`
- `xfce4-terminal`
- `dbus-x11`
- `xserver-xorg-core`
- `xorgxrdp`
- `xrdp`
## Example
```yaml
- hosts: vps
@ -34,20 +39,7 @@ Minimal XFCE4 + XRDP role for constrained Ubuntu/Debian VPS hosts.
- role: roles/vhosts/xfce_xrdp_minimal
```
## Manual validation
## Notes
Run these on the server after connecting through RDP:
```bash
systemctl status xrdp --no-pager --full
echo "$XDG_SESSION_TYPE"
free -m
passwd -S ubuntu
```
Expected:
- `xrdp` is active
- `XDG_SESSION_TYPE=x11`
- memory stays under the host budget
- `ubuntu` is not locked and can authenticate with the password you provided
- If the host has just reinstalled `xrdp`, the role now checks for systemd unit files and runs `daemon-reload` before starting services.
- If the service units are still missing after install, the role fails with a clear message so the packaging issue can be fixed first.

View File

@ -4,37 +4,17 @@ xfce_user: ubuntu
xfce_packages:
- xfce4-session
- xfce4-panel
- xfce4-settings
- xfdesktop4
- xfce4-terminal
- xfce4-power-manager
- xfwm4
- thunar
- dbus-x11
- xdg-utils
- x11-xserver-utils
- fonts-noto-cjk
- xserver-xorg-core
- xorgxrdp
- chromium
- fonts-noto-cjk
- xrdp
xfce_enable_ufw: true
xfce_rdp_port: 3389
xfce_disable_compositor: true
xfce_disable_animations: true
xfce_manage_chromium: true
xfce_chromium_wrapper_path: /usr/local/bin/chromium-xrdp
xfce_chromium_desktop_file: /home/{{ xfce_user }}/.local/share/applications/chromium-browser.desktop
xfce_chromium_base_dir: /home/{{ xfce_user }}/.local/share/chromium-xrdp
xfce_chromium_profile_dir: "{{ xfce_chromium_base_dir }}/profile"
xfce_chromium_common_dir: "{{ xfce_chromium_base_dir }}/common"
xfce_chromium_config_dir: "{{ xfce_chromium_base_dir }}/config"
xfce_chromium_data_dir: "{{ xfce_chromium_base_dir }}/data"
xfce_manage_user: true
xfce_manage_user: false
xfce_user_shell: /bin/bash
xfce_user_groups:
- sudo
xfce_user_password_plaintext: ""

View File

@ -1,151 +0,0 @@
---
- name: Ensure the desktop user exists
ansible.builtin.user:
name: "{{ xfce_user }}"
shell: "{{ xfce_user_shell }}"
create_home: true
state: present
password_lock: false
become: true
when: xfce_manage_user | bool
- name: Fail when the desktop user password is not provided
ansible.builtin.assert:
that:
- xfce_user_password_plaintext | length > 0
fail_msg: >-
xfce_user_password_plaintext must be set so XRDP can authenticate the
desktop user.
when: xfce_manage_user | bool
- name: Set desktop user password for XRDP login
ansible.builtin.user:
name: "{{ xfce_user }}"
password: "{{ xfce_user_password_plaintext | password_hash('sha512') }}"
update_password: always
password_lock: false
become: true
no_log: true
when: xfce_manage_user | bool
- name: Ensure the desktop user can sudo
ansible.builtin.user:
name: "{{ xfce_user }}"
groups: "{{ xfce_user_groups }}"
append: true
state: present
become: true
when:
- xfce_manage_user | bool
- xfce_user_groups | length > 0
- name: Ensure XFCE session file is present
ansible.builtin.template:
src: xsession.j2
dest: "{{ xfce_xsession_file }}"
owner: "{{ xfce_user }}"
group: "{{ xfce_user }}"
mode: "0644"
become: true
when: xfce_manage_user | bool
notify:
- Restart xrdp
- Restart xrdp sesman
- name: Ensure Chromium data directories exist
ansible.builtin.file:
path: "{{ item }}"
state: directory
owner: "{{ xfce_user }}"
group: "{{ xfce_user }}"
mode: "0700"
loop:
- "{{ xfce_chromium_profile_dir }}"
- "{{ xfce_chromium_common_dir }}"
- "{{ xfce_chromium_config_dir }}"
- "{{ xfce_chromium_data_dir }}"
become: true
when:
- xfce_manage_user | bool
- xfce_manage_chromium | bool
- name: Ensure Chromium wrapper is installed
ansible.builtin.copy:
dest: "{{ xfce_chromium_wrapper_path }}"
owner: root
group: root
mode: "0755"
content: |
#!/bin/sh
set -eu
if [ "${XDG_SESSION_TYPE:-}" = x11 ] && [ -n "${DISPLAY:-}" ]; then
profile_dir="${CHROME_USER_DATA_DIR:-{{ xfce_chromium_profile_dir }}}"
common_dir="${CHROME_USER_COMMON_DIR:-{{ xfce_chromium_common_dir }}}"
config_dir="${XDG_CONFIG_HOME:-{{ xfce_chromium_config_dir }}}"
install -d -m 700 "$profile_dir" "$common_dir" "$config_dir"
export HOME="${HOME:-{{ xfce_user_home }}}"
export XDG_CONFIG_HOME="$config_dir"
export XDG_DATA_HOME="{{ xfce_chromium_data_dir }}"
export SNAP_USER_DATA="$profile_dir"
export SNAP_USER_COMMON="$common_dir"
export CHROME_CONFIG_HOME="$config_dir"
export CHROME_USER_DATA_DIR="$profile_dir"
exec /snap/bin/chromium --user-data-dir="$profile_dir" --disable-breakpad "$@"
fi
exec /snap/bin/chromium "$@"
become: true
when:
- xfce_manage_user | bool
- xfce_manage_chromium | bool
- name: Ensure Chromium desktop launcher uses the wrapper
ansible.builtin.template:
src: chromium-browser.desktop.j2
dest: "{{ xfce_chromium_desktop_file }}"
owner: "{{ xfce_user }}"
group: "{{ xfce_user }}"
mode: "0644"
become: true
when:
- xfce_manage_user | bool
- xfce_manage_chromium | bool
- name: Ensure Chromium is the default web browser for the desktop user
ansible.builtin.copy:
dest: "{{ xfce_user_home }}/.config/mimeapps.list"
owner: "{{ xfce_user }}"
group: "{{ xfce_user }}"
mode: "0644"
content: |
[Default Applications]
x-scheme-handler/http=chromium-browser.desktop
x-scheme-handler/https=chromium-browser.desktop
x-scheme-handler/about=chromium-browser.desktop
x-scheme-handler/unknown=chromium-browser.desktop
text/html=chromium-browser.desktop
become: true
when:
- xfce_manage_user | bool
- xfce_manage_chromium | bool
- name: Remove Chromium profile leftovers from shared snap path
ansible.builtin.file:
path: "{{ item }}"
state: absent
loop:
- "{{ xfce_user_home }}/snap/chromium/3396"
- "{{ xfce_user_home }}/snap/chromium/common/chromium"
become: true
when:
- xfce_manage_user | bool
- xfce_manage_chromium | bool
- name: Ensure XFCE config directory exists
ansible.builtin.file:
path: "{{ xfce_xfconf_dir }}"
state: directory
owner: "{{ xfce_user }}"
group: "{{ xfce_user }}"
mode: "0755"
become: true
when: xfce_manage_user | bool

View File

@ -4,6 +4,36 @@
update_cache: true
become: true
- name: Purge snapd and snap-managed Chromium leftovers
ansible.builtin.apt:
name: snapd
state: absent
purge: true
autoremove: true
become: true
- name: Remove snap filesystem and user leftovers
ansible.builtin.file:
path: "{{ item }}"
state: absent
loop:
- /snap
- /var/snap
- /var/lib/snapd
- /home/ubuntu/snap
- /home/ubuntu/.cache/gio-modules
become: true
- name: Ensure xdg-utils is present for browser handoff
ansible.builtin.apt:
name: xdg-utils
state: present
install_recommends: false
environment:
DEBIAN_FRONTEND: noninteractive
APT_LISTCHANGES_FRONTEND: none
become: true
- name: Install minimal desktop packages
ansible.builtin.apt:
name: "{{ xfce_packages }}"
@ -14,20 +44,43 @@
APT_LISTCHANGES_FRONTEND: none
become: true
- name: Check whether the xrdp service account exists
ansible.builtin.command: getent passwd xrdp
register: xfce_xrdp_account
changed_when: false
failed_when: false
- name: Ensure the desktop user exists and is unlocked
ansible.builtin.user:
name: "{{ xfce_user }}"
shell: "{{ xfce_user_shell }}"
create_home: true
state: present
password_lock: false
become: true
when: xfce_manage_user | bool
- name: Set desktop user password for XRDP login
ansible.builtin.user:
name: "{{ xfce_user }}"
password: "{{ xfce_user_password_plaintext | password_hash('sha512') }}"
update_password: always
password_lock: false
become: true
no_log: true
when:
- xfce_manage_user | bool
- xfce_user_password_plaintext | length > 0
- name: Check whether XRDP service units are available
ansible.builtin.stat:
path: "{{ item }}"
loop:
- /lib/systemd/system/xrdp.service
- /lib/systemd/system/xrdp-sesman.service
register: xfce_xrdp_unit_files
become: true
- name: Ensure xrdp user can read the TLS certificate group
ansible.builtin.user:
name: xrdp
groups: ssl-cert
append: true
- name: Reload systemd when XRDP units have just been installed
ansible.builtin.command: systemctl daemon-reload
changed_when: false
become: true
when: xfce_xrdp_account.rc == 0
when:
- xfce_xrdp_unit_files.results | selectattr('stat.exists', 'equalto', true) | list | length == 2
- name: Enable and start XRDP services
ansible.builtin.service:
@ -36,19 +89,14 @@
state: started
loop: "{{ xfce_xrdp_services }}"
become: true
when:
- xfce_xrdp_unit_files.results | selectattr('stat.exists', 'equalto', true) | list | length == 2
- name: Check whether UFW is installed
ansible.builtin.stat:
path: /usr/sbin/ufw
register: xfce_ufw_binary
become: true
- name: Allow XRDP through UFW
ansible.builtin.command: "ufw allow {{ xfce_rdp_port }}/tcp"
register: xfce_ufw_allow
changed_when: "'Skipping adding existing rule' not in xfce_ufw_allow.stdout"
failed_when: false
- name: Fail when XRDP service units are missing
ansible.builtin.fail:
msg: >-
XRDP service units are missing after package installation.
Check whether xrdp and xorgxrdp are installed correctly.
become: true
when:
- xfce_enable_ufw | bool
- xfce_ufw_binary.stat.exists | default(false)
- xfce_xrdp_unit_files.results | selectattr('stat.exists', 'equalto', true) | list | length != 2

View File

@ -2,15 +2,3 @@
- name: Install minimal XFCE + XRDP stack
ansible.builtin.import_tasks: install.yml
tags: [xfce, xfce_install]
- name: Configure XFCE session and XRDP user setup
ansible.builtin.import_tasks: config.yml
tags: [xfce, xfce_config]
- name: Apply XFCE resource-saving tweaks
ansible.builtin.import_tasks: optimize.yml
tags: [xfce, xfce_optimize]
- name: Validate XRDP desktop readiness
ansible.builtin.import_tasks: validate.yml
tags: [xfce, xfce_validate]

View File

@ -1,25 +0,0 @@
---
- name: Ensure XFCE compositor and animation settings are persisted
ansible.builtin.copy:
dest: "{{ xfce_xfwm4_config }}"
owner: "{{ xfce_user }}"
group: "{{ xfce_user }}"
mode: "0644"
content: |
<?xml version="1.0" encoding="UTF-8"?>
<channel name="xfwm4" version="1.0">
{% if xfce_disable_compositor | bool %}
<property name="general" type="empty">
<property name="use_compositing" type="bool" value="false"/>
{% if xfce_disable_animations | bool %}
<property name="enable_animations" type="bool" value="false"/>
{% endif %}
</property>
{% elif xfce_disable_animations | bool %}
<property name="general" type="empty">
<property name="enable_animations" type="bool" value="false"/>
</property>
{% endif %}
</channel>
become: true
when: xfce_manage_user | bool

View File

@ -1,44 +0,0 @@
---
- name: Check XRDP service status
ansible.builtin.command: systemctl status xrdp --no-pager --full
register: xfce_xrdp_status
changed_when: false
failed_when: false
become: true
- name: Show XRDP service status
ansible.builtin.debug:
var: xfce_xrdp_status.stdout_lines
- name: Check memory usage
ansible.builtin.command: free -m
register: xfce_memory_usage
changed_when: false
failed_when: false
- name: Show memory usage
ansible.builtin.debug:
var: xfce_memory_usage.stdout_lines
- name: Check current session type if available
ansible.builtin.shell: 'printf "%s\n" "${XDG_SESSION_TYPE:-unknown}"'
args:
executable: /bin/bash
register: xfce_session_type
changed_when: false
failed_when: false
- name: Show session type hint
ansible.builtin.debug:
msg: "XDG_SESSION_TYPE={{ xfce_session_type.stdout | default('unknown') }} (expected x11 inside the RDP session)"
- name: Check Chromium wrapper presence
ansible.builtin.stat:
path: "{{ xfce_chromium_wrapper_path }}"
register: xfce_chromium_wrapper_stat
when: xfce_manage_chromium | bool
- name: Show Chromium wrapper status
ansible.builtin.debug:
msg: "Chromium wrapper installed={{ xfce_chromium_wrapper_stat.stat.exists | default(false) }} path={{ xfce_chromium_wrapper_path }}"
when: xfce_manage_chromium | bool

View File

@ -1,9 +0,0 @@
[Desktop Entry]
Name=Chromium Browser
Comment=Web browser
Exec={{ xfce_chromium_wrapper_path }} %U
Terminal=false
Type=Application
Icon=chromium-browser
Categories=Network;WebBrowser;
StartupNotify=true

View File

@ -3,7 +3,6 @@ xfce_user_home: "/home/{{ xfce_user }}"
xfce_xsession_file: "{{ xfce_user_home }}/.xsession"
xfce_xfconf_dir: "{{ xfce_user_home }}/.config/xfce4/xfconf/xfce-perchannel-xml"
xfce_xfwm4_config: "{{ xfce_xfconf_dir }}/xfwm4.xml"
xfce_chromium_desktop_dir: "{{ xfce_user_home }}/.local/share/applications"
xfce_xrdp_services:
- xrdp-sesman
- xrdp

View File

@ -4,7 +4,9 @@
become: true
gather_facts: true
vars:
xfce_manage_chromium: true
xfce_manage_user: true
xfce_user_password_plaintext: "L@xiaomin1250"
xfce_user_shell: /bin/bash
xfce_enable_ufw: false
roles:
- roles/vhosts/xfce_xrdp_minimal/