- 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.
13 KiB
RDtop — RustDesk Headless Display Setup
Автоматический виртуальный дисплей для RustDesk без подключенного HDMI монитора. Работает на любой Linux машине (Intel iGPU, AMD, NVIDIA, CPU-only VPS).
Содержание
Проблема
Оборудование: Intel Alder Lake-N (i915), Ubuntu 24.04, X11 (GDM/GNOME).
Что происходит
- При подключенном HDMI — Xorg инициализирует
HDMI-1на отдельный CRTC. - Когда кабель отключают — CRTC уничтожается.
- У Xorg не остается активного выхода. Может остаться черный экран или fallback 8×8.
- RustDesk все еще подключен, но захватывает
Screen 0— и видит либо черный экран, либо 8×8 пикселей.
Почему стандартные способы не помогли
| Способ | Результат |
|---|---|
Option "VirtualHeads" "1" (intel driver) |
Работает только с кабелем на момент загрузки. Без HDMI — VIRTUAL1 не создается. |
| modesetting driver | Создает VIRTUAL1 через randr, но после reboot пропадает. |
NoOutputInitialSize |
Требует пересборки xorg или патчей. |
| Dummy plug (аппаратный) | Работает, но нужно покупать. |
Решение
Хост: Dummy driver + kernel EDID fallback
Работает без кабеля HDMI на момент загрузки — dummy driver не зависит от физических выходов.
+------------------------------------------------------------------------+
| Xorg Dummy Driver (1920×1080) |
| +-------------------------+ |
| | DUMMY0 = primary | ← RustDesk --server захватывает |
| | 1920×1080 @ 60Hz | |
| +-------------------------+ |
| |
| При подключении HDMI кабеля: |
| скрипт hdmi-fallback.sh клонирует HDMI1 на DUMMY0 |
| При отключении: HDMI1 off, DUMMY0 остается primary |
+------------------------------------------------------------------------+
Kernel EDID fallback (дополнительно)
Параметры ядра:
video=HDMI-A-1:1920x1080@60 drm.edid_firmware=HDMI-A-1:edid/samsung.bin
Это заставляет ядро i915 инициализировать HDMI-A-1 с сохраненным EDID даже без кабеля. Если dummy driver не сработает (редкий случай), ядро все равно создаст виртуальный framebuffer.
VPS (CPU-only): Dummy driver + Xorg + RustDesk
Тот же dummy driver, но без GPU. Работает на любом VPS.
+------------------------------------------------------------------------+
| Xorg Dummy Driver (1920×1080) |
| +-------------------------+ |
| | DUMMY0 = primary | ← RustDesk --server захватывает |
| | 1920×1080 @ 60Hz | |
| +-------------------------+ |
| Нет GPU, нет DRM — работает на любом VPS |
+------------------------------------------------------------------------+
Файлы проекта
| Файл репозитория | Назначение | Системный путь |
|---|---|---|
bin/hdmi-fallback.sh |
Мониторинг HDMI-A-1 и авто-fallback на DUMMY0/VIRTUAL1 | ~/.local/bin/hdmi-fallback.sh |
bin/vps-start-xorg.sh |
Стартер Xorg с dummy driver на VPS | /usr/local/bin/start-xorg-dummy.sh |
config/x11-host/20-dummy-headless.conf |
Dummy driver headless config | /etc/X11/xorg.conf.d/20-dummy-headless.conf |
config/x11-host/20-intel-virtual.conf.bak |
Backup старого Intel config (не используется) | — |
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 |
Установщик для хоста | (запускается один раз) |
Установка
Хост (Desktop с GPU)
bash -c "$(curl -fsSL https://git.softuniq.eu/NW/RDtop/raw/branch/main/install.sh)"
После установки перезагрузить компьютер:
sudo reboot
Вручную:
# 1. Клонируем
git clone https://git.softuniq.eu/NW/RDtop.git ~/RDtop && cd ~/RDtop
# 2. Dummy driver config (главный способ)
sudo cp config/x11-host/20-dummy-headless.conf /etc/X11/xorg.conf.d/
# 3. Удалить старые конфиги если были
sudo rm -f /etc/X11/xorg.conf.d/20-intel-virtual.conf
sudo rm -f /etc/X11/xorg.conf.d/90-fallback.conf
# 4. Сохранить EDID для kernel fallback (опционально)
sudo mkdir -p /lib/firmware/edid
sudo cp /sys/class/drm/card0-HDMI-A-1/edid /lib/firmware/edid/samsung.bin
# 5. Обновить GRUB для kernel EDID fallback
sudo sed -i 's|GRUB_CMDLINE_LINUX_DEFAULT=".*"|GRUB_CMDLINE_LINUX_DEFAULT="quiet splash video=HDMI-A-1:1920x1080@60 drm.edid_firmware=HDMI-A-1:edid/samsung.bin"|' /etc/default/grub
sudo update-grub
# 6. Скрипт мониторинга
chmod +x bin/hdmi-fallback.sh
cp bin/hdmi-fallback.sh ~/.local/bin/
# 7. systemd unit
mkdir -p ~/.config/systemd/user
cp config/systemd/hdmi-fallback.service ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now hdmi-fallback.service
# 8. Перезагрузка
sudo reboot
Вариант Б: CPU-only VPS
# 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
Как это работает
Хост (Intel iGPU)
- Dummy driver (
Driver "dummy") создает DUMMY0 сразу при старте Xorg, независимо от HDMI. - Kernel EDID fallback (
drm.edid_firmware) — если dummy каким-то образом не сработает, ядроi915инициализирует HDMI-A-1 с сохраненным EDID. - Скрипт
hdmi-fallback.shпри старте:- Всегда активирует DUMMY0 как primary
- Если HDMI connected — делает HDMI1 clone (
--same-as) - Если HDMI disconnected — выключает HDMI1, DUMMY0 остается primary
- RustDesk захватывает DUMMY0 (primary).
VPS (CPU-only)
- Dummy driver (
Driver "dummy") не требует GPU, работает на чистом CPU. - Xorg запускается без DRM, создает DUMMY0 1920×1080.
- RustDesk
--serverзахватывает DUMMY0 через X11 screen capture. - Нет GUI оболочки по умолчанию — если нужен рабочий стол, установить
xfce4+tightvncserver.
Проверка
Хост (после reboot без HDMI)
# Должно показать DUMMY0 как primary
xrandr --listmonitors
# Ожидаемый вывод:
# 0: +*DUMMY0 1920/508x1080/286+0+0 DUMMY0 [PRIMARY]
# Если HDMI подключен:
# 1: +HDMI-1 1920/508x1080/286+0+0 HDMI-1 [CLONE]
Сервис
systemctl --user status hdmi-fallback.service
Логи
cat ~/.local/logs/drm-hotplug.log
VPS
export DISPLAY=:0
xrandr --listmonitors
# Должно быть:
# 0: +*DUMMY0 1920x... DUMMY0 [PRIMARY]
# RustDesk
ps aux | grep rustdesk
# /usr/lib/rustdesk/rustdesk --server должен быть запущен
Troubleshooting
DUMMY0 не появляется после reboot
# Проверить dummy driver:
grep "Loading.*dummy" /var/log/Xorg.0.log
# Должно быть: (II) Loading /usr/lib/xorg/modules/drivers/dummy_drv.so
# Проверить конфиг:
ls /etc/X11/xorg.conf.d/20-dummy-headless.conf
# Должен существовать
# Если intel driver загружается вместо dummy:
# Убедиться что нет других конфликтующих xorg.conf:
ls /etc/X11/xorg.conf 2>/dev/null || echo "OK: no xorg.conf"
RustDesk черный экран
# Проверить primary:
xrandr --verbose | grep primary
# Должно быть: DUMMY0 connected primary
# Если primary не DUMMY0:
xrandr --output DUMMY0 --mode "1920x1080" --primary
xrandr --output HDMI-1 --auto --same-as DUMMY0
VPS: RustDesk не видит DUMMY0
# Проверить что Xorg запущен:
ls /tmp/.X11-unix/X0
# Должен быть сокет
# Если нет — запустить вручную:
/usr/local/bin/start-xorg-dummy.sh
Откат
# Хост
sudo rm -f /etc/X11/xorg.conf.d/20-dummy-headless.conf
sudo rm -f /etc/X11/xorg.conf.d/20-intel-virtual.conf
sudo rm -f /etc/X11/xorg.conf.d/90-fallback.conf
systemctl --user disable --now hdmi-fallback.service
rm -f ~/.local/bin/hdmi-fallback.sh
# Вернуть стандартный GRUB:
sudo sed -i 's|GRUB_CMDLINE_LINUX_DEFAULT=".*"|GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"|' /etc/default/grub
sudo update-grub
# VPS
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
Технические детали
Почему dummy driver, а не intel с VirtualHeads?
intel driver + VirtualHeads=1 работает только если HDMI подключен при загрузке. Без кабеля — ядро не создает connector/CRTC для HDMI-A-1, и VirtualHeads не помогает. Dummy driver не зависит от физических выходов.
Почему kernel EDID fallback?
Параметры video=HDMI-A-1:1920x1080@60 и drm.edid_firmware=HDMI-A-1:edid/samsung.bin заставляют ядро i915 инициализировать connector с фиктивным EDID. Это "страховка": если dummy driver по какой-то причине не загрузится (например, обновление Xorg удалит его), ядро все равно создаст выход.
Почему клон, а не extended desktop?
--same-as клонирует framebuffer. При disconnect HDMI clone просто перестает рендериться, но primary (DUMMY0) не затрагивается — Xorg не теряет framebuffer.
Dummy driver на VPS
Не требует GPU, не использует DRM. Работает на любом Linux с xorg-server. RustDesk использует software capture через X11 API.
Авторы
- Deploy via AI Agent (Kilo Code Orchestrator)
- Target hardware: Intel Alder Lake-N (i915), Ubuntu 24.04
- VPS: CPU-only, Ubuntu 24.04, Hetzner/DigitalOcean/Linode
Ссылки
- Репозиторий:
https://git.softuniq.eu/NW/RDtop - Установщик:
bash -c "$(curl -fsSL https://git.softuniq.eu/NW/RDtop/raw/branch/main/install.sh)"