diff --git a/config/systemd/rustdesk-headless-inhibit.service b/config/systemd/rustdesk-headless-inhibit.service new file mode 100644 index 0000000..4697615 --- /dev/null +++ b/config/systemd/rustdesk-headless-inhibit.service @@ -0,0 +1,18 @@ +[Unit] +Description=Inhibit system sleep while RustDesk is active +After=rustdesk-headless.service + +[Service] +Type=simple +ExecStart=/bin/bash -c '\ + while true; do \ + if pgrep -f "/usr/share/rustdesk/rustdesk --server" >/dev/null; then \ + systemd-inhibit --what=sleep:idle:handle-lid-switch --who="RustDesk" --why="Remote access active" sleep 60; \ + else \ + sleep 5; \ + fi; \ + done' +Restart=always + +[Install] +WantedBy=multi-user.target diff --git a/config/systemd/rustdesk-headless.service b/config/systemd/rustdesk-headless.service new file mode 100644 index 0000000..1244236 --- /dev/null +++ b/config/systemd/rustdesk-headless.service @@ -0,0 +1,40 @@ +[Unit] +Description=RustDesk Headless Server (auto-display, sleep-safe) +After=display-manager.service graphical.target network.target +Wants=display-manager.service + +[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" +Environment="LIBGL_ALWAYS_INDIRECT=1" + +# Force DUMMY0 primary before starting +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 +ExecStartPost=/bin/bash -c 'echo "RustDesk started, ID: $(/usr/share/rustdesk/rustdesk --get-id 2>/dev/null || echo unknown)" >> /tmp/rustdesk-server.log' + +Restart=always +RestartSec=10 +StartLimitInterval=60 +StartLimitBurst=3 + +# Prevent system sleep while RustDesk is active +ExecStopPost=/bin/systemctl start --no-block rustdesk-headless-inhibit.service + +[Install] +WantedBy=multi-user.target diff --git a/install.sh b/install.sh index 49098e9..f75505c 100755 --- a/install.sh +++ b/install.sh @@ -2,9 +2,8 @@ set -euo pipefail ####################################### -# RDtop — One-Command RustDesk Headless Installer -# Works on any Linux (Intel iGPU, AMD, NVIDIA, CPU-only, VPS) -# Usage: curl -fsSL https://git.softuniq.eu/NW/RDtop/raw/branch/main/install.sh | sudo bash +# RDtop — Universal RustDesk Headless Installer +# One command: curl -fsSL https://git.softuniq.eu/NW/RDtop/raw/branch/main/install.sh | sudo bash ####################################### ARCH=$(uname -m) @@ -29,23 +28,67 @@ echo " Arch: $ARCH | Package: ${RUSTDESK_ARCH}.deb" echo "============================================" echo "" -# --- 1. Install dependencies --- -log "[1/6] Installing dependencies..." +# --- 1. Install dependencies (verbose on fresh machine) --- +log "[2/8] Installing dependencies..." +export DEBIAN_FRONTEND=noninteractive + if command -v apt-get >/dev/null 2>&1; then - export DEBIAN_FRONTEND=noninteractive - apt-get update -qq >/dev/null 2>&1 || true - apt-get install -y -qq curl wget xserver-xorg-core xserver-xorg-video-dummy >/dev/null 2>&1 || true - apt-get install -y -qq libva2 libvdpau1 >/dev/null 2>&1 || true + apt-get update -qq || true + # Core packages — must succeed + apt-get install -y -qq curl wget ca-certificates gnupg lsb-release >/dev/null 2>&1 || { + log " CRITICAL: Failed to install base tools (curl/wget)" + exit 1 + } + # Xorg + dummy driver + apt-get install -y -qq xserver-xorg-core xserver-xorg-video-dummy x11-xserver-utils >/dev/null 2>&1 || true + # VA/VDPAU libs (RustDesk needs these) + apt-get install -y -qq libva2 libvdpau1 libva-drm2 libva-x11-2 >/dev/null 2>&1 || true + # Polkit + inhibit (for preventing sleep) + 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 >/dev/null 2>&1 || true + dnf install -y curl wget xorg-x11-server-Xorg xorg-x11-drv-dummy 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 >/dev/null 2>&1 || true -else - log "WARNING: Unknown package manager. Trying to continue..." + pacman -Sy --noconfirm curl wget xorg-server xf86-video-dummy polkit dbus >/dev/null 2>&1 || true fi -# --- 2. Detect display environment --- -log "[2/6] Detecting display environment..." +# --- 2. Disable sleep / suspend / screensaver (critical for headless) --- +log "[3/8] Disabling sleep, suspend, hibernate, screensaver..." + +# systemd — mask sleep targets +systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target 2>/dev/null || true + +# logind — prevent idle sleep +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 + +# GNOME / gsettings — disable screensaver and lock (if available) +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 + +# X11 — disable screen blanking +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 + +# --- 3. Detect display environment --- +log "[4/8] Detecting display environment..." HAS_DISPLAY=false HAS_XORG=false @@ -59,15 +102,15 @@ if pgrep -x "Xorg" >/dev/null 2>&1 || pgrep -x "X" >/dev/null 2>&1; then log " Xorg already running" fi -# --- 3. Setup dummy driver if headless --- -log "[3/6] Setting up dummy driver..." +# --- 4. Setup dummy driver (force DUMMY0 as primary) --- +log "[5/8] Setting up dummy driver + forcing DUMMY0 primary..." mkdir -p /etc/X11/xorg.conf.d/ # Remove conflicting configs 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 -# Create dummy config (works for both host and VPS) +# Create dummy config with explicit primary output cat > /etc/X11/xorg.conf.d/20-dummy-headless.conf <<'XORG' Section "Device" Identifier "DummyHeadless" @@ -89,85 +132,131 @@ Section "Screen" 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 -# --- 4. Start Xorg if headless --- +# --- 5. Start Xorg if headless --- if [ "$HAS_DISPLAY" = false ] && [ "$HAS_XORG" = false ]; then - log "[4/6] Starting Xorg dummy display on :0..." - # Ensure no stale locks + log "[6/8] Starting Xorg dummy display on :0..." rm -f /tmp/.X11-unix/X0 /tmp/.X0-lock 2>/dev/null || true mkdir -p /tmp/.X11-unix chmod 1777 /tmp/.X11-unix - # Start Xorg with dummy config + # Start Xorg with dummy config (explicit config file) if [ "$EUID" -eq 0 ]; then nohup Xorg :0 -config /etc/X11/xorg.conf.d/20-dummy-headless.conf -nolisten tcp >/tmp/xorg-dummy.log 2>&1 & else - log " WARNING: Not root, trying xvfb-run fallback..." + log " WARNING: Not root, trying Xvfb..." apt-get install -y -qq xvfb >/dev/null 2>&1 || true fi - sleep 3 + sleep 4 # Verify if [ -S /tmp/.X11-unix/X0 ]; then log " Xorg dummy display :0 created" else log " WARNING: Xorg socket not found, trying 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 2 + sleep 3 fi - # Setup xauth for root + # Setup xauth if [ "$EUID" -eq 0 ]; then xauth -f /root/.Xauthority add :0 . $(mcookie) 2>/dev/null || true chmod 600 /root/.Xauthority 2>/dev/null || true fi else - log "[4/6] Existing display detected, skipping Xorg startup" + log " Step 6 skipped: existing display detected" fi export DISPLAY=:0 export XAUTHORITY="${XAUTHORITY:-/root/.Xauthority}" -# --- 5. Download & install RustDesk --- -log "[5/6] Downloading RustDesk ${RUSTDESK_VERSION} for ${RUSTDESK_ARCH}..." +# Force DUMMY0 as primary BEFORE RustDesk starts +log " Forcing DUMMY0 as primary output..." +if command -v xrandr >/dev/null 2>&1; then + # Wait for xrandr to see outputs + for i in 1 2 3 4 5; do + if xrandr >/dev/null 2>&1; then + # Check if DUMMY0 exists + if xrandr | grep -q "^DUMMY0"; then + xrandr --output DUMMY0 --mode "1920x1080" --primary 2>/dev/null || true + log " DUMMY0 set to primary 1920x1080" + break + fi + # Check if VIRTUAL1 exists (intel fallback) + 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 set to primary 1920x1080" + break + fi + fi + sleep 1 + done +fi +# --- 6. Download & install RustDesk (with fallback) --- +log "[7/8] Downloading RustDesk ${RUSTDESK_VERSION}..." + +# Try .deb from GitHub if command -v curl >/dev/null 2>&1; then - curl -fsSL -o "$TMP_DEB" "$RUSTDESK_URL" 2>&1 || true + 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>&1 || true + wget -q -O "$TMP_DEB" "$RUSTDESK_URL" 2>/dev/null || true fi -if [ ! -f "$TMP_DEB" ] || [ ! -s "$TMP_DEB" ]; then - log "ERROR: Failed to download RustDesk .deb" - log "URL: $RUSTDESK_URL" - log "Trying to install from repository..." - apt-get install -y -qq rustdesk 2>/dev/null || true -fi +INSTALL_OK=false if [ -f "$TMP_DEB" ] && [ -s "$TMP_DEB" ]; then - log " Installing from downloaded .deb..." - dpkg -i "$TMP_DEB" >/dev/null 2>&1 || apt-get install -f -y -qq >/dev/null 2>&1 || true + log " Installing from .deb..." + # Force install even if dependencies missing (fix with apt-get after) + dpkg --force-depends --force-confnew -i "$TMP_DEB" >/dev/null 2>&1 || true + # Fix any missing deps + 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 -# Verify installation -if [ ! -f /usr/share/rustdesk/rustdesk ]; then - log "ERROR: RustDesk not found at /usr/share/rustdesk/rustdesk" - log "Installation failed. Check /tmp/rdtop-install.log" +# Fallback: install from repo if .deb failed or not downloaded +if [ "$INSTALL_OK" = false ]; then + log " .deb failed or not available, trying repository install..." + apt-get install -y -qq rustdesk 2>/dev/null || true + + # Check again + if [ -f /usr/share/rustdesk/rustdesk ]; then + INSTALL_OK=true + fi +fi + +if [ "$INSTALL_OK" = false ]; then + log "ERROR: RustDesk installation failed. Check /tmp/rdtop-install.log" exit 1 fi -# --- 6. Start RustDesk & output credentials --- -log "[6/6] Starting RustDesk server..." +log " RustDesk installed: $(/usr/share/rustdesk/rustdesk --version 2>/dev/null || echo 'unknown')" + +# --- 7. Configure RustDesk for headless (no monitor selection, survive lock) --- +log "[8/8] Configuring RustDesk for headless + sleep-safe..." -# Create config dir mkdir -p ~/.config/rustdesk -# Write initial config with public rendezvous (for stable ID) +# Write config: public rendezvous, auto-display selection disabled (DUMMY0 is primary) cat > ~/.config/rustdesk/RustDesk2.toml <<'EOF' rendezvous_server = 'rs-ny.rustdesk.com:21116' nat_type = 1 @@ -176,45 +265,54 @@ unlock_pin = '' [options] local-ip-addr = 'auto' +hw-codec = 'N' EOF chmod 600 ~/.config/rustdesk/RustDesk2.toml -# Start server +# Kill any old RustDesk pkill -f "/usr/share/rustdesk/rustdesk" 2>/dev/null || true -sleep 1 +sleep 2 +# Start RustDesk with all env vars export DISPLAY=:0 export 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 running +if ! pgrep -f "/usr/share/rustdesk/rustdesk --server" >/dev/null; then + log "WARNING: RustDesk server not running, retrying..." + 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") -# Read or set password +# Get or set password RUSTDESK_PASS="" if [ -f ~/.config/rustdesk/RustDesk.toml ]; then - # Try to read encrypted password (it won't be plaintext) RUSTDESK_PASS=$(python3 -c " import sys try: with open(sys.argv[1]) as f: - for line in f: + content = f.read() + for line in content.split('\n'): if 'password' in line and '=' in line: - parts = line.split('=') - if len(parts) > 1: - print(parts[1].strip().strip(\"'\")) - break + 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="<генерируется RustDesk — посмотрите в GUI>" + RUSTDESK_PASS="<пароль в GUI: rustdesk → Настройки → Безопасность>" fi # Summary @@ -223,17 +321,74 @@ echo "============================================" echo " RustDesk Ready!" echo "============================================" echo "" -printf " %-12s %s\n" "ID:" "$RUSTDESK_ID" -printf " %-12s %s\n" "Password:" "$RUSTDESK_PASS" -printf " %-12s %s\n" "Display:" ":0 (1920x1080 dummy)" -printf " %-12s %s\n" "Version:" "$RUSTDESK_VERSION" -printf " %-12s %s\n" "Arch:" "$ARCH" +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" "Sleep/Lock:" "disabled (systemd masked)" +printf " %-14s %s\n" "Version:" "$RUSTDESK_VERSION" +printf " %-14s %s\n" "Arch:" "$ARCH" echo "" -echo " Connect: rustdesk $RUSTDESK_ID" -echo " Logs: /tmp/rdtop-install.log" -echo " RustDesk: /tmp/rustdesk-server.log" -echo " Xorg: /tmp/xorg-dummy.log" +echo " Connect: rustdesk $RUSTDESK_ID" +echo " Status: systemctl status display-manager" +echo " Logs: /tmp/rdtop-install.log" +echo " RustDesk: /tmp/rustdesk-server.log" +echo " Xorg: /tmp/xorg-dummy.log" echo "" echo "============================================" log "Installation complete. ID: $RUSTDESK_ID" + +# Post-install: show monitor status +if command -v xrandr >/dev/null 2>&1; then + echo "" + echo "--- Current monitor status ---" + xrandr --listmonitors 2>/dev/null || echo "xrandr not available" +fi + +# --- 8. Install systemd unit for RustDesk (survives sleep/lock) --- +log "[8/8] Installing systemd unit..." + +# Write unit inline +cat > /etc/systemd/system/rustdesk-headless.service <<'UNIT' +[Unit] +Description=RustDesk Headless Server (auto-display, sleep-safe) +After=display-manager.service graphical.target network.target +Wants=display-manager.service + +[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" +Environment="LIBGL_ALWAYS_INDIRECT=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 +StartLimitInterval=60 +StartLimitBurst=3 + +[Install] +WantedBy=multi-user.target +UNIT + +systemctl daemon-reload +systemctl enable rustdesk-headless.service + +# Stop the nohup process and 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: rustdesk-headless.service ACTIVE" +else + log " WARNING: rustdesk-headless.service not active, using nohup fallback" + nohup /usr/share/rustdesk/rustdesk --server >/tmp/rustdesk-server.log 2>&1 & +fi