15 Commits
master ... main

Author SHA1 Message Date
Orchestrator
4221bd53d0 fix: install.sh — Wayland disabled, Xvfb fallback, xauth fix, fresh machine ready
- 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
2026-05-16 11:31:03 +01:00
Orchestrator
5020b591aa fix: install.sh — sleep-safe, auto-display, fresh-machine install
- install.sh now has 8 steps:
  1) Detect arch, 2) Install deps, 3) Disable sleep/lock/screensaver,
  4) Detect display, 5) Setup dummy + force DUMMY0 primary,
  6) Start Xorg/Xvfb, 7) Download+install RustDesk (with apt fallback),
  8) Install systemd unit rustdesk-headless.service

- New systemd unit: rustdesk-headless.service
  * Forces DUMMY0 as primary via ExecStartPre (no monitor selection dialog)
  * Restart=always — survives any crash
  * Wants=display-manager.service — starts after graphical session

- Sleep-safe changes:
  * Mask sleep.target suspend.target hibernate.target hybrid-sleep.target
  * logind.conf: HandleLidSwitch=ignore, IdleAction=ignore
  * GNOME screensaver: gsettings lock-enabled false, idle-delay 0
  * X11: xset s off -dpms

- Fresh machine fixes:
  * dpkg --force-depends --force-confnew (installs even with missing deps)
  * apt-get install -f after dpkg (fixes broken deps)
  * Fallback to 'apt-get install rustdesk' from repo if .deb download fails
  * Added libva-drm2 libva-x11-2 (fresh systems often miss these)

- Output at end:
  * ID, Password, Display (:0 DUMMY0 primary), Sleep/Lock status
  * Monitor status via xrandr --listmonitors

Fixes #7
2026-05-16 11:19:43 +01:00
Orchestrator
3f6a62638f feat: universal one-command RustDesk installer
- install.sh: auto-detects arch, downloads latest RustDesk, sets up dummy Xorg,
  starts server, prints ID + password to console
- README.md: rewritten as universal installer guide
- Supports: x86_64, aarch64, armv7l
- Works on: Intel iGPU, AMD, NVIDIA, CPU-only, VPS

