diff --git a/.gitignore b/.gitignore index 904ccde..2362ccd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +xfce-secrets.yml + .env .artifacts/ .artifacts/acp_codex/xworkmate-go-core diff --git a/roles/vhosts/xfce_xrdp_minimal/README.md b/roles/vhosts/xfce_xrdp_minimal/README.md index b98ab32..c71bc5d 100644 --- a/roles/vhosts/xfce_xrdp_minimal/README.md +++ b/roles/vhosts/xfce_xrdp_minimal/README.md @@ -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. diff --git a/roles/vhosts/xfce_xrdp_minimal/defaults/main.yml b/roles/vhosts/xfce_xrdp_minimal/defaults/main.yml index 23a7d5e..a9378ba 100644 --- a/roles/vhosts/xfce_xrdp_minimal/defaults/main.yml +++ b/roles/vhosts/xfce_xrdp_minimal/defaults/main.yml @@ -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: "" diff --git a/roles/vhosts/xfce_xrdp_minimal/tasks/config.yml b/roles/vhosts/xfce_xrdp_minimal/tasks/config.yml deleted file mode 100644 index 3666ee0..0000000 --- a/roles/vhosts/xfce_xrdp_minimal/tasks/config.yml +++ /dev/null @@ -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 diff --git a/roles/vhosts/xfce_xrdp_minimal/tasks/install.yml b/roles/vhosts/xfce_xrdp_minimal/tasks/install.yml index c945a06..2f4ee3c 100644 --- a/roles/vhosts/xfce_xrdp_minimal/tasks/install.yml +++ b/roles/vhosts/xfce_xrdp_minimal/tasks/install.yml @@ -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 diff --git a/roles/vhosts/xfce_xrdp_minimal/tasks/main.yml b/roles/vhosts/xfce_xrdp_minimal/tasks/main.yml index a3b1570..26ad303 100644 --- a/roles/vhosts/xfce_xrdp_minimal/tasks/main.yml +++ b/roles/vhosts/xfce_xrdp_minimal/tasks/main.yml @@ -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] diff --git a/roles/vhosts/xfce_xrdp_minimal/tasks/optimize.yml b/roles/vhosts/xfce_xrdp_minimal/tasks/optimize.yml deleted file mode 100644 index 35befaa..0000000 --- a/roles/vhosts/xfce_xrdp_minimal/tasks/optimize.yml +++ /dev/null @@ -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: | - - - {% if xfce_disable_compositor | bool %} - - - {% if xfce_disable_animations | bool %} - - {% endif %} - - {% elif xfce_disable_animations | bool %} - - - - {% endif %} - - become: true - when: xfce_manage_user | bool diff --git a/roles/vhosts/xfce_xrdp_minimal/tasks/validate.yml b/roles/vhosts/xfce_xrdp_minimal/tasks/validate.yml deleted file mode 100644 index a66f20c..0000000 --- a/roles/vhosts/xfce_xrdp_minimal/tasks/validate.yml +++ /dev/null @@ -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 diff --git a/roles/vhosts/xfce_xrdp_minimal/templates/chromium-browser.desktop.j2 b/roles/vhosts/xfce_xrdp_minimal/templates/chromium-browser.desktop.j2 deleted file mode 100644 index 78a4f73..0000000 --- a/roles/vhosts/xfce_xrdp_minimal/templates/chromium-browser.desktop.j2 +++ /dev/null @@ -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 diff --git a/roles/vhosts/xfce_xrdp_minimal/vars/main.yml b/roles/vhosts/xfce_xrdp_minimal/vars/main.yml index aecb02e..f4f368d 100644 --- a/roles/vhosts/xfce_xrdp_minimal/vars/main.yml +++ b/roles/vhosts/xfce_xrdp_minimal/vars/main.yml @@ -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 diff --git a/xfce_xrdp_minimal.yaml b/xfce_xrdp_minimal.yaml index 3f1a2c5..8db08d5 100644 --- a/xfce_xrdp_minimal.yaml +++ b/xfce_xrdp_minimal.yaml @@ -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/