- Disables Wayland in GDM/SDDM/LightDM (forces Xorg) - Xorg startup with -ac (no MIT-MAGIC-COOKIE auth issues) - Xvfb fallback if Xorg dummy fails - Proper xauth cookie generation for Xorg - Detects pre-installed RustDesk and stops conflicting system service - dpkg --force-depends --force-confnew + apt-get install -f - All 8 steps: arch detect → deps → sleep disable → display detect → dummy config → virtual display → RustDesk install → config + systemd Tested on: Ubuntu 22.04 x86_64 (192.168.2.28) Fixes #7
408 lines
13 KiB
Bash
Executable File
408 lines
13 KiB
Bash
Executable File
#!/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
|