#!/bin/bash set -euo pipefail ####################################### # RDtop — Universal RustDesk Headless Installer # One command → ID + Password → Ready # Disables Wayland, forces Xorg/Xvfb, auto-selects display ####################################### ARCH=$(uname -m) case "$ARCH" in x86_64) RUSTDESK_ARCH="x86_64"; DEB_ARCH="amd64" ;; aarch64) RUSTDESK_ARCH="aarch64"; DEB_ARCH="arm64" ;; armv7l) RUSTDESK_ARCH="armv7"; DEB_ARCH="armhf" ;; *) echo "ERROR: Unsupported architecture: $ARCH"; exit 1 ;; esac RUSTDESK_VERSION="1.4.6" RUSTDESK_URL="https://github.com/rustdesk/rustdesk/releases/download/${RUSTDESK_VERSION}/rustdesk-${RUSTDESK_VERSION}-${RUSTDESK_ARCH}.deb" TMP_DEB="/tmp/rustdesk-${RUSTDESK_VERSION}-${DEB_ARCH}.deb" LOG="/tmp/rdtop-install.log" log() { echo "[$(date '+%F %T')] $1" | tee -a "$LOG"; } echo "" echo "============================================" echo " RDtop — RustDesk Headless Installer" echo " Arch: $ARCH | Package: ${RUSTDESK_ARCH}.deb" echo "============================================" echo "" # --- 1/8 Detect arch --- log "[1/8] Arch: $ARCH, target: ${RUSTDESK_ARCH}.deb" # --- 2/8 Install deps + disable Wayland --- log "[2/8] Installing dependencies + disabling Wayland..." export DEBIAN_FRONTEND=noninteractive if command -v apt-get >/dev/null 2>&1; then apt-get update -qq || true # Must-succeed base apt-get install -y -qq curl wget ca-certificates >/dev/null 2>&1 || { log "CRITICAL: no curl/wget"; exit 1; } # Xorg stack apt-get install -y -qq xserver-xorg-core xserver-xorg-video-dummy x11-xserver-utils xvfb xauth >/dev/null 2>&1 || true # VA/VDPAU apt-get install -y -qq libva2 libvdpau1 libva-drm2 libva-x11-2 >/dev/null 2>&1 || true # Polkit + inhibit apt-get install -y -qq policykit-1 dbus dbus-x11 >/dev/null 2>&1 || true elif command -v dnf >/dev/null 2>&1; then dnf install -y curl wget xorg-x11-server-Xorg xorg-x11-drv-dummy xvfb xauth polkit dbus >/dev/null 2>&1 || true elif command -v pacman >/dev/null 2>&1; then pacman -Sy --noconfirm curl wget xorg-server xf86-video-dummy xvfb xauth polkit dbus >/dev/null 2>&1 || true fi # Disable Wayland — force Xorg for GDM (Ubuntu/Debian GNOME) for gdm_conf in /etc/gdm3/custom.conf /etc/gdm/custom.conf; do if [ -f "$gdm_conf" ]; then if ! grep -q "^WaylandEnable=false" "$gdm_conf" 2>/dev/null; then sed -i 's/^#\?WaylandEnable=.*/WaylandEnable=false/' "$gdm_conf" 2>/dev/null || true if ! grep -q "WaylandEnable=false" "$gdm_conf" 2>/dev/null; then sed -i '/\[daemon\]/a WaylandEnable=false' "$gdm_conf" 2>/dev/null || true fi log " Wayland disabled in $gdm_conf" fi fi done # Also ensure Xorg is default for SDDM (KDE) and LightDM if [ -f /etc/sddm.conf ]; then sed -i 's/^DisplayServer=.*/DisplayServer=x11/' /etc/sddm.conf 2>/dev/null || true fi if [ -f /etc/lightdm/lightdm.conf ]; then sed -i 's/^#\?display-manager=.*/display-manager=xorg/' /etc/lightdm/lightdm.conf 2>/dev/null || true fi # --- 3/8 Disable sleep / lock --- log "[3/8] Disabling sleep, suspend, hibernate, screensaver..." systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target 2>/dev/null || true if [ -f /etc/systemd/logind.conf ]; then cp /etc/systemd/logind.conf /etc/systemd/logind.conf.bak.$(date +%s) 2>/dev/null || true cat > /etc/systemd/logind.conf <<'EOF' [Login] HandleLidSwitch=ignore HandleLidSwitchExternalPower=ignore HandleLidSwitchDocked=ignore IdleAction=ignore EOF systemctl restart systemd-logind 2>/dev/null || true log " systemd-logind: sleep disabled" fi if command -v gsettings >/dev/null 2>&1; then gsettings set org.gnome.desktop.screensaver lock-enabled false 2>/dev/null || true gsettings set org.gnome.desktop.screensaver idle-activation-enabled false 2>/dev/null || true gsettings set org.gnome.desktop.session idle-delay 0 2>/dev/null || true gsettings set org.gnome.desktop.screensaver lock-active false 2>/dev/null || true log " GNOME screensaver: disabled" fi if command -v xset >/dev/null 2>&1; then xset s off 2>/dev/null || true xset -dpms 2>/dev/null || true xset s noblank 2>/dev/null || true fi # --- 4/8 Detect display --- log "[4/8] Detecting display environment..." HAS_DISPLAY=false HAS_XORG=false if [ -n "${DISPLAY:-}" ] && xdpyinfo >/dev/null 2>&1; then HAS_DISPLAY=true log " Active display: $DISPLAY" fi if pgrep -x "Xorg" >/dev/null 2>&1 || pgrep -x "X" >/dev/null 2>&1; then HAS_XORG=true log " Xorg already running" fi # --- 5/8 Setup dummy driver --- log "[5/8] Setting up dummy driver..." mkdir -p /etc/X11/xorg.conf.d/ rm -f /etc/X11/xorg.conf.d/20-intel-virtual.conf 2>/dev/null || true rm -f /etc/X11/xorg.conf.d/90-fallback.conf 2>/dev/null || true cat > /etc/X11/xorg.conf.d/20-dummy-headless.conf <<'XORG' Section "Device" Identifier "DummyHeadless" Driver "dummy" VideoRam 256000 EndSection Section "Monitor" Identifier "DummyMonitor" HorizSync 28-80 VertRefresh 48-75 EndSection Section "Screen" Identifier "DummyScreen" Device "DummyHeadless" Monitor "DummyMonitor" DefaultDepth 24 SubSection "Display" Depth 24 Modes "1920x1080" "1280x720" Virtual 1920 1080 EndSubSection EndSection Section "ServerLayout" Identifier "DummyLayout" Screen 0 "DummyScreen" 0 0 Option "AutoAddGPU" "false" EndSection XORG chmod 644 /etc/X11/xorg.conf.d/20-dummy-headless.conf # --- 6/8 Start virtual display --- if [ "$HAS_DISPLAY" = false ] && [ "$HAS_XORG" = false ]; then log "[6/8] Starting virtual display on :0..." # Clean everything pkill -x Xorg 2>/dev/null || true pkill -x Xvfb 2>/dev/null || true rm -f /tmp/.X11-unix/X0 /tmp/.X0-lock /root/.Xauthority 2>/dev/null || true mkdir -p /tmp/.X11-unix chmod 1777 /tmp/.X11-unix # Try Xorg first (with -ac no-auth, dummy config) if [ "$EUID" -eq 0 ]; then nohup Xorg :0 -config /etc/X11/xorg.conf.d/20-dummy-headless.conf -ac -nolisten tcp >/tmp/xorg-dummy.log 2>&1 & sleep 5 fi if [ -S /tmp/.X11-unix/X0 ] && pgrep -x Xorg >/dev/null; then log " Xorg dummy :0 OK" # Generate xauth cookie COOKIE=$(mcookie) xauth -f /root/.Xauthority add :0 . "$COOKIE" 2>/dev/null || true xauth add :0 . "$COOKIE" 2>/dev/null || true chmod 600 /root/.Xauthority 2>/dev/null || true export XAUTHORITY=/root/.Xauthority else # Xvfb fallback — always works, -ac = no auth needed log " Xorg failed, using Xvfb..." pkill -x Xorg 2>/dev/null || true rm -f /tmp/.X11-unix/X0 /tmp/.X0-lock 2>/dev/null || true nohup Xvfb :0 -screen 0 1920x1080x24 +extension GLX +extension RANDR +extension RENDER -ac >/tmp/xvfb.log 2>&1 & sleep 4 if [ -S /tmp/.X11-unix/X0 ]; then log " Xvfb :0 OK (no auth)" # Xvfb with -ac does not need xauth export XAUTHORITY="" else log "CRITICAL: No display could start" exit 1 fi fi else log " Step 6 skipped: existing display" fi export DISPLAY=:0 # Force DUMMY0/VIRTUAL1 primary before RustDesk log " Forcing primary output..." if command -v xrandr >/dev/null 2>&1; then for i in $(seq 1 10); do if xrandr >/dev/null 2>&1; then if xrandr | grep -q "^DUMMY0"; then xrandr --output DUMMY0 --mode "1920x1080" --primary 2>/dev/null || true log " DUMMY0 primary" break fi if xrandr | grep -q "^VIRTUAL1"; then xrandr --newmode "1920x1080_60" 173.00 1920 2048 2248 2576 1080 1083 1088 1120 2>/dev/null || true xrandr --addmode VIRTUAL1 "1920x1080_60" 2>/dev/null || true xrandr --output VIRTUAL1 --mode "1920x1080_60" --primary 2>/dev/null || true log " VIRTUAL1 primary" break fi fi sleep 1 done fi # --- 7/8 Install RustDesk --- log "[7/8] Installing RustDesk..." # Check if already installed (from repo) if [ -f /usr/share/rustdesk/rustdesk ]; then log " RustDesk already installed" if systemctl is-active rustdesk >/dev/null 2>&1; then log " Stopping system rustdesk service..." systemctl stop rustdesk 2>/dev/null || true pkill -f "/usr/bin/rustdesk --service" 2>/dev/null || true sleep 2 fi fi # Download .deb if command -v curl >/dev/null 2>&1; then curl -fsSL -o "$TMP_DEB" "$RUSTDESK_URL" 2>/dev/null || true elif command -v wget >/dev/null 2>&1; then wget -q -O "$TMP_DEB" "$RUSTDESK_URL" 2>/dev/null || true fi INSTALL_OK=false if [ -f /usr/share/rustdesk/rustdesk ]; then INSTALL_OK=true fi if [ -f "$TMP_DEB" ] && [ -s "$TMP_DEB" ]; then log " Installing from .deb..." dpkg --force-depends --force-confnew -i "$TMP_DEB" >/dev/null 2>&1 || true apt-get install -f -y -qq >/dev/null 2>&1 || true rm -f "$TMP_DEB" if [ -f /usr/share/rustdesk/rustdesk ]; then INSTALL_OK=true fi fi if [ "$INSTALL_OK" = false ]; then log " Trying repository install..." apt-get install -y -qq rustdesk 2>/dev/null || true if [ -f /usr/share/rustdesk/rustdesk ]; then INSTALL_OK=true fi fi if [ "$INSTALL_OK" = false ]; then log "CRITICAL: RustDesk installation failed" exit 1 fi log " RustDesk OK: $(/usr/share/rustdesk/rustdesk --version 2>/dev/null || echo unknown)" # --- 8/8 Configure and start RustDesk --- log "[8/8] Configuring RustDesk..." mkdir -p ~/.config/rustdesk cat > ~/.config/rustdesk/RustDesk2.toml <<'EOF' rendezvous_server = 'rs-ny.rustdesk.com:21116' nat_type = 1 serial = 0 unlock_pin = '' [options] local-ip-addr = 'auto' hw-codec = 'N' EOF chmod 600 ~/.config/rustdesk/RustDesk2.toml # Kill old RustDesk pkill -f "/usr/share/rustdesk/rustdesk" 2>/dev/null || true sleep 2 # Start with software rendering (no GL needed) export DISPLAY=:0 export XAUTHORITY="${XAUTHORITY:-/root/.Xauthority}" export LIBVA_DRIVER_NAME=none export VDPAU_DRIVER=none export LIBGL_ALWAYS_SOFTWARE=1 export LIBGL_ALWAYS_INDIRECT=1 nohup /usr/share/rustdesk/rustdesk --server >/tmp/rustdesk-server.log 2>&1 & sleep 5 # Verify if ! pgrep -f "/usr/share/rustdesk/rustdesk --server" >/dev/null; then log " Retry RustDesk start..." sleep 3 nohup /usr/share/rustdesk/rustdesk --server >/tmp/rustdesk-server.log 2>&1 & sleep 3 fi # Get credentials RUSTDESK_ID=$(/usr/share/rustdesk/rustdesk --get-id 2>/dev/null || echo "N/A") RUSTDESK_PASS="" if [ -f ~/.config/rustdesk/RustDesk.toml ]; then RUSTDESK_PASS=$(python3 -c " import sys try: with open(sys.argv[1]) as f: content = f.read() for line in content.split('\n'): if 'password' in line and '=' in line: val = line.split('=', 1)[1].strip().strip(\"'\").strip('\"') if val: print(val); break except: pass " ~/.config/rustdesk/RustDesk.toml 2>/dev/null || true) fi if [ -z "$RUSTDESK_PASS" ]; then RUSTDESK_PASS="<пароль в GUI: Настройки → Безопасность>" fi # Install systemd unit log " Installing systemd unit..." cat > /etc/systemd/system/rustdesk-headless.service <<'UNIT' [Unit] Description=RustDesk Headless Server After=network.target Wants=network.target [Service] Type=simple User=root Environment="DISPLAY=:0" Environment="XAUTHORITY=/root/.Xauthority" Environment="LIBVA_DRIVER_NAME=none" Environment="VDPAU_DRIVER=none" Environment="LIBGL_ALWAYS_SOFTWARE=1" ExecStartPre=/bin/bash -c 'for i in 1 2 3 4 5 6 7 8 9 10; do if xrandr >/dev/null 2>&1; then if xrandr | grep -q "^DUMMY0"; then xrandr --output DUMMY0 --mode "1920x1080" --primary 2>/dev/null || true; exit 0; fi; fi; sleep 1; done' ExecStart=/usr/share/rustdesk/rustdesk --server Restart=always RestartSec=10 [Install] WantedBy=multi-user.target UNIT systemctl daemon-reload systemctl enable rustdesk-headless.service # Stop nohup, start via systemd pkill -f "/usr/share/rustdesk/rustdesk --server" 2>/dev/null || true sleep 2 systemctl start rustdesk-headless.service sleep 3 if systemctl is-active rustdesk-headless.service >/dev/null 2>&1; then log " systemd unit ACTIVE" else log " WARNING: systemd failed, using nohup fallback" nohup /usr/share/rustdesk/rustdesk --server >/tmp/rustdesk-server.log 2>&1 & fi # Summary echo "" echo "============================================" echo " RustDesk Ready!" echo "============================================" echo "" printf " %-14s %s\n" "ID:" "$RUSTDESK_ID" printf " %-14s %s\n" "Password:" "$RUSTDESK_PASS" printf " %-14s %s\n" "Display:" ":0 (DUMMY0 primary 1920x1080)" printf " %-14s %s\n" "Wayland:" "disabled (Xorg forced)" printf " %-14s %s\n" "Sleep/Lock:" "disabled" printf " %-14s %s\n" "Version:" "$RUSTDESK_VERSION" printf " %-14s %s\n" "Arch:" "$ARCH" echo "" echo " Connect: rustdesk $RUSTDESK_ID" echo " Status: systemctl status rustdesk-headless" echo " Logs: /tmp/rdtop-install.log" echo " RustDesk: /tmp/rustdesk-server.log" echo " Xorg: /tmp/xorg-dummy.log" echo "" echo "============================================" log "Done. ID: $RUSTDESK_ID" # Show monitor status if command -v xrandr >/dev/null 2>&1; then echo "" echo "--- Monitor status ---" xrandr --listmonitors 2>/dev/null || echo "xrandr unavailable" fi