vps-rustdesk-server branch contains archived VPS relay solution
2026-05-16 10:57:59 +01:00
Orchestrator
7319689814 refactor: clean VPS code, keep only host solution in main\n
- Removed all VPS-specific scripts and configs from main branch\n- VPS solution archived in archive/vps-rustdesk-server\n- Rewrote README.md to focus on Intel Alder Lake-N host setup\n- Added note about archive branch and host-only scope\n
Fixes #6 (wontfix for VPS GUI, host solution restored)
2026-05-16 00:52:54 +01:00
Orchestrator
038b9791c5 feat: add Xvfb + RustDesk scripts for VPS GUI fix (#6)\n\n- scripts/vps/start-rustdesk-xvfb.sh: Xvfb + xcompmgr + RustDesk launcher\n- scripts/host/manual-start-rustdesk.sh: manual run script for VPS\n\nWorkaround for RustDesk v1.4.6 SIGSEGV on dummy/Xvfb display\nwhen opening GUI (Flutter requires GL/GLES compositor).\n\nCloses #6 (partial) 2026-05-16 00:46:53 +01:00
Orchestrator
43e7b30f41 feat: add host setup scripts + configs for Intel Alder Lake-N
- scripts/host/setup-host-rustdesk.sh: protect RustDesk ID on host
- scripts/host/README-host.md: instructions for manual apply
- configs/rustdesk2-host.toml.template: config template
- configs/systemd/: systemd units for both VPS and host
2026-05-16 00:16:14 +01:00
Orchestrator
32451eb0f8 feat: add client config script and systemd unit 2026-05-15 23:51:09 +01:00
Orchestrator
3f49556cd7 feat: add RustDesk Server scripts (hbbs+hbbr native, systemd, UFW)
- install-rustdesk-server.sh: download & install hbbs/hbbr from GitHub releases
- rustdesk-hbbs.service: systemd unit for ID-server (ports 21115-21116)
- rustdesk-hbbr.service: systemd unit for relay (port 21117)
- open-rustdesk-ports.sh: idempotent UFW port opening
- README.md: deployment instructions

Generated by orchestrator in APAW worktree, applied to VPS 2.59.219.61
2026-05-15 23:50:39 +01:00
Deploy Bot
554aa6008d feat: working XFCE + RustDesk online on VPS tmux
- Add start-rd-desktop.sh: Xvfb :99 + xfwm4 + xfce4-panel + RustDesk client
- Add rustdesk-vps.service (Type=simple, but systemd kills processes) → use tmux instead
- Update README.md with VPS architecture (Xvfb + xfce4-session + RustDesk)
- Update VPS section: tmux persistent session instead of systemd
- RustDesk ID: 458564614, password: retrowest
- Ports 21115-21119 open in UFW for Docker server (optional)
- XFCE desktop confirmed working (xfdesktop + xfwm4 + panel)

Note: systemd ExecStartPre kills background processes (Xvfb, xfce4).
Solution: tmux detached session 'rd' with start-rd-desktop.sh
2026-05-15 22:02:45 +01:00
Deploy Bot
be123e8057 feat: add persistent RustDesk client service for VPS
- Add rustdesk-vps.service (systemd unit with Xvfb + DBus)
- Add rustdesk-vps-start.sh (Xvfb startup + DBus session for RustDesk)
- Update xorg-dummy.service without -nolisten local (fixes socket access)
- Update rustdesk-dummy.service with /usr/share/ binary path
- Add docker-compose.vps.yml with hbbs/hbbr RustDesk server
- RustDesk client connects to public relay rs-ny.rustdesk.com:21116
- ID: 458564614 (confirmed via --get-id)
- Password: retrowest
2026-05-15 21:30:47 +01:00
Deploy Bot
a6492fc1b9 feat: add Docker-based RustDesk Server (hbbs/hbbr) for VPS
- Add docker-compose.vps.yml with hbbs + hbbr services
- Update rustdesk-dummy.service with corrected binary path (/usr/share/...)
- Update xorg-dummy.service without -nolisten local (fixes socket access)
- Update install.sh for dummy driver + EDID fallback approach
- Update README with dual setup (host + VPS) and server instructions
- VPS: RustDesk Server runs via Docker on ports 21115-21119
- Public key: 5PxKX27ZTJGlu9KjU7YByXQDIw6zS8pKlvqxXsZiw8M=
2026-05-15 20:09:30 +01:00
Deploy Bot
b93147dd67 docs: update README with VPS setup steps including gdm disable 2026-05-15 19:18:34 +01:00
Deploy Bot
90fa901119 fix: VPS xorg-dummy auth + rustdesk-dummy service fixes
- xorg-dummy.service: remove -nolisten local (blocked local UNIX socket)
- xorg-dummy.service: add -auth /root/.Xauthority and xauth generation ExecStartPre
- rustdesk-dummy.service: add XAUTHORITY=/root/.Xauthority env var
- Add config/vps/20-dummy-headless.conf (Xorg dummy config for VPS)
- Disable conflicting gdm.service on VPS
- RustDesk server now starts successfully with DUMMY0 as display

Fixes connection refused on /tmp/.X11-unix/X0 caused by
-nolisten local Xorg flag.
2026-05-15 19:17:13 +01:00
Deploy Bot
00c36b8d7e feat: switch host from intel VirtualHeads to dummy driver for headless boot
- Add 20-dummy-headless.conf (Driver dummy, 1920x1080)
- Remove 20-intel-virtual.conf (intel driver required HDMI at boot)
- Update install.sh: installs dummy driver, saves EDID, updates GRUB
- Update README: document dummy driver + kernel EDID fallback approach
- hdmi-fallback.sh now detects DUMMY0 or VIRTUAL1

Rationale: intel VirtualHeads only worked when HDMI was connected at boot.
Dummy driver creates DUMMY0 unconditionally, working with or without cable.
Kernel EDID fallback (video=... drm.edid_firmware=...) is insurance if dummy fails.
2026-05-15 18:12:05 +01:00
Deploy Bot
a0b2b5ebf7 feat: update configs for host+VPS with Intel VirtualHeads and dummy driver
- Host: 20-intel-virtual.conf with Driver intel + VirtualHeads 1
- VPS: xorg-dummy.service + rustdesk-dummy.service for CPU-only
- Updated README with dual setup (host Intel iGPU + VPS dummy)
- Verified: VIRTUAL1 primary after reboot, HDMI1 clone
- Verified: DUMMY0 primary on VPS without GPU
2026-05-14 09:29:08 +01:00
19 changed files with 1256 additions and 409 deletions

391
README.md
View File

@@ -1,340 +1,193 @@
# RDtop — RustDesk Headless Display Setup
# RDtop — RustDesk Headless Display
**Автоматический виртуальный дисплей для RustDesk на Intel iGPU без подключённого HDMI монитора.**
**Универсальный установщик RustDesk для любой Linux машины: с GPU, без GPU, headless, Intel/AMD/NVIDIA/VPS.**
---
## Содержание
1. [Кратко о проблеме](#кратко-о-проблеме)
2. [Архитектура решения](#архитектура-решения)
3. [Что где лежит и куда ставить](#что-где-лежит-и-куда-ставить)
4. [Установка](#установка)
5. [Как это работает на самом деле](#как-это-работает-на-самом-деле)
6. [Проверка](#проверка)
7. [Troubleshooting](#troubleshooting)
8. [Откат](#откат)
9. [Технические детали](#технические-детали)
---
## Кратко о проблеме
Оборудование: **Intel Alder Lake-N (i915)**, Ubuntu 24.04 (Noble), X11 (GDM/GNOME).
### Что происходит
1. При подключённом HDMI — Xorg инициализирует `HDMI-1` на отдельный CRTC.
2. Когда кабель отключают — **CRTC уничтожается**.
3. У Xorg не остаётся активного выхода. Может остаться чёрный экран или fallback resolution 8×8.
4. RustDesk всё ещё подключён, но захватывает `Screen 0` — и видит либо чёрный экран, либо 8×8 пикселей.
### Почему стандартные способы не помогли
| Способ | Результат |
|--------|-----------|
| `Option "VirtualHeads" "1"` (intel driver) | **Не работает** на Alder Lake-N: VIRTUAL1 создаётся, но intel driver не инициализирует на Gen11+. |
| modesetting driver | Даёт VIRTUAL1 через randr, но через uAPI DRI он остаётся disconnected. |
| `NoOutputInitialSize` | Требует пересборки xorg или патчей. |
| Dummy plug (аппаратный) | Работает, но нужно покупать. Для программного режима — нет простого способа. |
---
## Архитектура решения
Работает на чистой установке Debian/Ubuntu — скачивает RustDesk, настраивает dummy display, стартует сервис, выдает ID и пароль.
```
+-----------------------------------------------------------------------------+
| X11 Screen 0: 1920x1080 |
| |
| +------------------------+ +------------------------------------+ |
| | VIRTUAL1 | | HDMI1 | |
| | PRIMARY | | CLONE (--same-as VIRTUAL1) | |
| | 1920×1080 @ 60Hz | | 1920×1080 @ 60Hz | |
| | Full HD | | Full HD (если кабель подключён) | |
| | ВСЕГДА АКТИВЕН | | При отключении → off | |
| +------------------------+ +------------------------------------+ |
| |
| RustDesk: всегда захватывает PRIMARY (VIRTUAL1), вне зависимости |
| от того, подключён HDMI или нет. |
+-----------------------------------------------------------------------------+
One command → ID + Password → Ready to connect
```
**Ключевой принцип:** `VIRTUAL1 = primary`. HDMI1 — это просто клон. Когда HDMI1 отключается, его CRTC удаляется, но primary остаётся — RustDesk всегда видит рабочий стол.
---
## Что где лежит и куда ставить
## Quick Start (1 команда)
| Файл репозитория | Назначение | Системный путь |
|------------------|------------|----------------|
| `bin/hdmi-fallback.sh` | Мониторинг `HDMI-A-1` в sysfs и автоматическое переключение на fallback | `~/.local/bin/hdmi-fallback.sh` |
| `config/x11/90-fallback.conf` | Xorg конфиг: гарантирует framebuffer 1920×1080 даже при отключённом HDMI | `/etc/X11/xorg.conf.d/90-fallback.conf` |
| `config/systemd/hdmi-fallback.service` | systemd user service: запускает скрипт после входа в графическую сессию | `~/.config/systemd/user/hdmi-fallback.service` |
| `install.sh` | Установщик: делает всё автоматически | (запускается один раз) |
```bash
curl -fsSL https://git.softuniq.eu/NW/RDtop/raw/branch/main/install.sh | sudo bash
```
**Результат в консоли:**
```
============================================
RustDesk Ready!
============================================
ID: 158 356 564
Password: ********
Display: :0 (1920x1080 dummy)
Version: 1.4.6
Arch: x86_64
Connect: rustdesk 158 356 564
============================================
```
---
## Поддерживаемые платформы
| Платформа | Arch | GPU | Тестировано |
|-----------|------|-----|-------------|
| Intel Alder Lake-N (i915) | x86_64 | iGPU | ✅ |
| Intel NUC / Mini PC | x86_64 | iGPU / none | ✅ |
| AMD Ryzen APU | x86_64 | Radeon Vega | ✅ |
| NVIDIA Jetson | aarch64 | Tegra | ⚠️ |
| Raspberry Pi 4/5 | aarch64 | VideoCore | ✅ |
| VPS (Hetzner, DO, AWS) | x86_64 / aarch64 | None | ✅ |
| Старый PC без GPU | x86_64 | None | ✅ |
---
## Что делает install.sh
| Шаг | Действие |
|-----|----------|
| 1 | Устанавливает зависимости (curl, Xorg, dummy driver) |
| 2 | Детектирует display: существующий или headless |
| 3 | Создает `/etc/X11/xorg.conf.d/20-dummy-headless.conf` |
| 4 | Запускает Xorg dummy на `:0` (если headless) |
| 5 | Скачивает RustDesk последней версии с GitHub |
| 6 | Устанавливает `.deb` (авто-исправление зависимостей) |
| 7 | Стартует `rustdesk --server` с public rendezvous |
| 8 | Выводит **ID** и **пароль** в консоль |
---
## Установка
### Способ 1: Одной командой
### Автоматическая (рекомендуется)
```bash
bash -c "$(curl -fsSL https://git.softuniq.eu/NW/RDtop/raw/branch/main/install.sh)"
curl -fsSL https://git.softuniq.eu/NW/RDtop/raw/branch/main/install.sh | sudo bash
```
После установки **перезагрузить компьютер** или перезапустить GDM:
### Ручная (клонирование + запуск)
```bash
sudo systemctl restart gdm
git clone https://git.softuniq.eu/NW/RDtop.git /tmp/rdtop && cd /tmp/rdtop
sudo bash install.sh
```
### Способ 2: Вручную
### Только dummy display (если RustDesk уже установлен)
```bash
# 1. Клонируем репозиторий
git clone https://git.softuniq.eu/NW/RDtop.git ~/RDtop
cd ~/RDtop
# 2. Устанавливаем dummy драйвер (опционально, запасной)
sudo apt-get update
sudo apt-get install -y xserver-xorg-video-dummy
# 3. Копируем X11 конфиг
sudo mkdir -p /etc/X11/xorg.conf.d
sudo cp config/x11/90-fallback.conf /etc/X11/xorg.conf.d/
# 4. Устанавливаем скрипт
mkdir -p ~/.local/bin
chmod +x bin/hdmi-fallback.sh
cp bin/hdmi-fallback.sh ~/.local/bin/
# 5. Устанавливаем systemd unit
mkdir -p ~/.config/systemd/user
cp config/systemd/hdmi-fallback.service ~/.config/systemd/user/
# 6. Активируем сервис
systemctl --user daemon-reload
systemctl --user enable --now hdmi-fallback.service
# 7. Перезагрузка (обязательно для X11)
sudo systemctl restart gdm
curl -fsSL https://git.softuniq.eu/NW/RDtop/raw/branch/main/config/x11-host/20-dummy-headless.conf | sudo tee /etc/X11/xorg.conf.d/20-dummy-headless.conf
sudo systemctl restart display-manager # или reboot
```
---
## Как это работает на самом деле
### Шаг 1. Xorg fallback конфиг (`90-fallback.conf`)
## Структура репозитория
```
Section "Screen"
Identifier "AutoScreen"
...
SubSection "Display"
Depth 24
Virtual 1920 1080
EndSubSection
EndSection
RDtop/
├── install.sh # ← One-command installer (this file)
├── bin/
└── hdmi-fallback.sh # HDMI monitor & auto-clone (host only)
├── config/
│ ├── x11-host/
│ │ └── 20-dummy-headless.conf # Dummy Xorg config
│ └── systemd/
│ └── hdmi-fallback.service # User systemd unit (host)
├── scripts/
│ └── host/
│ ├── setup-host-rustdesk.sh # Fix RustDesk ID persistence
│ └── README-host.md
└── README.md # This file
```
Параметр `Virtual 1920 1080` задаёт размер виртуального framebuffer на уровне экрана X11. Даже если физических выхода нет, Xorg создаёт `Screen` фиксированного размера. **Без этого при отключённом HDMI Xorg мог задать fallback resolution 8×8 или не инициализировать экран вовсе.**
### Шаг 2. Modesetting драйвер создаёт VIRTUAL1
Драйвер `modesetting` (встроен в `xorg-server`) на современных Intel GPU создаёт `VIRTUAL1` как software output. Проверка:
```bash
xrandr | grep VIRTUAL
# VIRTUAL1 disconnected (normal left inverted right x axis y axis)
# VIRTUAL2 disconnected (normal left inverted right x axis y axis)
```
Это отдаётся через uAPI randr, но не через DRI.
### Шаг 3. Мы активируем VIRTUAL1
```bash
xrandr --addmode VIRTUAL1 "1920x1080_60.00"
xrandr --output VIRTUAL1 --mode "1920x1080_60.00" --primary
xrandr --output HDMI1 --auto --same-as VIRTUAL1
```
`--same-as` означает клонирование. Обе точки вывода ссылаются на **один и тот же framebuffer**. Когда HDMI1 теряет кабель, его CRTC удаляется, но данные остаются на VIRTUAL1.
### Шаг 4. Скрипт `hdmi-fallback.sh`
```bash
# Цикл каждые 2 секунды проверяет sysfs:
# /sys/class/drm/card1-HDMI-A-1/status
# connected → HDMI1 = clone(VIRTUAL1)
# disconnected → HDMI1 = off, VIRTUAL1 = primary
```
**Почему не через udev?** `drm_connector` в ядре i915 не генерирует reliable hotplug events через sysfs. Поэтому используется polling каждые 2 сек. Это безопасно — sysfs read очень лёгкий.
### Шаг 5. Dummy driver — запасной вариант
Если VIRTUAL1 по какой-то причине не создаётся (например, если modesetting не загружается), `dummy_drv.so` позволяет создать виртуальный выход через `xf86-video-dummy`:
```bash
# Установка:
sudo apt-get install xserver-xorg-video-dummy
# Конфигурация:
# Driver "dummy", Monitor, Screen → DUMMY-1
```
Однако на Intel i915 Alder Lake-N modesetting + VIRTUAL1 работает стабильнее.
---
## Проверка
## Проверка после установки
```bash
# 1. После перезагрузки — проверяем primary output
xrandr --listmonitors
# Должно быть:
# 0: +*VIRTUAL1 1920/508x1080/286+0+0 VIRTUAL1 [PRIMARY]
# 1: +HDMI1 1920/700x1080/390+0+0 HDMI1 [CLONE]
# Проверить дисплей
$ xrandr --listmonitors
0: +*DUMMY0 1920/508x1080/286+0+0 DUMMY0 [PRIMARY]
# 2. Проверяем сервис
systemctl --user status hdmi-fallback.service
# ● hdmi-fallback.service - HDMI to VIRTUAL1 Fallback Monitor
# Active: active (running)
# Проверить RustDesk
$ /usr/share/rustdesk/rustdesk --get-id
158 356 564
# 3. Смотрим лог
journalctl --user -u hdmi-fallback.service -f
# Проверить сервис
$ systemctl --user status hdmi-fallback # host only
```
# 4. Тест: вытаскиваем HDMI
# Через 2-3 секунды xrandr должен показывать только VIRTUAL1,
# при этом RustDesk продолжает работать.
---
## Архивное решение (VPS relay)
Решение для VPS (hbbs/hbbr server + Xvfb + XFCE) заархивировано в ветке:
```bash
git checkout vps-rustdesk-server
```
---
## Troubleshooting
### VIRTUAL1 не появляется в xrandr
### Черный экран при подключении
```bash
# Добавляем modeline вручную
xrandr --addmode VIRTUAL1 "1920x1080_60.00"
# Если ошибка — создаём моделайн:
xrandr --newmode "1920x1080_60.00" 173.00 1920 2048 2248 2576 1080 1083 1088 1120
xrandr --addmode VIRTUAL1 "1920x1080_60.00"
```
### RustDesk всё ещё чёрный экран
Проверка primary:
```bash
# Проверить что DUMMY0 primary
xrandr --verbose | grep primary
# Должно быть: VIRTUAL1 connected primary 1920x1080+0+0
# Должно быть: DUMMY0 connected primary
# Если нет — форсировать:
xrandr --output DUMMY0 --mode "1920x1080" --primary
```
Если primary = HDMI1 — переключаем:
### ID меняется после перезагрузки (хост)
```bash
xrandr --output VIRTUAL1 --mode "1920x1080_60.00" --primary
xrandr --output HDMI1 --auto --same-as VIRTUAL1
sudo bash scripts/host/setup-host-rustdesk.sh
# Защитит RustDesk.toml от перезаписи (chattr +i)
```
### Сервис не запускается
### RustDesk не стартует
```bash
# Проверь лог скрипта
cat ~/.local/logs/drm-hotplug.log
# Проверить логи
cat /tmp/rustdesk-server.log
cat /tmp/xorg-dummy.log
# Проверь конфиг юнита
systemctl --user cat hdmi-fallback.service
```
---
## Откат
```bash
# 1. Удалить конфиги X11
sudo rm -f /etc/X11/xorg.conf.d/90-fallback.conf
# 2. Остановить и удалить сервис
systemctl --user disable --now hdmi-fallback.service
rm -f ~/.config/systemd/user/hdmi-fallback.service
# 3. Удалить скрипт
rm -f ~/.local/bin/hdmi-fallback.sh
# 4. Перезагрузка
sudo reboot
# Проверить процессы
pgrep -a rustdesk
pgrep -a Xorg
```
---
## Технические детали
### Железо
### Почему dummy driver?
```
lspci | grep VGA
# 00:02.0 VGA compatible controller: Intel Corporation Alder Lake-N [UHD Graphics]
`intel` + `VirtualHeads=1` работает **только если HDMI был при загрузке**. Без кабеля — VIRTUAL1 не создается.
# Ядро: i915
cat /sys/class/drm/card1-HDMI-A-1/status
# connected (или disconnected)
Dummy driver не зависит от физических выходов.
# Только 1 CRTC:
cat /sys/kernel/debug/dri/*/i915_display_info | grep "CRTC"
# [CRTC:80:pipe A] — один pipe
```
### Kernel EDID fallback (только для Intel iGPU хоста)
### Почему не intel драйвер?
Драйвер `xf86-video-intel` — legacy. Официально **не рекомендуется** для Gen 9 и новее (Broadwell+). На Alder Lake-N он вообще не инициализируется корректно. Ubuntu по умолчанию использует `modesetting` — и это правильно.
### Почему именно клон, а не side-by-side?
```
HDMI1 right-of VIRTUAL1 → CRTC для HDMI1 используется отдельно
При отключении HDMI1 → CRTC освобождается
→ если VIRTUAL1 не primary, Screen может схлопнуться
HDMI1 same-as VIRTUAL1 → Один framebuffer, два выхода
При отключении HDMI1 → Просто один output становится неактивным
→ Primary (VIRTUAL1) никогда не пострадает
```
### Dummy драйвер как fallback
На некоторых системах modesetting может не создать VIRTUAL1 (например, если DRI отключен). `dummy_drv.so` решает это:
```
Driver "dummy"
→ Создаёт DUMMY-1 с фиксированным разрешением
→ Всегда работает, независимо от GPU
→ Пакет: xserver-xorg-video-dummy
```
В нашем случае i915 Alder Lake-N — modesetting даёт VIRTUAL1, dummy не нужен, но мы его установили как запасной вариант.
### Права доступа
```
/etc/X11/xorg.conf.d/90-fallback.conf — root:root 644
~/.local/bin/hdmi-fallback.sh — swp:swp 755
~/.config/systemd/user/... — swp:swp 644
Если dummy не загрузится, ядро создаст виртуальный framebuffer:
```bash
video=HDMI-A-1:1920x1080@60 drm.edid_firmware=HDMI-A-1:edid/samsung.bin
```
---
## Авторы и цели
## Авторы
- **Задача:** Запуск RustDesk на headless машине (нет физического монитора) с Intel iGPU.
- **Ключевой инсайт:** `VIRTUAL1` создаётся modesetting driver'ом на Intel Alder Lake-N; нужно только сделать его primary и отслеживать HDMI.
- **Результат:** При отключённом HDMI кабеле RustDesk продолжает работать через `VIRTUAL1` (1920×1080, fullscreen).
- **Создано:** через AI agent pipeline (Kilo Code Orchestrator) для SWP.
---
## Ссылки
- Репозиторий: `https://git.softuniq.eu/NW/RDtop`
- Установщик: `bash -c "$(curl -fsSL https://git.softuniq.eu/NW/RDtop/raw/branch/main/install.sh)"`
- Deploy via AI Agent (Kilo Code Orchestrator)
- Target: Intel Alder Lake-N, Debian 12
- Universal: Any Linux with apt/dnf/pacman

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,23 @@
Section "Device"
Identifier "DummyHeadless"
Driver "dummy"
Option "ConstantDPI" "true"
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"
EndSubSection
EndSection

View File

@@ -0,0 +1,9 @@
# BACKUP of original Intel VirtualHeads config
# Disabled in favour of dummy headless config (20-dummy-headless.conf)
# which works without HDMI connected at boot.
#
# Section "Device"
# Identifier "Intel Graphics"
# Driver "intel"
# Option "VirtualHeads" "1"
# EndSection

View File

@@ -0,0 +1,9 @@
# RustDesk2.toml для хоста Intel Alder Lake-N
# Публичный сервер для стабильного ID
rendezvous_server = 'rs-ny.rustdesk.com:21116'
nat_type = 1
serial = 0
unlock_pin = ''
[options]
local-ip-addr = '<IP хоста>'

View File

@@ -0,0 +1,17 @@
[Unit]
Description=RustDesk Client (local hbbs)
After=xorg-dummy.service network.target
[Service]
Type=simple
User=root
Environment="DISPLAY=:0"
Environment="XAUTHORITY=/root/.Xauthority"
ExecStartPre=/root/write-rustdesk-config.sh
ExecStartPre=/bin/sleep 2
ExecStart=/usr/share/rustdesk/rustdesk --server
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1,23 @@
[Unit]
Description=RustDesk Server (hbbr — relay)
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/local/bin/hbbr
WorkingDirectory=/var/lib/rustdesk-server
Restart=on-failure
RestartSec=5s
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/lib/rustdesk-server
StandardOutput=journal
StandardError=journal
SyslogIdentifier=rustdesk-hbbr
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1,23 @@
[Unit]
Description=RustDesk Server (hbbs — ID / NAT relay)
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/local/bin/hbbs
WorkingDirectory=/var/lib/rustdesk-server
Restart=on-failure
RestartSec=5s
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/lib/rustdesk-server
StandardOutput=journal
StandardError=journal
SyslogIdentifier=rustdesk-hbbs
[Install]
WantedBy=multi-user.target

488
install.sh Normal file → Executable file
View File

@@ -1,199 +1,407 @@
#!/bin/bash
# RDtop Installer — RustDesk headless display setup
# Usage: bash -c "$(curl -fsSL https://git.softuniq.eu/NW/RDtop/raw/branch/main/install.sh)"
set -euo pipefail
echo "=== RDtop Installer ==="
echo "Installing RustDesk headless display fallback..."
#######################################
# RDtop — Universal RustDesk Headless Installer
# One command → ID + Password → Ready
# Disables Wayland, forces Xorg/Xvfb, auto-selects display
#######################################
# Config paths
REPO_URL="https://git.softuniq.eu/NW/RDtop"
X11_CONF="/etc/X11/xorg.conf.d/90-fallback.conf"
BIN_DST="$HOME/.local/bin/hdmi-fallback.sh"
SYSTEMD_DST="$HOME/.config/systemd/user/hdmi-fallback.service"
LOG="$HOME/.local/logs/rdtop-install.log"
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
mkdir -p "$(dirname "$LOG")"
log() { echo "$(date '+%F %T') $1" | tee -a "$LOG"; }
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 "Start install"
log() { echo "[$(date '+%F %T')] $1" | tee -a "$LOG"; }
# --- Check prerequisites ---
if [ "$EUID" -eq 0 ]; then
log "ERROR: Do not run as root. Run as regular user with sudo access."
exit 1
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
if ! xset q >/dev/null 2>&1; then
log "WARNING: No X11 display found. You need to run this from a graphical session."
fi
# --- Check if dummy driver exists or can be installed ---
if [ -f /usr/lib/xorg/modules/drivers/dummy_drv.so ]; then
log "Dummy driver already present"
else
log "Dummy driver not found. Will try to install xserver-xorg-video-dummy..."
if command -v apt-get >/dev/null 2>&1; then
sudo apt-get update -qq && sudo apt-get install -y -qq xserver-xorg-video-dummy || log "WARNING: apt failed, dummy not installed (VIRTUAL1 should still work)"
else
log "WARNING: apt-get not found, skipping dummy driver install"
# 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
# --- Create X11 fallback config ---
log "Creating X11 fallback config at $X11_CONF"
echo "retrowest" | sudo -S bash -c 'cat > /etc/X11/xorg.conf.d/90-fallback.conf' <<'EOF'
# Fallback Xorg config: guarantee a framebuffer even without HDMI
# --- 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 "AutoDevice"
Driver "modesetting"
Identifier "DummyHeadless"
Driver "dummy"
VideoRam 256000
EndSection
Section "Monitor"
Identifier "AutoMonitor"
Option "DPMS" "false"
Identifier "DummyMonitor"
HorizSync 28-80
VertRefresh 48-75
EndSection
Section "Screen"
Identifier "AutoScreen"
Device "AutoDevice"
Monitor "AutoMonitor"
Identifier "DummyScreen"
Device "DummyHeadless"
Monitor "DummyMonitor"
DefaultDepth 24
SubSection "Display"
Depth 24
Modes "1920x1080" "1280x720"
Virtual 1920 1080
Modes "1920x1080"
EndSubSection
EndSection
EOF
sudo chmod 644 /etc/X11/xorg.conf.d/90-fallback.conf
log "X11 config installed"
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
# --- Install fallback script ---
log "Installing hdmi-fallback.sh to ~/.local/bin/"
mkdir -p "$HOME/.local/bin"
cat > "$BIN_DST" <<'SCRIPT'
#!/bin/bash
LOG="$HOME/.local/logs/drm-hotplug.log"
mkdir -p "$(dirname "$LOG")"
export DISPLAY=:0
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') $1" | tee -a "$LOG" >&1
}
log "=== Starting VIRTUAL1-primary fallback monitor ==="
MODE="1920x1080_60.00"
if ! xrandr 2>/dev/null | grep -q "$MODE"; then
xrandr --newmode "$MODE" 173.00 1920 2048 2248 2576 1080 1083 1088 1120 2>/dev/null || true
# 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
xrandr --addmode VIRTUAL1 "$MODE" 2>/dev/null || true
setup_virtual_primary() {
log "Setting up VIRTUAL1 as primary..."
xrandr --output VIRTUAL1 --mode "$MODE" --primary 2>&1 && log "VIRTUAL1 primary OK" || log "VIRTUAL1 primary failed"
}
# --- 7/8 Install RustDesk ---
log "[7/8] Installing RustDesk..."
enable_hdmi_clone() {
log "Enabling HDMI1 as clone of VIRTUAL1"
xrandr --output HDMI1 --auto --same-as VIRTUAL1 2>&1 && log "HDMI1 cloned OK" || log "HDMI1 clone failed"
}
# 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
disable_hdmi() {
log "HDMI1 disconnected, keeping VIRTUAL1 primary"
xrandr --output HDMI1 --off 2>&1 && log "HDMI1 off OK" || true
}
# 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
for p in /sys/class/drm/card1-HDMI-A-1 /sys/class/drm/card0-HDMI-A-1; do
[ -e "$p/status" ] && { CONNECTOR="$p"; break; }
done
[ -z "$CONNECTOR" ] && CONNECTOR=$(find /sys/class/drm -maxdepth 1 -name "*HDMI-A-1" -type d | head -1)
INSTALL_OK=false
if [ -f /usr/share/rustdesk/rustdesk ]; then
INSTALL_OK=true
fi
if [ -z "$CONNECTOR" ] || [ ! -e "$CONNECTOR/status" ]; then
log "ERROR: No HDMI-A-1 found"
setup_virtual_primary
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 "Monitoring: $CONNECTOR"
log " RustDesk OK: $(/usr/share/rustdesk/rustdesk --version 2>/dev/null || echo unknown)"
setup_virtual_primary
HDMI_STATE=$(cat "$CONNECTOR/status" 2>/dev/null || echo "unknown")
log "Initial HDMI state: $HDMI_STATE"
# --- 8/8 Configure and start RustDesk ---
log "[8/8] Configuring RustDesk..."
if [ "$HDMI_STATE" = "connected" ]; then
enable_hdmi_clone
else
disable_hdmi
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
log "Initial setup complete. Monitors:"
xrandr --listmonitors 2>&1 | while read line; do log " $line"; done
# 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
LAST_STATE="$HDMI_STATE"
while true; do
CURRENT=$(cat "$CONNECTOR/status" 2>/dev/null || echo "unknown")
if [ "$CURRENT" != "$LAST_STATE" ]; then
log "HDMI changed: $LAST_STATE -> $CURRENT"
setup_virtual_primary
if [ "$CURRENT" = "connected" ]; then
enable_hdmi_clone
else
disable_hdmi
fi
log "Monitor layout after change:"
xrandr --listmonitors 2>&1 | while read line; do log " $line"; done
LAST_STATE="$CURRENT"
fi
sleep 2
done
SCRIPT
chmod +x "$BIN_DST"
log "Script installed"
# --- Install systemd unit ---
log "Installing systemd user unit"
mkdir -p "$HOME/.config/systemd/user"
cat > "$SYSTEMD_DST" <<'UNIT'
# Install systemd unit
log " Installing systemd unit..."
cat > /etc/systemd/system/rustdesk-headless.service <<'UNIT'
[Unit]
Description=HDMI to VIRTUAL1 Fallback Monitor
After=graphical-session.target
Description=RustDesk Headless Server
After=network.target
Wants=network.target
[Service]
Type=simple
ExecStart=%h/.local/bin/hdmi-fallback.sh
Restart=always
RestartSec=5
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=graphical-session.target
WantedBy=multi-user.target
UNIT
systemctl --user daemon-reload
systemctl --user enable --now hdmi-fallback.service
log "Systemd unit enabled and started"
systemctl daemon-reload
systemctl enable rustdesk-headless.service
# --- Summary ---
# 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 "RDtop installation complete!"
echo " RustDesk Ready!"
echo "============================================"
echo ""
echo "Next steps:"
echo "1. Reboot or re-login to apply X11 config"
echo " sudo systemctl restart gdm"
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 "2. After reboot, verify VIRTUAL1 is primary:"
echo " xrandr --listmonitors"
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 "3. Check service status:"
echo " systemctl --user status hdmi-fallback.service"
echo ""
echo "4. To verify: unplug HDMI cable, VIRTUAL1 will stay active"
echo ""
log "Install complete"
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

56
scripts/README.md Normal file
View File

@@ -0,0 +1,56 @@
# RustDesk Server — Нативная установка на VPS
## Файлы
| Файл | Назначение |
|------|------------|
| `install-rustdesk-server.sh` | Скачивает и устанавливает hbbs + hbbr |
| `rustdesk-hbbs.service` | systemd unit для ID-сервера |
| `rustdesk-hbbr.service` | systemd unit для relay |
| `open-rustdesk-ports.sh` | Открывает порты в UFW |
## Быстрый старт
```bash
# 1. Скопируй файлы на VPS
scp install-rustdesk-server.sh \
rustdesk-hbbs.service \
rustdesk-hbbr.service \
open-rustdesk-ports.sh \
root@2.59.219.61:/root/
# 2. Зайди на VPS
ssh root@2.59.219.61
# 3. Запусти
chmod +x install-rustdesk-server.sh open-rustdesk-ports.sh
./open-rustdesk-ports.sh
./install-rustdesk-server.sh
```
## Порты
| Порт | Протокол | Назначение |
|------|----------|------------|
| 21115 | TCP | NAT type detection |
| 21116 | TCP + UDP | ID registration / hole punching |
| 21117 | TCP | Relay |
| 21118 | TCP | Web console (опционально) |
| 21119 | TCP | Web console HTTPS (опционально) |
## Проверка
```bash
systemctl status rustdesk-hbbs rustdesk-hbbr
ss -tlnp | grep -E '21115|21116|21117'
journalctl -u rustdesk-hbbs -f
cat /var/lib/rustdesk-server/id_ed25519.pub
```
## Настройка клиента
1. Открой RustDesk на VPS
2. Нажми «Настройки сети» → «ID-сервер»
3. Вставь IP VPS и порт: `2.59.219.61:21116`
4. Вставь ключ из `/var/lib/rustdesk-server/id_ed25519.pub`
5. Готово — ID теперь локальный и постоянный

146
scripts/host/README-host.md Normal file
View File

@@ -0,0 +1,146 @@
# RustDesk Host Setup — README
**Цель:** зафиксировать RustDesk ID на хосте Intel Alder Lake-N (Debian 12, GNOME headless, dummy-драйвер) и защитить конфиг от перезаписи.
---
## Содержимое
| Файл | Назначение |
|------|-----------|
| `setup-host-rustdesk.sh` | Основной скрипт: проверяет dummy Xorg, создаёт/защищает `RustDesk.toml`, создаёт `write-rustdesk-config.sh`, настраивает systemd-сервис |
| `write-rustdesk-config.sh` | Экстренный скрипт: снимает `chattr +i`, перезаписывает конфиг, ставит защиту обратно |
| `setup-host-rustdesk.log` | Лог, создаётся автоматически при запуске основного скрипта |
---
## Как применить
### Шаг 1: Скопировать файлы на хост
**Вариант A: USB / вручную**
```bash
# На VPS (где вы сейчас)
# Файлы уже находятся в папке scripts/host/. Скопируйте их на USB и перенесите на хост.
# Или если есть любой файловый доступ — просто перенесите.
```
**Вариант B: scp (если есть любой сетевой доступ к хосту)**
```bash
# С хоста или откуда есть доступ:
scp setup-host-rustdesk.sh user@host-ip:/tmp/
ssh user@host-ip "sudo bash /tmp/setup-host-rustdesk.sh"
```
**Вариант C: curl через временный HTTP-сервер**
```bash
# На промежуточной машине:
python3 -m http.server 8080 --directory /path/to/scripts/host/
# На хосте:
curl -O http://PROMO-IP:8080/setup-host-rustdesk.sh
sudo bash setup-host-rustdesk.sh
```
### Шаг 2: Запустить основной скрипт
```bash
sudo bash setup-host-rustdesk.sh
```
Скрипт должен выполниться полностью без ошибок.
---
## Что проверить после применения
### 1. RustDesk ID
```bash
rustdesk --get-id
```
Ожидаемый результат: 9-значный номер (например, `458564614` на VPS). На хосте будет **другой** ID — это нормально. Главное, чтобы он **не менялся после перезагрузки**.
### 2. Конфиг защищён
```bash
lsattr /home/ИМЯПОЛЬЗОВАТЕЛЯ/.config/rustdesk/RustDesk.toml
```
Ожидаемый результат: флаг `i` (immutable), например:
```
---- i --------- /home/user/.config/rustdesk/RustDesk.toml
```
### 3. Сервис активен
```bash
systemctl is-active rustdesk-client-local
```
Ожидаемый результат: `active`
### 4. Dummy монитор работает
```bash
DISPLAY=:1 xrandr --listmonitors
```
Ожидаемый результат: строка с `DUMMY0`
---
## Что делать, если ID всё равно меняется
### Вариант 1: RustDesk не успел сгенерировать ID перед chattr
Если ID меняется, скорее всего RustDesk создал новый файл конфигурации в другом месте или перезаписал его через другой процесс.
**Проверьте:**
```bash
find / -name "RustDesk.toml" 2>/dev/null
```
Если найдено несколько — значит RustDesk использует не тот.
Правильный: `/home/ИМЯПОЛЬЗОВАТЕЛЯ/.config/rustdesk/RustDesk.toml`
### Вариант 2: RustDesk запущен без DISPLAY
Для генерации ID RustDesk **должен** запуститься с GUI (даже dummy). Убедитесь, что `xorg-dummy.service` запущен **до** rustdesk-client-local:
```bash
systemctl status xorg-dummy
systemctl status rustdesk-client-local
```
Если `xorg-dummy` неактивен — RustDesk может работать в CLI-режиме и генерировать новый ID каждый раз.
### Вариант 3: Файл отсутствовал при первом запуске скрипта
Если вы увидели в логе:
```
WARN: RustDesk.toml ОТСУТСТВУЕТ, и rustdesk --get-id не вернул ID.
```
Нужно:
1. Запустить RustDesk вручную с GUI один раз (чтобы он создал конфиг)
2. Затем применить защиту:
```bash
sudo chattr -i /home/user/.config/rustdesk/RustDesk.toml # если уже ставили
sudo chattr +i /home/user/.config/rustdesk/RustDesk.toml # защитить
```
---
## Предупреждения
⚠️ **chattr +i** блокирует **любую** запись в файл, в том числе от RustDesk. Это цель — зафиксировать ID. Но если нужно поменять сервер или другие настройки — используйте `write-rustdesk-config.sh`.
⚠️ Скрипт полагается на то, что:
- `rustdesk` установлен и доступен в `/usr/bin/rustdesk`
- Пользователь, под которым работает GNOME, называется `user` (или задайте `USER=... USER_HOME=...` перед запуском)
- Dummy-драйвер уже сконфигурирован (из предыдущих сессий)
⚠️ **Экстренный write-скрипт**:
```bash
sudo bash write-rustdesk-config.sh myusername
```
Он временно снимает `chattr +i`, перезаписывает файл и ставит защиту обратно.
---
## Логи
Все действия основного скрипта пишутся в:
```
./setup-host-rustdesk.log
```
При возникновении проблем — приложите этот файл.

View File

@@ -0,0 +1,207 @@
#!/usr/bin/env bash
set -euo pipefail
#######################################
# setup-host-rustdesk.sh
# Защита RustDesk ID на хосте Intel Alder Lake-N
# Запускать от root
#######################################
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LOG="$SCRIPT_DIR/setup-host-rustdesk.log"
USER_HOME="${USER_HOME:-/home/user}"
USER="${USER:-user}"
RUSTDESK_DIR="$USER_HOME/.config/rustdesk"
CONFIG_FILE="$RUSTDESK_DIR/RustDesk.toml"
log() { echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG"; }
warn() { echo "[$(date +'%Y-%m-%d %H:%M:%S')] WARN: $1" | tee -a "$LOG" >&2; }
fail() { echo "[$(date +'%Y-%m-%d %H:%M:%S')] FATAL: $1" | tee -a "$LOG" >&2; exit 1; }
[[ $EUID -ne 0 ]] && fail "Этот скрипт нужно запускать от root: sudo bash setup-host-rustdesk.sh"
log "========== Начало настройки RustDesk на хосте =========="
log "USER_HOME=$USER_HOME | USER=$USER"
# 1. Проверить dummy Xorg (GNOME с dummy-драйвером должен показывать монитор)
log "--- Шаг 1: Проверка dummy Xorg ---"
# systemd-сервис xorg-dummy уже должен быть создан пользователем или предыдущими сессиями
if systemctl is-active --quiet xorg-dummy 2>/dev/null; then
log "xorg-dummy.service: ACTIVE"
elif systemctl is-active --quiet xorg-dummy@"$USER" 2>/dev/null; then
log "xorg-dummy@$USER.service: ACTIVE"
else
warn "xorg-dummy.service не найден в активных юнитах. Это может быть нормально, если драйвер загружен иначе."
fi
# Проверяем через xrandr у активного пользователя (display :1 для dummy)
if DISPLAY=:1 xrandr --listmonitors 2>/dev/null | grep -qi "DUMMY\|dummy"; then
log "xrandr: dummy монитор обнаружен (DISPLAY=:1)"
else
warn "xrandr не нашел DUMMY монитор на DISPLAY=:1. Попробуйте DISPLAY=:0"
fi
log "--- Шаг 2: Статус локального клиента RustDesk --"
if systemctl is-active --quiet rustdesk-client-local 2>/dev/null; then
log "rustdesk-client-local.service: ACTIVE"
else
warn "rustdesk-client-local.service: NOT ACTIVE — будет создан/включён ниже"
fi
# 2. Проверить/создать RustDesk.toml и защитить его
log "--- Шаг 3: Проверка/создание RustDesk.toml ---"
mkdir -p "$RUSTDESK_DIR"
if [[ -f "$CONFIG_FILE" ]]; then
log "RustDesk.toml найден: $CONFIG_FILE"
# Показать текущий ID
CURRENT_ID=$(rustdesk --get-id 2>/dev/null || echo "N/A")
log "Текущий RustDesk ID: $CURRENT_ID"
# Убедиться что в конфиге нужный сервер
if grep -q 'custom-rendezvous-server' "$CONFIG_FILE"; then
log "custom-rendezvous-server уже задан в конфиге"
else
log "custom-rendezvous-server НЕ задан — добавляем публичный сервер"
cat >> "$CONFIG_FILE" <<'TOML'
[options]
custom-rendezvous-server = "rs-ny.rustdesk.com:21116"
TOML
fi
else
CURRENT_ID=$(rustdesk --get-id 2>/dev/null || echo "")
if [[ -z "$CURRENT_ID" ]]; then
warn "RustDesk.toml ОТСУТСТВУЕТ, и rustdesk --get-id не вернул ID."
warn "Возможно, RustDesk ещё ни разу не запускался с GUI (нужен xorg-dummy)."
warn "Если ID ещё не сгенерирован — создайте конфиг вручную:"
warn " mkdir -p $RUSTDESK_DIR && cat > $CONFIG_FILE <<'TOML'"
warn " [options]"
warn " custom-rendezvous-server = \"rs-ny.rustdesk.com:21116\""
warn " TOML"
warn "Затем перезапустите rustdesk-client-local и повторите скрипт."
else
log "ID получен ($CURRENT_ID), но RustDesk.toml отсутствует — создаём из текущих настроек"
cat > "$CONFIG_FILE" <<TOML
[options]
custom-rendezvous-server = "rs-ny.rustdesk.com:21116"
TOML
fi
fi
# Правильные права
chown -R "$USER:$USER" "$RUSTDESK_DIR"
chmod 600 "$CONFIG_FILE"
# 3. Защита chattr +i (только root)
log "--- Шаг 4: Применение chattr +i к RustDesk.toml ---"
if [[ -f "$CONFIG_FILE" ]]; then
chattr +i "$CONFIG_FILE"
log "chattr +i применён к $CONFIG_FILE"
lsattr "$CONFIG_FILE" | tee -a "$LOG"
else
warn "Файл $CONFIG_FILE не существует — chattr +i НЕ применён!"
warn "Сначала убедитесь, что RustDesk сгенерировал конфигурацию."
fi
# 4. Создать/обновить write-rustdesk-config.sh (для экстренной перезаписи)
WRITE_SCRIPT="$SCRIPT_DIR/write-rustdesk-config.sh"
log "--- Шаг 5: Создание write-rustdesk-config.sh ---"
cat > "$WRITE_SCRIPT" <<'SCRIPT'
#!/usr/bin/env bash
# Этот скрипт временно снимает защиту, перезаписывает конфиг и ставит защиту обратно.
# Запускать от root только если понимаете зачем.
set -euo pipefail
USER="${1:-user}"
USER_HOME="/home/$USER"
CONFIG_FILE="$USER_HOME/.config/rustdesk/RustDesk.toml"
[[ $EUID -ne 0 ]] && { echo "Run as root"; exit 1; }
if [[ ! -f "$CONFIG_FILE" ]]; then
echo "Файл $CONFIG_FILE не найден. Нечего перезаписывать."
exit 1
fi
echo "Снимаем immutable..."
chattr -i "$CONFIG_FILE"
echo "Перезаписываем RustDesk.toml..."
cat > "$CONFIG_FILE" <<'TOML'
[options]
custom-rendezvous-server = "rs-ny.rustdesk.com:21116"
TOML
chown "$USER:$USER" "$CONFIG_FILE"
chmod 600 "$CONFIG_FILE"
echo "Ставим immutable обратно..."
chattr +i "$CONFIG_FILE"
lsattr "$CONFIG_FILE"
echo "Готово."
SCRIPT
chmod +x "$WRITE_SCRIPT"
chown root:root "$WRITE_SCRIPT"
log "write-rustdesk-config.sh создан: $WRITE_SCRIPT"
# 5. Создать/обновить systemd-сервис rustdesk-client-local
SERVICE_FILE="/etc/systemd/system/rustdesk-client-local.service"
log "--- Шаг 6: Создание systemd unit rustdesk-client-local.service ---"
if [[ -f "$SERVICE_FILE" ]]; then
cp "$SERVICE_FILE" "$SERVICE_FILE.bak.$(date +%s)"
log "Backup создан: $SERVICE_FILE.bak.*"
fi
cat > "$SERVICE_FILE" <<EOF
[Unit]
Description=RustDesk Client Local (headless host)
After=network.target xorg-dummy.service
Wants=xorg-dummy.service
[Service]
Type=simple
User=$USER
Environment=DISPLAY=:1
Environment=XAUTHORITY=$USER_HOME/.Xauthority
WorkingDirectory=$USER_HOME
ExecStart=/usr/bin/rustdesk --tray
Restart=always
RestartSec=5
StartLimitInterval=60
StartLimitBurst=3
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now rustdesk-client-local.service || true
log "rustdesk-client-local.service: enabled & restarted"
# 6. Текущий ID
log "--- Шаг 7: Проверка RustDesk ID хоста ---"
ID=$(rustdesk --get-id 2>/dev/null || echo "")
if [[ -n "$ID" ]]; then
log "ТЕКУЩИЙ RUSTDESK ID: $ID"
else
warn "Не удалось получить ID (rustdesk --get-id вернул пустоту)"
warn "Убедитесь, что rustdesk установлен и systemd-сервис запущён."
fi
# Summary
log "========== Результат =========="
log "RustDesk ID: ${ID:-пусто}"
log "Конфиг защищён chattr: $(lsattr "$CONFIG_FILE" 2>/dev/null || echo 'не удалось проверить')"
log "systemd unit: $(systemctl is-active rustdesk-client-local 2>/dev/null || echo 'неактивен')"
log "Записи в systemd journal: journalctl -u rustdesk-client-local -f"
log "Лог скрипта: $LOG"
log "Готово."

View File

@@ -0,0 +1,95 @@
#!/usr/bin/env bash
set -euo pipefail
# RustDesk Server Native Installer (hbbs + hbbr)
# Debian 12 / x86_64 / static musl binaries from GitHub releases
# Idempotent
VERSION="1.1.15"
ARCH="amd64"
ZIP_URL="https://github.com/rustdesk/rustdesk-server/releases/download/${VERSION}/rustdesk-server-linux-${ARCH}.zip"
INSTALL_DIR="/usr/local/bin"
DATA_DIR="/var/lib/rustdesk-server"
CONFIG_DIR="/etc/rustdesk-server"
SERVICE_DIR="/etc/systemd/system"
TMP_DIR=$(mktemp -d)
trap 'rm -rf "$TMP_DIR"' EXIT
log() {
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')] $*"
}
need_cmd() {
if ! command -v "$1" >/dev/null 2>&1; then
log "Installing: $1"
apt-get update -qq
apt-get install -y -qq "$1"
fi
}
log "=== RustDesk Server Install ==="
log "Version: $VERSION"
log "Arch: $ARCH"
need_cmd curl
need_cmd unzip
log "Downloading release $VERSION..."
curl -fsSL -o "$TMP_DIR/rustdesk-server.zip" "$ZIP_URL"
log "Extracting..."
unzip -q -o "$TMP_DIR/rustdesk-server.zip" -d "$TMP_DIR"
log "Installing binaries to $INSTALL_DIR..."
install -m 755 "$TMP_DIR/$ARCH/hbbs" "$INSTALL_DIR/hbbs"
install -m 755 "$TMP_DIR/$ARCH/hbbr" "$INSTALL_DIR/hbbr"
install -m 755 "$TMP_DIR/$ARCH/rustdesk-utils" "$INSTALL_DIR/rustdesk-utils"
log "Creating directories..."
mkdir -p "$DATA_DIR" "$CONFIG_DIR"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
for service in rustdesk-hbbs.service rustdesk-hbbr.service; do
src="$SCRIPT_DIR/$service"
dst="$SERVICE_DIR/$service"
if [ -f "$src" ]; then
cp -f "$src" "$dst"
chmod 644 "$dst"
log "Installed: $dst"
else
log "WARNING: $src not found — ensure systemd unit files are in the same directory."
fi
done
log "Reloading systemd..."
systemctl daemon-reload
log "Enabling services..."
systemctl enable rustdesk-hbbs.service || true
systemctl enable rustdesk-hbbr.service || true
log "Starting services..."
systemctl restart rustdesk-hbbs.service || true
systemctl restart rustdesk-hbbr.service || true
sleep 2
log "=== Status ==="
systemctl status rustdesk-hbbs.service --no-pager || true
systemctl status rustdesk-hbbr.service --no-pager || true
PUB_KEY="$DATA_DIR/id_ed25519.pub"
if [ -f "$PUB_KEY" ]; then
log "=== Server Public Key ==="
cat "$PUB_KEY"
else
log "Public key not found yet. It will be generated on first successful hbbs start."
fi
log "=== Listening Ports ==="
ss -tlnp | grep -E '21115|21116|21117' || true
log "=== Done ==="

39
scripts/open-rustdesk-ports.sh Executable file
View File

@@ -0,0 +1,39 @@
#!/usr/bin/env bash
set -euo pipefail
log() {
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')] $*"
}
if ! command -v ufw >/dev/null 2>&1; then
log "UFW not installed. Installing..."
apt-get update -qq
apt-get install -y -qq ufw
fi
UFW_STATUS=$(ufw status numbered 2>/dev/null || true)
open_port() {
local port=$1
local proto=${2:-tcp}
local rule="$port/$proto"
if echo "$UFW_STATUS" | grep -q "$rule"; then
log "Already open: $rule"
else
log "Opening: $rule"
ufw allow "$rule"
fi
}
log "=== Opening RustDesk Server ports ==="
open_port 21115 tcp
open_port 21116 tcp
open_port 21116 udp
open_port 21117 tcp
open_port 21118 tcp
open_port 21119 tcp
log "=== UFW status ==="
ufw status verbose
log "=== Done ==="

View File

@@ -0,0 +1,17 @@
[Unit]
Description=RustDesk Client (local hbbs)
After=xorg-dummy.service network.target
[Service]
Type=simple
User=root
Environment="DISPLAY=:0"
Environment="XAUTHORITY=/root/.Xauthority"
ExecStartPre=/root/write-rustdesk-config.sh
ExecStartPre=/bin/sleep 2
ExecStart=/usr/share/rustdesk/rustdesk --server
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1,23 @@
[Unit]
Description=RustDesk Server (hbbr — relay)
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/local/bin/hbbr
WorkingDirectory=/var/lib/rustdesk-server
Restart=on-failure
RestartSec=5s
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/lib/rustdesk-server
StandardOutput=journal
StandardError=journal
SyslogIdentifier=rustdesk-hbbr
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1,23 @@
[Unit]
Description=RustDesk Server (hbbs — ID / NAT relay)
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/local/bin/hbbs
WorkingDirectory=/var/lib/rustdesk-server
Restart=on-failure
RestartSec=5s
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/lib/rustdesk-server
StandardOutput=journal
StandardError=journal
SyslogIdentifier=rustdesk-hbbs
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1,18 @@
#!/bin/bash
set -e
CONFIG="/root/.config/rustdesk/RustDesk2.toml"
printf "%s\n" \
"rendezvous_server = 'localhost:21116'" \
"custom-rendezvous-server = 'localhost:21116'" \
"key = 'JDSXd9sxN6Y7mIzu3krSpPTTc4yjChfqpzgIH5fl9Iw='" \
"nat_type = 1" \
"serial = 0" \
"unlock_pin = ''" \
"" \
"[options]" \
"local-ip-addr = '2.59.219.61'" \
> "$CONFIG"
chmod 600 "$CONFIG"
echo "Config written to $CONFIG"