Проброс видеокарты в ВМ Proxmox: GPU passthrough
Разбираем проброс видеокарты в ВМ Proxmox VE 9: IOMMU в прошивке и в ядре, группы IOMMU, привязка к vfio-pci, q35 с OVMF и почему ломается консоль хоста.
Проброс видеокарты в Proxmox: что вы получаете и что теряете
Проброс видеокарты в ВМ Proxmox (GPU passthrough) отдаёт физическую карту одной виртуальной машине целиком. Гость видит настоящее устройство PCI Express и работает с ним родным драйвером, поэтому внутри ВМ доступны CUDA, NVENC и вывод на реальный монитор. Хост при этом карту не видит вообще: подсистема VFIO забирает устройство себе, и вернуть его хосту надёжно можно только остановкой ВМ и перезагрузкой.
Текст написан под Proxmox VE 9.x. Версия 9.2 вышла 21 мая 2026 года и собрана на Debian 13. Речь идёт про машину, которой вы владеете: домашний сервер или железо в колокации, где вы управляете прошивкой материнской платы. На арендованной виртуалке ничего из этого сделать нельзя, потому что там гость уже вы.
Все команды ниже выполняете вы на своём хосте, и результат зависит от вашего железа. Порядок шагов не произвольный: каждый следующий проверяет результат предыдущего.
- Включить IOMMU в прошивке материнской платы.
- Убедиться, что ядро хоста его действительно использует.
- Прочитать группы IOMMU и понять, одна ли карта в своей группе.
- Привязать карту к vfio-pci и убрать хостовой драйвер.
- Собрать ВМ на машине q35 с прошивкой OVMF и отдать ей обе функции карты.
Что такое IOMMU и почему его включают в двух местах
IOMMU (input/output memory management unit) это блок процессора и чипсета, который транслирует адреса памяти для устройств так же, как MMU транслирует их для процессов. Без IOMMU устройство обращается к физической памяти напрямую через DMA (direct memory access, прямой доступ к памяти) и может прочитать или испортить любой её байт. Отдать такое устройство гостю означает отдать гостю всю память хоста. Именно поэтому ядро отказывается пробрасывать PCI-устройство, пока IOMMU не работает: у него нет способа ограничить DMA гостя памятью самого гостя.
Включать приходится в двух местах, потому что это две разные вещи. В прошивке (VT-d у Intel, AMD-Vi или просто IOMMU у AMD) вы разрешаете платформе опубликовать таблицы ACPI: DMAR у Intel, IVRS у AMD. Пока прошивка их не публикует, ядру нечего использовать, и никакой параметр загрузки этого не исправит. На стороне ядра вы разрешаете драйверу эти таблицы взять и начать ремаппинг адресов. Названия пунктов в прошивке различаются у каждого производителя, ищите VT-d, AMD-Vi, IOMMU или SVM. Рядом обычно лежат Above 4G decoding и Resizable BAR, они относятся к работе самой карты, а не к IOMMU.
Проверка на хосте одна:
dmesg | grep -e DMAR -e IOMMU -e AMD-ViОдной строки, которую можно искать буквально, тут нет: точный текст зависит от оборудования и версии ядра. Вам нужно увидеть упоминание того, что IOMMU или Directed I/O включён, и строки про interrupt remapping. Пустой вывод означает, что дальше идти бессмысленно, возвращайтесь в прошивку.
На ядрах 6.8 и новее IOMMU включается по умолчанию и на Intel, и на AMD, поэтому на Proxmox VE 9 параметр intel_iommu=on обычно уже не нужен. В старых руководствах он есть потому, что раньше был обязателен. Вреда он не приносит, так что если dmesg молчит, добавить его стоит: это дешёвая проверка гипотезы.
Как добавить параметры ядра: GRUB или systemd-boot
На этом шаге теряют больше всего времени, потому что правят файл не того загрузчика. Установщик Proxmox VE ставит systemd-boot на UEFI-системах, где корень лежит на ZFS, и GRUB в остальных случаях, а содержимым разделов EFI (ESP, EFI System Partition) управляет утилита proxmox-boot-tool. Не угадывайте, спросите систему:
proxmox-boot-tool status
efibootmgr -vВ выводе efibootmgr -v путь с grubx64.efi означает GRUB в режиме UEFI, shimx64.efi означает GRUB с включённым Secure Boot, а systemd-bootx64.efi означает systemd-boot. Если переменные EFI недоступны, у вас GRUB в legacy-режиме.
Для GRUB параметры идут в переменную GRUB_CMDLINE_LINUX_DEFAULT файла /etc/default/grub, после чего конфигурацию нужно пересобрать:
nano /etc/default/grub
# GRUB_CMDLINE_LINUX_DEFAULT="quiet iommu=pt"
update-grubДля systemd-boot параметры идут в /etc/kernel/cmdline. Это ровно одна строка, без пустых строк перед ней, и в ней уже стоит корневая файловая система, которую трогать нельзя. Дописывайте свои параметры в конец той же строки, затем синхронизируйте разделы EFI:
nano /etc/kernel/cmdline
proxmox-boot-tool refreshПосле перезагрузки проверьте, что ядро получило именно то, что вы написали:
cat /proc/cmdlineЕсли /proc/cmdline не изменился, вы правили не тот файл. Это самая частая причина жалобы "IOMMU включён в биосе, а Proxmox его не видит": ZFS-система с systemd-boot просто не читает /etc/default/grub, и update-grub на ней не делает ничего полезного. Параметр iommu=pt в примере необязателен, документация Proxmox упоминает его как возможное улучшение производительности, а не как требование.
Группы IOMMU: почему карта не уезжает одна
VFIO (virtual function I/O, подсистема ядра для передачи устройств в пространство пользователя) работает не с отдельными устройствами, а с группами IOMMU. Группа это наименьший набор устройств, который IOMMU умеет изолировать от остальных. Если два устройства попали в одну группу, они способны обращаться к памяти друг друга в обход IOMMU, поэтому ядро отдаёт группу только целиком. Отсюда сообщение, которое появляется в логе задачи при старте ВМ:
vfio: error, group 12 is not viable, please ensure all devices within the iommu_group are bound to their vfio bus driverПосмотреть свои группы можно обходом sysfs:
for d in /sys/kernel/iommu_groups/*/devices/*; do
n=${d#*/iommu_groups/*}; n=${n%%/*}
printf 'IOMMU group %s ' "$n"
lspci -nns "${d##*/}"
doneТо же самое умеет сам Proxmox, подставьте имя своего узла вместо NODE:
pvesh get /nodes/NODE/hardware/pci --pci-class-blacklist ""Хорошая группа это группа, где кроме вашей карты нет ничего чужого. Функции самой карты в ней быть обязаны: видеокарта почти всегда представлена двумя устройствами, 01:00.0 для графики и 01:00.1 для HDMI-аудио, а у свежих моделей встречаются ещё контроллеры USB-C и UCSI. Их пробрасывают вместе. Корневой порт PCIe или мост в той же группе тоже допустимы. А вот сетевая карта, контроллер NVMe или USB-хаб рядом с видеокартой означают, что пробросить придётся и их, то есть хост останется без диска или без сети.
Что с этим делают на практике. Самое эффективное действие это переставить карту в другой слот: линии, разведённые прямо на процессор, обычно получают отдельные группы, а слоты через чипсет часто сваливаются в одну общую. Второе по эффективности это обновление прошивки платы, потому что поддержка ACS (access control services, механизм, которым устройство заявляет об изоляции) иногда появляется в новых версиях. Третий путь это параметр pcie_acs_override, который искусственно разбивает группы. Он требует ядра, собранного с соответствующим патчем, и по смыслу сообщает ядру об изоляции, которой в железе нет, поэтому гость получает потенциальный доступ к памяти хоста. Для домашнего стенда это приемлемый компромисс. Для сервера с чужими данными нет.
Привязка карты к vfio-pci и отключение драйвера хоста
Задача из двух половин: загрузить модули vfio и не дать хостовому драйверу забрать карту раньше них.
# /etc/modules-load.d/vfio.conf
vfio
vfio_iommu_type1
vfio_pciДальше нужны идентификаторы устройства:
lspci -nnВ выводе вас интересуют две вещи: адрес в формате bus:dev.func (например 01:00.0) и идентификатор вида 10de:xxxx в квадратных скобках, где 10de это код вендора NVIDIA. Выпишите обе функции карты, графическую и звуковую.
# /etc/modprobe.d/vfio.conf
options vfio-pci ids=10de:2484,10de:228b disable_vga=1Значения 10de:2484 и 10de:228b здесь только пример, подставьте свои из lspci -nn. Параметр disable_vga=1 убирает карту из арбитража VGA на хосте. Важная тонкость: привязка по ids действует на все карты с такими идентификаторами. Если в машине две одинаковые карты и одну вы хотите оставить хосту, этот способ не подходит, привязывайтесь по адресу через driver_override.
Теперь хостовой драйвер:
# /etc/modprobe.d/blacklist-gpu.conf
blacklist nouveau
blacklist nvidia
blacklist nvidia_drm
blacklist nvidia_modeset
softdep nouveau pre: vfio-pci
softdep nvidia pre: vfio-pciСтроки softdep говорят ядру загружать vfio-pci раньше указанного модуля, поэтому vfio-pci успевает занять устройство первым. Одного blacklist часто мало, потому что модуль может подтянуться как зависимость чего-то ещё.
update-initramfs -u -k all
rebootБез update-initramfs файлы из /etc/modprobe.d не попадают в initramfs, и nouveau захватывает карту на раннем этапе загрузки, до того как ваши настройки будут прочитаны с корневой файловой системы. Это вторая по частоте причина ситуации "всё настроил, ничего не изменилось".
Проверка после перезагрузки:
lspci -nnk
lsmod | grep vfioДля вашей карты строка "Kernel driver in use" должна показывать vfio-pci, либо отсутствовать вовсе. Если там nvidia или nouveau, драйвер хоста всё ещё держит устройство, и ВМ его не получит. Команда lsmod должна показать три модуля: vfio, vfio_iommu_type1 и vfio_pci.
Настройка ВМ: q35, OVMF и обе функции карты
Проброс по PCI Express работает только на машине q35, потому что у i440fx шины PCIe нет. Прошивку берите OVMF (реализация UEFI для QEMU): для совместимости с OVMF у карты должен быть UEFI-совместимый ROM, и у моделей последнего десятилетия он есть. У совсем старых карт бывает только legacy VBIOS, и тогда остаётся SeaBIOS.
qm set 101 --machine q35 --bios ovmf
qm set 101 --efidisk0 local-lvm:0,efitype=4m,pre-enrolled-keys=0
qm set 101 --cpu host
qm set 101 --hostpci0 01:00,pcie=1Адрес 01:00 без номера функции это не опечатка. В такой короткой форме пробрасываются все функции устройства сразу, и графика, и HDMI-аудио, что как раз и нужно для видеокарты. Если карта должна быть в гостевой системе основным видеоадаптером, добавьте x-vga=1:
qm set 101 --hostpci0 01:00,pcie=1,x-vga=1Значение pre-enrolled-keys=0 оставляет гостя без предзагруженных ключей Microsoft, то есть фактически без работающего Secure Boot. Это осознанный выбор: проприетарный модуль NVIDIA внутри гостя с включённым Secure Boot нужно подписывать, иначе он не загрузится, и разбор этой ошибки лежит в отклонённой подписи модуля NVIDIA при Secure Boot.
Дальше начинается то, чего обычно не ожидают. Первое: кадровый буфер проброшенной карты не показывается ни в noVNC, ни в SPICE, консоль Proxmox покажет пустой экран или только ранний вывод прошивки. Доступ в гостя по SSH или RDP нужно подготовить заранее, иначе вы получите работающую ВМ, в которую нельзя войти. Второе: вся память ВМ закрепляется в оперативной памяти хоста, потому что устройство обращается к ней напрямую через DMA, а такие страницы нельзя ни выгрузить в swap, ни отобрать через balloon. Гость с 32 ГБ займёт 32 ГБ сразу и до остановки. Третье: карта на хосте занята до конца жизни ВМ, вторая ВМ с тем же hostpci просто не запустится. Четвёртое: адрес 01:00 верен только для этой машины, поэтому в кластере такую ВМ не переселить простым переносом. Для этого в hostpci есть параметр mapping, ссылающийся на общее для кластера описание устройства.
Внутри гостя дальше идёт обычная установка драйвера, и проблемы там уже не про Proxmox. Если после установки nvidia-smi не находит карту, разбор причин собран в материале про то, почему драйвер NVIDIA не загружается на Ubuntu Server. Если цель это медиасервер, следующий шаг описан в настройке аппаратного перекодирования Jellyfin на NVENC, у которого свои требования к версии драйвера.
Единственная видеокарта: чем вы платите за проброс
Пробросив единственную карту, вы теряете графическую консоль хоста. Это не побочный эффект неправильной настройки, а прямое следствие: устройство отдано vfio-pci, хост через него ничего не выводит. Монитор гаснет на каком-то этапе загрузки и больше не оживает, локальный TTY физически недоступен. Единственная конфигурация, которая при этом нормально работает, это headless-сервер: сеть, SSH и веб-интерфейс.
Что нужно подготовить до первой перезагрузки: постоянный адрес в сети, вход по SSH с ключом и путь восстановления. Путём восстановления может быть IPMI или iKVM серверной платы, вторая дешёвая карта в другом слоте, либо интегрированная графика процессора. Последний вариант самый аккуратный: консоль хоста остаётся на iGPU, дискретная карта уходит гостю, и вы ничего не теряете.
Если ни IPMI, ни iGPU нет, оцените риск честно. Любая опечатка в /etc/modprobe.d или в строке параметров ядра, после которой сеть не поднялась, означает поездку к железу с монитором и клавиатурой. Схемы с отвязкой и возвратом карты хосту скриптами существуют, но они держатся на том, что хостовой драйвер корректно отпускает устройство и корректно его подхватывает обратно. Для сервера, который должен работать без вашего участия, это слабый фундамент.
Почему не работает: разбор по симптомам
"No IOMMU detected, please activate it." Proxmox не нашёл работающий IOMMU. Проверяйте по порядку: пункт VT-d или AMD-Vi в прошивке, затем вывод cat /proc/cmdline, затем dmesg. В большинстве случаев причина в том, что параметры дописали в /etc/default/grub на системе с systemd-boot, и до ядра они не дошли.
"group is not viable" при старте ВМ. В группе IOMMU вашей карты есть устройство, которое не отдано vfio. Либо пробросьте всю группу, либо переставьте карту в другой слот. Список устройств группы вы получите обходом /sys/kernel/iommu_groups из раздела выше.
В lspci -nnk по-прежнему nvidia или nouveau. Настройки modprobe не попали в initramfs. Выполните update-initramfs -u -k all и перезагрузитесь. Если и это не помогло, модуль загружается как зависимость, и нужны строки softdep.
ВМ работает, устройство в гостевой системе видно, монитор молчит. Сначала проверьте очевидное: кабель включён в проброшенную карту, а не в выход материнской платы. Затем x-vga=1, если карта должна быть основным видеоадаптером. Если при этом гость стартует с OVMF, а ROM карты умеет только legacy-режим, вывода не будет. Смотреть на noVNC в этой ситуации бесполезно по определению.
Windows показывает ошибку 43 у видеоадаптера. Исторически драйверы NVIDIA сами блокировали работу GeForce в виртуальной машине, и весь пласт советов про сокрытие гипервизора родом оттуда. NVIDIA сняла это ограничение в драйверах ветки R465 (2021 год), так что начинайте с обновления драйвера в гостевой системе, а не с правки args.
Первый запуск ВМ проходит, второй нет. Не каждая карта корректно сбрасывается между запусками. Свойство это аппаратное, зависит от поддержки сброса функции конкретной моделью, и обходится перезагрузкой хоста. Если модель ведёт себя так, планируйте, что рестарт гостя означает рестарт всей машины.
Своё железо или аренда GPU: где граница
Проброс оправдан, когда карта уже стоит в вашем корпусе и нагрузка постоянная: медиасервер с перекодированием, локальная модель, которая отвечает круглосуточно, задачи CUDA, для которых данные не должны покидать помещение. Разовая работа на несколько часов по этой схеме не считается: бюджет первого проброса это вечер и две или три перезагрузки, а ещё привязка к слоту, которую вы обнаружите при следующем апгрейде платы, потому что группы IOMMU после него другие.
Если нужна карта, которой у вас нет, ответ простой: её надо арендовать. Обзор того, как выглядит VPS с видеокартой и что там реально дают, отвечает на половину вопросов, а расчёт точки безразличия между своим сервером и оплатой по токенам собран в сравнении GPU-сервера и оплаты API-токенов. Точка эта считается в часах загрузки карты, а не в вашем отношении к облакам.
Есть и третий ответ, который забывают чаще всего: изоляция не обязана быть виртуальной машиной. Если задача только в том, чтобы отделить сервис, работающий с картой, от остальной системы, контейнер с доступом к устройствам обойдётся без IOMMU, без потери консоли хоста и без привязки к слоту. Чем отличаются модели изоляции, разобрано в сравнении KVM, Xen и LXC. Полноценная ВМ нужна там, где гость обязан иметь своё ядро: другая операционная система, другая версия драйвера, Windows или вложенная виртуализация внутри гостя. А если вы всё ещё выбираете между своим гипервизором и арендой целиком, начните с сравнения Proxmox на своём железе и VPS.
FAQ
Нужно ли добавлять intel_iommu=on в Proxmox VE 9?
Обычно нет. Начиная с ядра 6.8 IOMMU включён по умолчанию и на Intel, и на AMD, а Proxmox VE 9 работает на более новых ядрах. Сначала проверьте вывод dmesg | grep -e DMAR -e IOMMU -e AMD-Vi. Если там пусто, причина чаще в выключенном VT-d или AMD-Vi в прошивке платы. Параметр не вреден, поэтому как проверку гипотезы его добавить можно, но начинать надо с прошивки и с cat /proc/cmdline.
Почему после проброса видеокарты в noVNC чёрный экран?
Так и должно быть. Кадровый буфер проброшенной карты недоступен ни через noVNC, ни через SPICE, потому что этой памятью распоряжается гостевой драйвер напрямую, а не QEMU. Изображение появится на мониторе, физически подключённом к проброшенной карте. Для работы без монитора подготовьте SSH или RDP внутри гостя до того, как добавите hostpci.
Можно ли пробросить одну видеокарту в две ВМ одновременно?
Нет. Устройство, привязанное к vfio-pci, получает ровно одна работающая ВМ, вторая с тем же hostpci не запустится. Разделение одной карты между гостями это отдельная технология mediated devices, для которой в hostpci есть параметр mdev, и она требует поддержки со стороны конкретной модели карты и её программного обеспечения. Обычный проброс такого не умеет.
Карта в одной группе IOMMU с другими устройствами. Что делать?
Сначала посмотрите, что именно с ней рядом. Функции самой карты, например HDMI-аудио, и корневой порт PCIe помехой не являются, функции пробрасываются вместе короткой формой адреса вида 01:00. Проблема появляется, когда в группе сетевой контроллер или NVMe, потому что отдать группу придётся целиком. Рабочие решения: переставить карту в слот, разведённый напрямую на процессор, и обновить прошивку платы. Параметр pcie_acs_override разбивает группы искусственно и снимает изоляцию, которой в железе нет, поэтому за пределами домашнего стенда его использовать не стоит.