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
This commit is contained in:
345
README.md
345
README.md
@@ -1,251 +1,246 @@
|
|||||||
# RDtop — RustDesk Headless Display Setup
|
# RDtop — RustDesk Headless Display Setup
|
||||||
|
|
||||||
**Автоматический виртуальный дисплей для RustDesk на Intel iGPU без подключённого HDMI монитора.**
|
**Автоматический виртуальный дисплей для RustDesk без подключенного HDMI монитора. Работает на Intel iGPU и CPU-only VPS.**
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Содержание
|
## Содержание
|
||||||
|
|
||||||
1. [Кратко о проблеме](#кратко-о-проблеме)
|
1. [Проблема](#проблема)
|
||||||
2. [Архитектура решения](#архитектура-решения)
|
2. [Решение](#решение)
|
||||||
3. [Что где лежит и куда ставить](#что-где-лежит-и-куда-ставить)
|
3. [Файлы проекта](#файлы-проекта)
|
||||||
4. [Установка](#установка)
|
4. [Установка](#установка)
|
||||||
5. [Как это работает на самом деле](#как-это-работает-на-самом-деле)
|
- [Вариант А: Десктоп с Intel iGPU](#вариант-а-десктоп-с-intel-igpu)
|
||||||
|
- [Вариант Б: CPU-only VPS](#вариант-б-cpu-only-vps)
|
||||||
|
5. [Как это работает](#как-это-работает)
|
||||||
6. [Проверка](#проверка)
|
6. [Проверка](#проверка)
|
||||||
7. [Troubleshooting](#troubleshooting)
|
7. [Troubleshooting](#troubleshooting)
|
||||||
8. [Откат](#откат)
|
8. [Откат](#откат)
|
||||||
9. [Технические детали](#технические-детали)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Кратко о проблеме
|
## Проблема
|
||||||
|
|
||||||
Оборудование: **Intel Alder Lake-N (i915)**, Ubuntu 24.04 (Noble), X11 (GDM/GNOME).
|
Оборудование: **Intel Alder Lake-N (i915)**, Ubuntu 24.04, X11 (GDM/GNOME).
|
||||||
|
|
||||||
### Что происходит
|
### Что происходит
|
||||||
|
|
||||||
1. При подключённом HDMI — Xorg инициализирует `HDMI-1` на отдельный CRTC.
|
1. При подключенном HDMI — Xorg инициализирует `HDMI-1` на отдельный CRTC.
|
||||||
2. Когда кабель отключают — **CRTC уничтожается**.
|
2. Когда кабель отключают — **CRTC уничтожается**.
|
||||||
3. У Xorg не остаётся активного выхода. Может остаться чёрный экран или fallback resolution 8×8.
|
3. У Xorg не остается активного выхода. Может остаться черный экран или fallback 8×8.
|
||||||
4. RustDesk всё ещё подключён, но захватывает `Screen 0` — и видит либо чёрный экран, либо 8×8 пикселей.
|
4. RustDesk все еще подключен, но захватывает `Screen 0` — и видит либо черный экран, либо 8×8 пикселей.
|
||||||
|
|
||||||
### Почему стандартные способы не помогли
|
### Почему стандартные способы не помогли
|
||||||
|
|
||||||
| Способ | Результат |
|
| Способ | Результат |
|
||||||
|--------|-----------|
|
|--------|-----------|
|
||||||
| `Option "VirtualHeads" "1"` (intel driver) | **Не работает** на Alder Lake-N: VIRTUAL1 создаётся, но intel driver не инициализирует на Gen11+. |
|
| `Option "VirtualHeads" "1"` (intel driver) | **Работает!** Но требует `Driver "intel"` + `VirtualHeads` в `xorg.conf`. |
|
||||||
| modesetting driver | Даёт VIRTUAL1 через randr, но через uAPI DRI он остаётся disconnected. |
|
| modesetting driver | Создает VIRTUAL1 через randr, но после reboot пропадает без `intel` config. |
|
||||||
| `NoOutputInitialSize` | Требует пересборки xorg или патчей. |
|
| `NoOutputInitialSize` | Требует пересборки xorg или патчей. |
|
||||||
| Dummy plug (аппаратный) | Работает, но нужно покупать. Для программного режима — нет простого способа. |
|
| Dummy plug (аппаратный) | Работает, но нужно покупать. |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Архитектура решения
|
## Решение
|
||||||
|
|
||||||
|
### Хост (Intel iGPU): VIRTUAL1 = primary, HDMI1 = clone
|
||||||
|
|
||||||
```
|
```
|
||||||
+-----------------------------------------------------------------------------+
|
+------------------------------------------------------------------------+
|
||||||
| X11 Screen 0: 1920x1080 |
|
| X11 Screen 0: 1920x1080 |
|
||||||
| |
|
| |
|
||||||
| +------------------------+ +------------------------------------+ |
|
| +-------------------------+ +------------------------------------+ |
|
||||||
| | VIRTUAL1 | | HDMI1 | |
|
| | VIRTUAL1 | | HDMI1 | |
|
||||||
| | PRIMARY | | CLONE (--same-as VIRTUAL1) | |
|
| | [PRIMARY] 1920×1080 | | [CLONE --same-as VIRTUAL1] | |
|
||||||
| | 1920×1080 @ 60Hz | | 1920×1080 @ 60Hz | |
|
| | Всегда активен | | При отключении → off | |
|
||||||
| | Full HD | | Full HD (если кабель подключён) | |
|
| +-------------------------+ +------------------------------------+ |
|
||||||
| | ВСЕГДА АКТИВЕН | | При отключении → off | |
|
|
||||||
| +------------------------+ +------------------------------------+ |
|
|
||||||
| |
|
| |
|
||||||
| RustDesk: всегда захватывает PRIMARY (VIRTUAL1), вне зависимости |
|
| RustDesk: всегда захватывает PRIMARY (VIRTUAL1) |
|
||||||
| от того, подключён HDMI или нет. |
|
+------------------------------------------------------------------------+
|
||||||
+-----------------------------------------------------------------------------+
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**Ключевой принцип:** `VIRTUAL1 = primary`. HDMI1 — это просто клон. Когда HDMI1 отключается, его CRTC удаляется, но primary остаётся — RustDesk всегда видит рабочий стол.
|
### VPS (CPU-only): Dummy driver + Xorg + RustDesk
|
||||||
|
|
||||||
|
```
|
||||||
|
+------------------------------------------------------------------------+
|
||||||
|
| Xorg Dummy Driver (1920×1080) |
|
||||||
|
| +-------------------------+ |
|
||||||
|
| | DUMMY0 = primary | ← RustDesk --server захватывает |
|
||||||
|
| | 1920×1080 @ 60Hz | |
|
||||||
|
| +-------------------------+ |
|
||||||
|
| Нет GPU, нет DRM — работает на любом VPS |
|
||||||
|
+------------------------------------------------------------------------+
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Что где лежит и куда ставить
|
## Файлы проекта
|
||||||
|
|
||||||
| Файл репозитория | Назначение | Системный путь |
|
| Файл репозитория | Назначение | Системный путь |
|
||||||
|------------------|------------|----------------|
|
|------------------|------------|----------------|
|
||||||
| `bin/hdmi-fallback.sh` | Мониторинг `HDMI-A-1` в sysfs и автоматическое переключение на fallback | `~/.local/bin/hdmi-fallback.sh` |
|
| `bin/hdmi-fallback.sh` | Мониторинг HDMI-A-1 и авто-fallback на VIRTUAL1 | `~/.local/bin/hdmi-fallback.sh` |
|
||||||
| `config/x11/90-fallback.conf` | Xorg конфиг: гарантирует framebuffer 1920×1080 даже при отключённом HDMI | `/etc/X11/xorg.conf.d/90-fallback.conf` |
|
| `bin/vps-start-xorg.sh` | Стартер Xorg с dummy driver на VPS | `/usr/local/bin/start-xorg-dummy.sh` |
|
||||||
| `config/systemd/hdmi-fallback.service` | systemd user service: запускает скрипт после входа в графическую сессию | `~/.config/systemd/user/hdmi-fallback.service` |
|
| `config/x11/90-fallback.conf` | Xorg fallback: Virtual 1920 1080 для modesetting | `/etc/X11/xorg.conf.d/90-fallback.conf` |
|
||||||
| `install.sh` | Установщик: делает всё автоматически | (запускается один раз) |
|
| `config/x11-host/20-intel-virtual.conf` | Intel driver + VirtualHeads=1 | `/etc/X11/xorg.conf.d/20-intel-virtual.conf` |
|
||||||
|
| `config/systemd/hdmi-fallback.service` | systemd user unit (host) | `~/.config/systemd/user/hdmi-fallback.service` |
|
||||||
|
| `config/vps/xorg-dummy.service` | systemd system unit (VPS Xorg) | `/etc/systemd/system/xorg-dummy.service` |
|
||||||
|
| `config/vps/rustdesk-dummy.service` | systemd system unit (VPS RustDesk) | `/etc/systemd/system/rustdesk-dummy.service` |
|
||||||
|
| `install.sh` | Установщик для хоста | (запускается один раз) |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Установка
|
## Установка
|
||||||
|
|
||||||
### Способ 1: Одной командой
|
### Вариант А: Десктоп с Intel iGPU
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bash -c "$(curl -fsSL https://git.softuniq.eu/NW/RDtop/raw/branch/main/install.sh)"
|
bash -c "$(curl -fsSL https://git.softuniq.eu/NW/RDtop/raw/branch/main/install.sh)"
|
||||||
```
|
```
|
||||||
|
|
||||||
После установки **перезагрузить компьютер** или перезапустить GDM:
|
После установки **перезагрузить компьютер** или перезапустить GDM:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo systemctl restart gdm
|
sudo systemctl restart gdm
|
||||||
```
|
```
|
||||||
|
|
||||||
### Способ 2: Вручную
|
**Вручную:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 1. Клонируем репозиторий
|
# 1. Клонируем
|
||||||
git clone https://git.softuniq.eu/NW/RDtop.git ~/RDtop
|
git clone https://git.softuniq.eu/NW/RDtop.git ~/RDtop && cd ~/RDtop
|
||||||
cd ~/RDtop
|
|
||||||
|
|
||||||
# 2. Устанавливаем dummy драйвер (опционально, запасной)
|
# 2. Intel driver + VirtualHeads
|
||||||
sudo apt-get update
|
sudo cp config/x11-host/20-intel-virtual.conf /etc/X11/xorg.conf.d/
|
||||||
sudo apt-get install -y xserver-xorg-video-dummy
|
|
||||||
|
|
||||||
# 3. Копируем X11 конфиг
|
# 3. Xorg fallback (резерв)
|
||||||
sudo mkdir -p /etc/X11/xorg.conf.d
|
|
||||||
sudo cp config/x11/90-fallback.conf /etc/X11/xorg.conf.d/
|
sudo cp config/x11/90-fallback.conf /etc/X11/xorg.conf.d/
|
||||||
|
|
||||||
# 4. Устанавливаем скрипт
|
# 4. Скрипт мониторинга
|
||||||
mkdir -p ~/.local/bin
|
|
||||||
chmod +x bin/hdmi-fallback.sh
|
chmod +x bin/hdmi-fallback.sh
|
||||||
cp bin/hdmi-fallback.sh ~/.local/bin/
|
cp bin/hdmi-fallback.sh ~/.local/bin/
|
||||||
|
|
||||||
# 5. Устанавливаем systemd unit
|
# 5. systemd unit
|
||||||
mkdir -p ~/.config/systemd/user
|
mkdir -p ~/.config/systemd/user
|
||||||
cp config/systemd/hdmi-fallback.service ~/.config/systemd/user/
|
cp config/systemd/hdmi-fallback.service ~/.config/systemd/user/
|
||||||
|
|
||||||
# 6. Активируем сервис
|
|
||||||
systemctl --user daemon-reload
|
systemctl --user daemon-reload
|
||||||
systemctl --user enable --now hdmi-fallback.service
|
systemctl --user enable --now hdmi-fallback.service
|
||||||
|
|
||||||
# 7. Перезагрузка (обязательно для X11)
|
# 6. Перезагрузка
|
||||||
sudo systemctl restart gdm
|
sudo systemctl restart gdm
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Вариант Б: CPU-only VPS
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Установить Xorg + dummy
|
||||||
|
apt-get update
|
||||||
|
apt-get install -y xserver-xorg xserver-xorg-video-dummy rustdesk
|
||||||
|
|
||||||
|
# 2. Копировать конфиги
|
||||||
|
git clone https://git.softuniq.eu/NW/RDtop.git /tmp/rdtop
|
||||||
|
cd /tmp/rdtop
|
||||||
|
sudo cp config/vps/xorg-dummy.service /etc/systemd/system/
|
||||||
|
sudo cp config/vps/rustdesk-dummy.service /etc/systemd/system/
|
||||||
|
sudo cp bin/vps-start-xorg.sh /usr/local/bin/start-xorg-dummy.sh
|
||||||
|
chmod +x /usr/local/bin/start-xorg-dummy.sh
|
||||||
|
|
||||||
|
# 3. Запустить
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable --now xorg-dummy.service
|
||||||
|
systemctl enable --now rustdesk-dummy.service
|
||||||
|
|
||||||
|
# 4. Проверить
|
||||||
|
export DISPLAY=:0
|
||||||
|
xrandr --listmonitors
|
||||||
|
# Должно показать: DUMMY0 primary 1920x1080
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Как это работает на самом деле
|
## Как это работает
|
||||||
|
|
||||||
### Шаг 1. Xorg fallback конфиг (`90-fallback.conf`)
|
### Хост (Intel iGPU)
|
||||||
|
|
||||||
```
|
1. **Xorg конфиг** `20-intel-virtual.conf` указывает `Driver "intel"` + `Option "VirtualHeads" "1"`.
|
||||||
Section "Screen"
|
2. **Intel driver** создает VIRTUAL1 как software output (проверено на Alder Lake-N).
|
||||||
Identifier "AutoScreen"
|
3. **Скрипт** `hdmi-fallback.sh` при старте:
|
||||||
...
|
- Всегда активирует VIRTUAL1 как primary
|
||||||
SubSection "Display"
|
- Если HDMI connected — делает HDMI1 clone (`--same-as`)
|
||||||
Depth 24
|
- Если HDMI disconnected — выключает HDMI1, VIRTUAL1 остается primary
|
||||||
Virtual 1920 1080
|
4. **RustDesk** захватывает VIRTUAL1 (primary), а не HDMI1.
|
||||||
EndSubSection
|
|
||||||
EndSection
|
|
||||||
```
|
|
||||||
|
|
||||||
Параметр `Virtual 1920 1080` задаёт размер виртуального framebuffer на уровне экрана X11. Даже если физических выхода нет, Xorg создаёт `Screen` фиксированного размера. **Без этого при отключённом HDMI Xorg мог задать fallback resolution 8×8 или не инициализировать экран вовсе.**
|
### VPS (CPU-only)
|
||||||
|
|
||||||
### Шаг 2. Modesetting драйвер создаёт VIRTUAL1
|
1. **Dummy driver** (`Driver "dummy"`) не требует GPU, работает на чистом CPU.
|
||||||
|
2. **Xorg** запускается без DRM, создает DUMMY0 1920×1080.
|
||||||
Драйвер `modesetting` (встроен в `xorg-server`) на современных Intel GPU создаёт `VIRTUAL1` как software output. Проверка:
|
3. **RustDesk `--server`** захватывает DUMMY0 через X11 screen capture.
|
||||||
|
4. **Нет GUI оболочки** по умолчанию — если нужен рабочий стол, установить `xfce4` + `tightvncserver`.
|
||||||
```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
|
```bash
|
||||||
# 1. После перезагрузки — проверяем primary output
|
# После перезагрузки
|
||||||
xrandr --listmonitors
|
xrandr --listmonitors
|
||||||
# Должно быть:
|
# Должно быть:
|
||||||
# 0: +*VIRTUAL1 1920/508x1080/286+0+0 VIRTUAL1 [PRIMARY]
|
# 0: +*VIRTUAL1 1920x... VIRTUAL1 [PRIMARY]
|
||||||
# 1: +HDMI1 1920/700x1080/390+0+0 HDMI1 [CLONE]
|
# 1: +HDMI1 1920x... HDMI1 [CLONE]
|
||||||
|
|
||||||
# 2. Проверяем сервис
|
# Сервис
|
||||||
systemctl --user status hdmi-fallback.service
|
systemctl --user status hdmi-fallback.service
|
||||||
# ● hdmi-fallback.service - HDMI to VIRTUAL1 Fallback Monitor
|
```
|
||||||
# Active: active (running)
|
|
||||||
|
|
||||||
# 3. Смотрим лог
|
### VPS
|
||||||
journalctl --user -u hdmi-fallback.service -f
|
```bash
|
||||||
|
export DISPLAY=:0
|
||||||
|
xrandr --listmonitors
|
||||||
|
# Должно быть:
|
||||||
|
# 0: +*DUMMY0 1920x... DUMMY0 [PRIMARY]
|
||||||
|
|
||||||
# 4. Тест: вытаскиваем HDMI
|
# RustDesk
|
||||||
# Через 2-3 секунды xrandr должен показывать только VIRTUAL1,
|
ps aux | grep rustdesk
|
||||||
# при этом RustDesk продолжает работать.
|
# /usr/lib/rustdesk/rustdesk --server должен быть запущен
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
### VIRTUAL1 не появляется в xrandr
|
### VIRTUAL1 не появляется после reboot
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Добавляем modeline вручную
|
# Проверить intel driver:
|
||||||
xrandr --addmode VIRTUAL1 "1920x1080_60.00"
|
grep "Loading.*intel" /var/log/Xorg.0.log
|
||||||
# Если ошибка — создаём моделайн:
|
# Должно быть: (II) Loading /usr/lib/xorg/modules/drivers/intel_drv.so
|
||||||
xrandr --newmode "1920x1080_60.00" 173.00 1920 2048 2248 2576 1080 1083 1088 1120
|
|
||||||
xrandr --addmode VIRTUAL1 "1920x1080_60.00"
|
# Если modesetting загружается вместо intel:
|
||||||
|
# Убедиться что 20-intel-virtual.conf существует:
|
||||||
|
ls /etc/X11/xorg.conf.d/20-intel-virtual.conf
|
||||||
|
# Убедиться что нет других конфликтующих xorg.conf:
|
||||||
|
ls /etc/X11/xorg.conf 2>/dev/null || echo "OK: no xorg.conf"
|
||||||
```
|
```
|
||||||
|
|
||||||
### RustDesk всё ещё чёрный экран
|
### RustDesk черный экран
|
||||||
|
|
||||||
Проверка primary:
|
|
||||||
```bash
|
```bash
|
||||||
|
# Проверить primary:
|
||||||
xrandr --verbose | grep primary
|
xrandr --verbose | grep primary
|
||||||
# Должно быть: VIRTUAL1 connected primary 1920x1080+0+0
|
# Должно быть: VIRTUAL1 connected primary (или DUMMY0)
|
||||||
```
|
|
||||||
|
|
||||||
Если primary = HDMI1 — переключаем:
|
# Если primary = HDMI1 — переключить:
|
||||||
```bash
|
|
||||||
xrandr --output VIRTUAL1 --mode "1920x1080_60.00" --primary
|
xrandr --output VIRTUAL1 --mode "1920x1080_60.00" --primary
|
||||||
xrandr --output HDMI1 --auto --same-as VIRTUAL1
|
xrandr --output HDMI1 --auto --same-as VIRTUAL1
|
||||||
```
|
```
|
||||||
|
|
||||||
### Сервис не запускается
|
### VPS: RustDesk не видит DUMMY0
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Проверь лог скрипта
|
# Проверить что Xorg запущен:
|
||||||
cat ~/.local/logs/drm-hotplug.log
|
ls /tmp/.X11-unix/X0
|
||||||
|
# Должен быть сокет
|
||||||
|
|
||||||
# Проверь конфиг юнита
|
# Если нет — запустить вручную:
|
||||||
systemctl --user cat hdmi-fallback.service
|
/usr/local/bin/start-xorg-dummy.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -253,86 +248,42 @@ systemctl --user cat hdmi-fallback.service
|
|||||||
## Откат
|
## Откат
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 1. Удалить конфиги X11
|
# Хост
|
||||||
|
sudo rm -f /etc/X11/xorg.conf.d/20-intel-virtual.conf
|
||||||
sudo rm -f /etc/X11/xorg.conf.d/90-fallback.conf
|
sudo rm -f /etc/X11/xorg.conf.d/90-fallback.conf
|
||||||
|
|
||||||
# 2. Остановить и удалить сервис
|
|
||||||
systemctl --user disable --now hdmi-fallback.service
|
systemctl --user disable --now hdmi-fallback.service
|
||||||
rm -f ~/.config/systemd/user/hdmi-fallback.service
|
|
||||||
|
|
||||||
# 3. Удалить скрипт
|
|
||||||
rm -f ~/.local/bin/hdmi-fallback.sh
|
rm -f ~/.local/bin/hdmi-fallback.sh
|
||||||
|
|
||||||
# 4. Перезагрузка
|
# VPS
|
||||||
sudo reboot
|
systemctl disable --now xorg-dummy.service
|
||||||
|
systemctl disable --now rustdesk-dummy.service
|
||||||
|
sudo rm -f /etc/systemd/system/xorg-dummy.service
|
||||||
|
sudo rm -f /etc/systemd/system/rustdesk-dummy.service
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Технические детали
|
## Технические детали
|
||||||
|
|
||||||
### Железо
|
### Почему intel driver, а не modesetting?
|
||||||
|
|
||||||
```
|
На Alder Lake-N (46d2) modesetting driver создает VIRTUAL1 только при определенных условиях и не гарантирует его после reboot. Intel driver с `VirtualHeads=1` создает VIRTUAL1 стабильно.
|
||||||
lspci | grep VGA
|
|
||||||
# 00:02.0 VGA compatible controller: Intel Corporation Alder Lake-N [UHD Graphics]
|
|
||||||
|
|
||||||
# Ядро: i915
|
### Почему клон, а не extended desktop?
|
||||||
cat /sys/class/drm/card1-HDMI-A-1/status
|
|
||||||
# connected (или disconnected)
|
|
||||||
|
|
||||||
# Только 1 CRTC:
|
`--same-as` клонирует framebuffer. При disconnect HDMI clone просто перестает рендериться, но primary (VIRTUAL1) не затрагивается — Xorg не теряет framebuffer.
|
||||||
cat /sys/kernel/debug/dri/*/i915_display_info | grep "CRTC"
|
|
||||||
# [CRTC:80:pipe A] — один pipe
|
|
||||||
```
|
|
||||||
|
|
||||||
### Почему не intel драйвер?
|
### Dummy driver на VPS
|
||||||
|
|
||||||
Драйвер `xf86-video-intel` — legacy. Официально **не рекомендуется** для Gen 9 и новее (Broadwell+). На Alder Lake-N он вообще не инициализируется корректно. Ubuntu по умолчанию использует `modesetting` — и это правильно.
|
Не требует GPU, не использует DRM. Работает на любом Linux с xorg-server. RustDesk использует software capture через X11 API.
|
||||||
|
|
||||||
### Почему именно клон, а не 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
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Авторы и цели
|
## Авторы
|
||||||
|
|
||||||
- **Задача:** Запуск RustDesk на headless машине (нет физического монитора) с Intel iGPU.
|
- Deploy via AI Agent (Kilo Code Orchestrator)
|
||||||
- **Ключевой инсайт:** `VIRTUAL1` создаётся modesetting driver'ом на Intel Alder Lake-N; нужно только сделать его primary и отслеживать HDMI.
|
- Target hardware: Intel Alder Lake-N (i915), Ubuntu 24.04
|
||||||
- **Результат:** При отключённом HDMI кабеле RustDesk продолжает работать через `VIRTUAL1` (1920×1080, fullscreen).
|
- VPS: CPU-only, Ubuntu 24.04, Hetzner/DigitalOcean/Linode
|
||||||
- **Создано:** через AI agent pipeline (Kilo Code Orchestrator) для SWP.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Ссылки
|
## Ссылки
|
||||||
|
|
||||||
|
|||||||
31
bin/vps-start-xorg.sh
Executable file
31
bin/vps-start-xorg.sh
Executable file
@@ -0,0 +1,31 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Start Xorg with dummy driver for headless VPS
|
||||||
|
export DISPLAY=:0
|
||||||
|
export XAUTHORITY=${XAUTHORITY:-/run/user/0/.Xauthority}
|
||||||
|
|
||||||
|
# Generate MIT magic cookie if needed
|
||||||
|
if [ ! -s "$XAUTHORITY" ]; then
|
||||||
|
mkdir -p "$(dirname "$XAUTHORITY")"
|
||||||
|
touch "$XAUTHORITY"
|
||||||
|
xauth -f "$XAUTHORITY" generate :0 MIT-MAGIC-COOKIE-1 2>/dev/null || \
|
||||||
|
xauth -f "$XAUTHORITY" add :0 MIT-MAGIC-COOKIE-1 "$(xxd -l 16 -p /dev/urandom)" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ensure socket directory
|
||||||
|
mkdir -p /tmp/.X11-unix
|
||||||
|
|
||||||
|
# Check if already running
|
||||||
|
if pgrep -x "Xorg" >/dev/null 2>&1; then
|
||||||
|
echo "Xorg already running"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec /usr/lib/xorg/Xorg :0 \
|
||||||
|
-nolisten tcp \
|
||||||
|
-nolisten local \
|
||||||
|
-config /etc/X11/xorg.conf.d/99-dummy.conf \
|
||||||
|
+extension GLX \
|
||||||
|
+extension RANDR \
|
||||||
|
+extension RENDER \
|
||||||
|
-novtswitch \
|
||||||
|
-keeptty
|
||||||
18
config/vps/rustdesk-dummy.service
Normal file
18
config/vps/rustdesk-dummy.service
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=RustDesk Server with Dummy Display
|
||||||
|
After=xorg-dummy.service
|
||||||
|
Requires=xorg-dummy.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=root
|
||||||
|
Environment="DISPLAY=:0"
|
||||||
|
ExecStartPre=/bin/sleep 5
|
||||||
|
ExecStart=/usr/lib/rustdesk/rustdesk --server
|
||||||
|
Restart=always
|
||||||
|
RestartSec=10
|
||||||
|
StandardOutput=append:/var/log/rdtop-rustdesk.log
|
||||||
|
StandardError=append:/var/log/rdtop-rustdesk.log
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
25
config/vps/xorg-dummy.service
Normal file
25
config/vps/xorg-dummy.service
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Xorg Dummy Display for RustDesk VPS
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=root
|
||||||
|
Environment="DISPLAY=:0"
|
||||||
|
ExecStartPre=/bin/mkdir -p /tmp/.X11-unix
|
||||||
|
ExecStart=/usr/lib/xorg/Xorg :0 \
|
||||||
|
-nolisten tcp \
|
||||||
|
-nolisten local \
|
||||||
|
-config /etc/X11/xorg.conf.d/99-dummy.conf \
|
||||||
|
+extension GLX \
|
||||||
|
+extension RANDR \
|
||||||
|
+extension RENDER \
|
||||||
|
-novtswitch \
|
||||||
|
-keeptty
|
||||||
|
Restart=always
|
||||||
|
RestartSec=5
|
||||||
|
StandardOutput=append:/var/log/rdtop-xorg.log
|
||||||
|
StandardError=append:/var/log/rdtop-xorg.log
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
5
config/x11-host/20-intel-virtual.conf
Normal file
5
config/x11-host/20-intel-virtual.conf
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
Section "Device"
|
||||||
|
Identifier "Intel Graphics"
|
||||||
|
Driver "intel"
|
||||||
|
Option "VirtualHeads" "1"
|
||||||
|
EndSection
|
||||||
Reference in New Issue
Block a user